OCIのAlarmをLINE Notifyを利用して通知(LINE Messaging APIに変更)

<font color="Red">
LINE Notifyの提供終了が発表されています。

[LINE Notify提供終了のお知らせ](https://notify-bot.line.me/closing-announce)
後継サービスのMessaging APIに変更するため、以下のように記載を変更します。
LINE Notifyに関する記述：【終了予定】を追加
LINE Messaging APIに関する記述：【追記】を追加

</font>

# 概要
Oracle Cloud Infrastructure(OCI)の監視アラームは通知機能(Notifications)があり、メールやslackでユーザ通知することができます。LINEには標準機能では通知できませんが、Functionsを利用することにより通知することができました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/e9547228-62ad-55cd-d370-32da66b983f2.png)

# LINE Notify設定<font color="Red">【終了予定】</font>
## LINEトークルームを作成
-LINEでグループトークルームを作成します

## LINE Notifyアクセストークン発行
-LINE Notify(https://notify-bot.line.me/ja/) にアクセス
-右上ユーザーからマイページを選択
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/3b72f5ee-6c82-0aac-4366-f3ce8955fdef.png">

-アクセストークンの発行より「トークンを発行する」ボタンを押下
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/68f15ae3-90e0-e97e-0067-dcc389c287c8.png">

-トークン名と通知するトークンルームを選択して「発行する」ボタンを押下
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/081ba098-8a2e-51d5-222f-3839e10b4de7.png">

-トークンは再発行できないので確実にコピー
-作成したトークルームにLINE Notifyを友だち追加

# LINE Messaging API設定<font color="Red">【追加】</font>
以下のガイドを参照しながら作成をすすめます。

[Messaging APIを始めよう](https://developers.line.biz/ja/docs/messaging-api/getting-started/)

LINE DevelopersにアクセスしてチャネルアクセストークンとユーザーIDを取得します
- チャネルアクセストークン
トップ>>プロバイダー>>チャネル>>Messaging API設定
- ユーザーID
トップ>>プロバイダー>>チャネル>>チャネル基本設定

# OCI コンテナレジストリ設定
-OCIコンソールから開発者サービス>>コンテナレジストリから「レジストリの作成」を押下
リポジトリ名を作成して「リポジトリの作成」を押下
リポジトリ名：alarmtoline/alarmtoline
アクセス：プライベート
今回はalarmtoline/alarmtolineをFunctionsの格納先としました

# OCI Functions設定

-以下のハンズオンを参考にFunctionsがVCNとコンテナリポジトリを使用できるようポリシーを作成します。
追加するポリシー:
Allow service FaaS to use virtual-network-family in tenancy
Allow service FaaS to read repos in tenancy

[Oracle Functions ハンズオン](https://oracle-japan.github.io/ocitutorials/cloud-native/functions-for-beginners/)

-OCIコンソールから開発者サービス>>ファンクション＞＞アプリケーションから「アプリケーションの作成」を押下
名前やネットワークを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/b08425ad-d80f-a83e-683d-347749f0489a.png)

今回はalarmtolineを作成しました

指定するサブネットについては
パブリック・サブネットが指定されている場合、インターネット・ゲートウェイへの通信ができるようRouting tableおよびセキュリティリストが設定されている必要があります。
プライベート・サブネットが指定されている場合、サービス・ゲートウェイとNATゲートウェイへの通信ができるようRouting tableおよびセキュリティリストが設定されている必要があります。

[ファンクションの呼出しの問題](https://docs.oracle.com/ja-jp/iaas/Content/Functions/Tasks/functionstroubleshooting_topic-Issues-invoking-functions.htm)

ネットワークセキュリティグループも設定できますので必要な通信のみ許可します。
（サブネットのセキュリティリストに設定済の場合は不要）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/bffae852-dfc8-16e6-1e23-ae621f449593.png)
-スタートガイドにて「Cloud Shell設定」を選択
-今回はCloud ShellにてFunctionsを作成するため、Cloud Shell設定を選択して"Cloud Shellセッションの開始"と"Cloud Shellでのfn CLIの設定"を順番に実施
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/d421caa9-0a85-5055-9251-07dcfa7570a0.png)
 
-"ファンクションの作成、デプロイおよび呼出し"については以下の手順にて実施
OCIコンソール右上の開発者ツールからCloud Shellを選択
Cloud Shellが立ち上がったらFunctions名をalarmtolineとしてテンプレートを作成します
```
user@cloudshell:~ (ap-tokyo-1)$ fn init --runtime python alarmtoline
Creating function at: ./alarmtoline
Function boilerplate generated.
func.yaml created.
```
ディレクトリalarmtolineに移動します。func.py, func.yamlおよびrequirements.txtが作成されています。
それぞれのファイルを以下のように更新します

■func.py
LINEのアクセストークンは発行されたトークンです
メッセージ部分は通知したいメッセージ文字列です。今回はProdServiceDownとしました
メッセージに加え、JSON形式のアラームメッセージからアラートパラメータ"title"を抽出して通知対象としています。
その他パラメータについては以下を参考にします・
[アラーム・メッセージの書式](https://docs.public.oneportal.content.oci.oraclecloud.com/ja-jp/iaas/Content/Monitoring/alarm-message-format.htm)
[アラームメッセージの例](https://docs.public.oneportal.content.oci.oraclecloud.com/ja-jp/iaas/Content/Monitoring/alarm-message-examples.htm)

<font color="Red">LINE Notifyを利用【終了予定】</font>
```func.py
import io
import json
import logging
import requests

def handler(ctx, data: io.BytesIO = None):
    try:
        body = json.loads(data.getvalue())
        title = body["title"]

        headers = {
           'Authorization': 'Bearer LINEのアクセストークン',
        }

        files = {
           'message': (None, 'メッセージ'+ title),
        }

        requests.post('https://notify-api.line.me/api/notify', headers=headers, files=files)

    except Exception as e:
        print('ERROR: bad Event!', flush=True)
        raise
```
<font color="Red">LINE Messaging APIを利用【追記】</font>
【CHANNEL ACCESS TOKEN】は取得したチャネルアクセストークン、【USERID】は取得したユーザーIDを使用します
```func.py
import io
import json
import logging
import requests

def handler(ctx, data: io.BytesIO = None):
    try:
        body = json.loads(data.getvalue())
        title = body["title"]
        alerttype = body["type"]

        headers = {
           "content-type": "application/json",
           "Authorization": "Bearer 【CHANNEL ACCESS TOKEN】",
        }

        
        data = {
           "to": "【USERID】",
            "messages":[
                {
                    "type":"text",
                    "text":"Name:" + title + " Type:" + alerttype
                }
            ]
        }

        requests.post('https://api.line.me/v2/bot/message/push', headers=headers, data=json.dumps(data))

    except Exception as e:
        print('ERROR: bad Event!', flush=True)
        raise
```
■func.yaml
imageやtab等を定義します
```func.yaml
schema_version: 20180708
name: alarmtoline
version: 0.0.0
runtime: python
build_image: fnproject/python:3.9-dev
run_image: fnproject/python:3.9
entrypoint: /python/bin/fdk /function/func.py handler
memory: 128
```
■requirements.txt
requestに関する依存関係を追加しています
```requirements.txt
fdk>=0.1.51
requests>=2.28.1
```

作成できたらdeployします
```
fn -v deploy --app alarmtoline
```

-OCIコンソールから開発者サービス>>ファンクション＞＞アプリケーションから先程作成したアプリケーションを選択しFunctionsに作成されていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/e839675f-feb6-b8e7-2e2e-bb9b9f8aa004.png)


-OCIコンソールから開発者サービス>>コンテナレジストリから作成したリポジトリ名を選択してイメージが保管されていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/23216caa-1b37-64ac-b50f-ad061e564c1e.png)


# 監視設定
## 通知設定
- OCIコンソールメニューから開発者サービス>>アプリケーション統合>>通知を選択
- 「トピックの作成」ボタンを押下
- トピックの名前を入力して「作成」ボタンを押下
- 作成したトピックを選択
- 「サブスクリプションの作成」ボタンを押下
- プロトコルで通知方法を「ファンクション」、アプリケーションはalarmtoline、ファンクションはalarmtolineを選択
- 「作成」ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/b3048551-f039-e33e-3ac9-a037ff49a82f.png)

