ないのなら作ってしまおう、Microsoft Teams 向け AWS Chatbot っぽいもの

## AWS Chatbot とは
https://aws.amazon.com/jp/chatbot/

ざっくりと言ってしまうと、AWS上で起きた事象を Slack や Amazon Chime に通知したり、スラッシュコマンドなどで操作できたりするものです。

本稿執筆時点では、ベータ版のため、[この資料](https://d1.awsstatic.com/legal/awsserviceterms/AWS%20Service%20Terms%20-%20Japanese%20Translation.pdf)の ***1.10 Beta Service Participation*** に則り、これ以上の言及は致しません。

## 背景
現時点では、Slack と Amazon Chime のみの対応のため、Microsoft Teams 用として AWS Chatbot っぽいものを作ろうということです。

ベータが外れたころに採用されてるといいなぁと願いながら...

## レシピ
### 登場人物
- Microsoft Teams
- AWS Lambda
- Amazon SNS
- Amazon CloudWatch

Slackでいうところのスラッシュコマンドのようなものを実装するなら Amazon API Gateway も使います。

### Microsoft Teams の設定
AWS からの通知を受け付ける設定をします。
通知を受け付けたいチームのチャネル右側の[...]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/35d60d89-929b-8136-cd6c-6b17b0745084.png)

すると、以下のようなメニューが表示されるので[コネクタ]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/67dce720-6611-def0-9573-cafda005eb0e.png)

コネクタの一覧が表示されたら[Incoming Webhook] の構成ボタンをクリックします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/de02513f-59bf-3609-44cd-140472a4a661.png)

次に任意の名称を付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/518944ed-03be-9aea-3abb-63aea6e5535b.png)

最後にお好みに応じてイメージをアップロードして、「作成」ボタンをクリックします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/f0221879-9e81-0bc5-6656-db83525bb981.png)


作成が完了すると、AWS からの通知を受け付けるURLが生成されるので、コピーして控えておきます。作業が終わったら[完了]ボタンで閉じます。
このURLは後続の AWS Lambda上のコードに使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/0762fdcb-6248-9864-4c66-d529417d1f8f.png)

URL を控えるのを忘れても、再度、コネクタの画面を表示し、左側の「構成済み」からたどることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/55b8a8f7-c860-1a56-57c0-b9cd4cfcda7b.png)

コネクタが作られたチャネルには、以下のような記事がポストされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/9930086e-1c28-6b4b-eaed-5bd01bf20596.png)



### AWS Lambda 上のコード
※今回は、CloudWatch メトリクスのアラームを受けて、それを Microsoft Teamsに送付するサンプルです。
※Lambdaに入っていないモジュールとして、**PIL**(pillow) と **requests** を使用しています。
※適宜配置してください。
※Python3.8 で動作確認しています。

```python:lambda_function.py
import boto3
import json
import io
import base64
from PIL import Image
from io import BytesIO
import requests

teams_endpoint = 'Microsoft Teamsの設定で控えておいたURLを指定する'
# URLは必用に応じてKMSなどを利用して暗号化したり、環境変数機能をご利用ください。
                  
def lambda_handler(event, context):
    subjet = event['Records'][0]['Sns']['Subject']
    
    # SNS が送信するJson内のMessage要素以下はStringなのでJsonとして読み込む
    message = json.loads(event['Records'][0]['Sns']['Message'])
    
    newStateReason = message['NewStateReason']
    newStateValue = message['NewStateValue']
    nameSpace = message['Trigger']['Namespace']
    metricName = message['Trigger']['MetricName']
    topicName =  event['Records'][0]['Sns']['TopicArn'].split(':')[5]
    resourceId = message['Trigger']['Dimensions'][0]['value']
    resourceType = message['Trigger']['Dimensions'][0]['name']
    
    # Microsoft Teams にポストする内容をつくる
    text = []
    text.append(newStateReason)
    text.append("\r\n\r\n")
    text.append("**Alarm State:** {0}　　　　　　　　　　**Name Space:**: {1}".format(newStateValue, nameSpace))
    text.append("**Metric:** {0}　　　　　　　　　　**Topic Name:** {1}".format(metricName, topicName))
    text.append("\r\n\r\n")
    
    # 対象のメトリック画像を取得する
    cw = boto3.client('cloudwatch')
    widget = '{\
            "view": "timeSeries",\
            "stacked": false,\
            "metrics": [\
                [ "'+ nameSpace +'", "'+ metricName +'", "'+ resourceType + '", "' + resourceId +'" ]\
            ], \
            "width": 480,\
            "height": 180,\
            "start": "-PT2H",\
            "end": "P0D",\
            "timezone": "+0900"\
        }'

    response = cw.get_metric_widget_image(MetricWidget = widget)
    img = Image.open(BytesIO(response["MetricWidgetImage"]))

    # メモリ上に画像を格納するおまじない
    buffer = io.BytesIO()
    img.save(buffer,"PNG")
    
    # メモリ上に保存した画像をBASE64エンコードする
    imgBase64 = base64.b64encode(buffer.getvalue()).decode().replace("'", "")
    
    # BASE64エンコードした文字列を Microsoft Teams へ送信する内容に追加
    text.append("![Chart](data:image/png;base64,{0})".format(imgBase64))
    
    # Microsoft Teams へ送信する下ごしらえ
    request = {
        'title': subjet,
        'text': '\r\n\r\n'.join(text)
        }
    
    # Microsoft Teams へ送信する
    response = requests.post(teams_endpoint, json.dumps(request))
```


