【AWS CDK】AWS CloudWatch AlarmsからのメッセージをGoogle Hangouts Chatに自動通知する構成を速攻で作る

AWS CloudWatch AlarmsからのメッセージをGoogle Hangouts Chatに通知したいことがあるかと思います。
今回はその構成をCDKで作成してみました。

## 環境
CDK CLI: 1.32.0
ローカルのNode: 11.15.0

## 構成
今回は、`trigger-chat-cdk`というLambda関数を監視対象とし、「1分間に2回以上、関数が呼び出されたらエラーを挙げる」という条件を設定します。
<img width="637" alt="スクリーンショット 2020-04-21 16.04.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/039606b3-1fe7-a049-1234-132cd66dfec6.png">



以下は手順になりますが、[このリポジトリ](https://github.com/nomi3/cdk-alarm-to-hungout-chat)をcloneすれば、手順の3,4は省略できるので、より速攻で作れるかと思います。

## 1. Hangouts ChatのWebhook URLを作成する
まず前準備として、Hangouts ChatのWebhook URLを作成する必要があります。
作成は以下リンク先の「準備」を参照すれば可能です。
https://qiita.com/iitenkida7/items/3c8f9f8f6ee1e809558d#%E6%BA%96%E5%82%99


## 2. Webhook URLをパラメータストアに設定する
AWSマネジメントコンソールを開き、
System Manager→パラメータストア→パラメータの作成
と進み、

名前：HANGOUTS_CHAT_WEBHOOK_URL
値：取得したWebhook URL
種類：SecureString

で設定します。

## 3. CDKでスタックの作成
ここまでの準備ができたら、CDKのスタックを定義していきます。

```lib/cdk-alarm-stack.ts

import * as cdk from '@aws-cdk/core'
import * as sns from '@aws-cdk/aws-sns'
import * as subs from '@aws-cdk/aws-sns-subscriptions'
import * as cw from '@aws-cdk/aws-cloudwatch'
import * as lambda from '@aws-cdk/aws-lambda'
import * as iam from '@aws-cdk/aws-iam'
import * as cw_actions from '@aws-cdk/aws-cloudwatch-actions'

export class CdkAlarmStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    const layer = new lambda.LayerVersion(this, 'node-fetch', {
      code: lambda.Code.asset('layer/forChat'),
      compatibleRuntimes: [
        lambda.Runtime.NODEJS_10_X,
        lambda.Runtime.NODEJS_12_X
      ],
      layerVersionName: 'node-fetch'
    })
    const triggerFunction = new lambda.Function(this, 'triggerFunction', {
      runtime: lambda.Runtime.NODEJS_12_X,
      handler: 'index.handler',
      code: lambda.Code.asset('lambda/trigger-chat-cdk'),
      functionName: 'trigger-chat-cdk'
    })
    const sendChatFunction = new lambda.Function(this, 'sendChatFunction', {
      runtime: lambda.Runtime.NODEJS_12_X,
      handler: 'index.handler',
      code: lambda.Code.asset('lambda/send-chat-cdk'),
      functionName: 'send-chat-cdk',
      layers: [
        layer
      ]
    })
    sendChatFunction.addToRolePolicy(new iam.PolicyStatement({
      actions: [
        'sts:AssumeRole',
        'ssm:GetParameter'
      ],
      resources: [
        '*'
      ]
    }))
    const topic = new sns.Topic(
      this,
      'sendChatTopic',
      {
        displayName: 'send chat',
        topicName: 'sendChatTopicCdk'
      }
    )
    topic.addSubscription(new subs.LambdaSubscription(sendChatFunction))
    const alarm = new cw.Alarm(this, 'sendChatAlarm', {
      evaluationPeriods: 1,
      metric: triggerFunction.metricInvocations(),
      threshold: 2,
      period: cdk.Duration.minutes(1),
      alarmName: 'sendChatCdk'
    })
    alarm.addAlarmAction(new cw_actions.SnsAction(topic));

  }
}


```
`triggerFunction`を別のリソースに書き換えれば、アラームの監視対象を変えることができますし、`alarm`を書き換えれば、アラームの定義を自由に設定することができます。

## 4. Chatにメッセージを送るLambda関数を書く
今回はLambda関数として
 - 監視対象となる`trigger-chat-cdk`
 - Chatにメッセージを送る`send-chat-cdk`
の2つを定義する必要がありますが、`trigger-chat-cdk`の中身は正直なんでも良いので、説明を省略します。

`send-chat-cdk`の中身は以下の通りです。

```send-chat-cdk.js
const fetch = require('node-fetch')
const AWS = require('aws-sdk')

exports.handler = async (event, context, callback) => {
  const ssm = new AWS.SSM()
  const res = await ssm.getParameter({ Name: 'HANGOUTS_CHAT_WEBHOOK_URL', WithDecryption: true }).promise()

  const fromSNS = event.Records[0].Sns.Message
  const data = JSON.stringify({
    text: `${fromSNS}`
  })

  fetch(res.Parameter.Value, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json; charset=UTF-8'
    },
    body: data
  })

  callback(null, event)
}
```
この関数で、`node-fetch`というモジュールをインポートしているので、このモジュールを使えるようにします。

## 5. Layerで使用するモジュールをインストールする
今回使用するモジュールはLayerにセットします。
そのため、`lambda/layer/forChat/nodejs`というディレクトリを作成し、このディレクトリで

```
$ npm i node-fetch
```
を実施し、インストールします。

## 6. デプロイ
ここまで完了したら、

```
$ cdk deploy
```
で、スタックをデプロイします。

## 7.実行テスト
AWSのマネジメントコンソールから、Lambdaの`trigger-chat-cdk`の管理画面を開き、適当なテストイベントを2回以上実行します。
<img width="828" alt="スクリーンショット 2020-04-21 15.46.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/28645557-6e46-4775-b02c-3b6069fc24f1.png">

1分ほど待って、作成したHangouts ChatのチャットルームにCloudWatchからのエラーメッセージが届けば成功です！

メッセージ文の内容は、Lambdaの中身を適宜アレンジして頂ければと思います。

以上、ありがとうございました。