## アラーム定義
-作成済みのアラーム定義のアラーム定義の宛先に作成済の通知設定（トピック）を選択

# アラーム結果
アラームを発生させると以下のようにLINEに通知がとどきました
アラームメッセージ本体はProdServiceDownで、対象のアラーム定義はWebService(test)です。
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/5c756a5b-7506-0f8e-1ce8-157f2d89daaf.png">

# 問題切り分け
通信が失敗する場合、Functionsが起動するサブネットからLINEに通信可能か確認することが有効です。

<font color="Red">LINE Notifyを利用【終了予定】</font>
```curl command
curl -X POST -H 'Authorization: Bearer 【トークン】' -F 'message=【メッセージ】' https://notify-api.line.me/api/notify
```
<font color="Red">LINE Messaging APIを利用【追記】</font>
```
curl -v -X POST https://api.line.me/v2/bot/message/push \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer 【CHANNEL ACCESS TOKEN】' \
-d '{
    "to": "【USERID】",
    "messages":[
        {
            "type":"text",
            "text":"Hello, world1"
        }
    ]
}'
```
また、ファンクション>>アプリケーションのログ設定を有効にしておけばログを確認することができます。
Functionsが失敗する際の切り分けとして有効です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/64d1b41b-f058-22bd-5043-7c870683f757.png)

エラーメッセージの内容はこちらから確認可能です。
[ファンクションの呼出しの問題](https://docs.oracle.com/ja-jp/iaas/Content/Functions/Tasks/functionstroubleshooting_topic-Issues-invoking-functions.htm)