### Amazon SNS の設定
#### トピックの作成
Amazon SNS の画面を表示させ、[トピックの作成]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/0870250d-2ca7-2a78-7646-1a2f2635c894.png)
名前や表示名を指定します。その他必要な設定があれば実施し、[トピックの作成]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/12543eca-431f-0714-4860-490ae63f541d.png)

#### サブスクリプションの作成
トピックの作成が完了すると、以下の画面が表示されるので、[サブスクリプションの作成]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/a2e023c1-2bf9-79c7-92f1-89c6c0bc8ab8.png)
プロトコルに「AWS Lambda」を選択します。
そして、エンドポイントで先ほど作成した AWS Lambda の Lambda関数を指定し、その他必要に応じて設定を行い、[サブスクリプションの作成]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/dca455ca-bf04-d9c3-3217-4db4e1c6e478.png)

### Amazon CloudWatch アラームの設定
Amazon CloudWatch の画面を表示し、左側にある「アラーム」をクリックします。
アラームの一覧が表示されたら、[アラームの作成]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/a17aec17-7193-2603-35d5-9e8233f601f9.png)

[メトリクスの選択]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/7bd4d13a-3afa-2834-0f2b-6c21c1b4adbb.png)

フィルタ条件を指定するフィールドに、通知したいEC2インスタンスのインスタンスIDを指定し、Enterキーを押します。
すると、以下のように ***EC2＞インスタンス別メトリクス*** のみになるのでクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/94250b0c-f4e5-1b97-c311-6fe4cb8e9f5a.png)

通知したいメトリクスを選択します。この例では、CPUUtilization (CPU使用率)を選択しています。
選択したら、画面下部の[メトリクスの選択]ボタンをクリックします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/e67ec240-c9fb-af65-e247-55354c97f003.png)

メトリクスの条件設定を行います。
通知したい条件を設定します。この例では、CPU 使用率が 80 を超えたら通知が出るようにしています。
[次へ]ボタンをクリックして進めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/67520f92-0c77-4820-a23a-e11075d3b245.png)

SNS トピックは先ほど作成したものを利用するので、
[既存の SNS トピックを選択]を選択します。
そして、[通知の送信先]に作成したものを指定します。
[次へ]ボタンをクリックして進めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/8612142f-4987-c6b5-e0cb-875fcd1184de.png)

アラームの名称を指定します。任意のもので構いません。
[次へ]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/ac546b23-2cb7-a897-8014-0acc2a91afa3.png)

プレビューと作成画面が表示されるので、設定内容を確認して、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/8044ef42-9294-e53c-2b49-0bc6070d545f.png)
画面をスクロースして、[アラームの作成]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/b42adafd-90d4-5835-c905-97367f3e1f0d.png)


## テスト
色々と設定が終わったら、Cloudwatch アラームを発火させます。
アラームを設定した EC2 インスタンスが Linux であれば、以下のコマンドを実行することで、簡単にCPU使用率をあげることができます。

```sh
sudo yes >> /dev/null &
[1] 10968
```

少し待つと、 Microsoft Teams 以下のような記事が追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/5a562874-44a5-0b3b-58ee-317ee85cad59.png)

テストが終わったら、プロセスを `kill` してください。


## まとめ
コミュニケーション基盤が Slack や Amazon Chime ではなく Microsoft Teams のため、すぐに AWS Chatbot の恩恵にあずかれない！と悲しんでいる方も、この作例をもとに、ニッコリ笑顔になっていただけたら幸いです。

## 参考資料
https://hacknote.jp/archives/51333/
https://qiita.com/m_hama123/items/c40c8f5271ca03fc57e9