CloudWatchのAlertをAWS Lambda経由でSlackに飛ばす


[AWS Lambda使ってCloudWatchのAlertをSlackに飛ばしてみた](http://qiita.com/shigure_onishi/items/92be0075f0573af80d1b)
この記事を読んで、「まさしくコレがやりたかった！」と思いトライしてみたが、S3 でロックファイル管理するなど、結構高機能なつくりのようだったので、もうちょっと単純なつくりにしたいと考えた。

と思ったら、 [AWS Lambda function for forwarding SNS notifications to Slack](https://gist.github.com/vgeshel/1dba698aed9e8b39a464) なるコードを発見したので、少し改変して使わせていただくことにした、という話。

# やりたいこと

* CloudWatch の Alert は諸々設定済みで、通知先の Topic には Email の Subscription が設定してある
* この Topic に Slack 通知する Lambda function の Subscription を追加したい

# 手順

## Slack の WebHooks integration をつくる

https://slack.com/services/new から Incoming WebHooks の integration を作成しておく。アイコンや名前は適当。

![Kobito.9rYp2k.png](https://qiita-image-store.s3.amazonaws.com/0/1329/b1eaab6c-2613-0599-100a-ef8d41b4b9d7.png "Kobito.9rYp2k.png")


## Lambda function を登録する

AWS ダッシュボードで ```Create a Lambda function``` ボタンから Lambda function を登録する。AP リージョンはまだ提供されていないが、リージョン跨ぎで SNS Subscription 登録できるので、```us-east-1``` とかどこでも OK。

ブラウザ上のエディタで Lambda function を記述する。名前などは適当。

Gist のコードそのままでも良いが、これだと、SNS にポストされる JSON がそのまま Slack に流れてきて読みづらいので、ちょっと整形して以下のコードにした。各 Alarm には description が設定されている想定。ソース中の、```slack_url``` には、先に作成した WebHooks の URL を指定しておく。

```javascript
console.log('Loading function');
 
const https = require('https');
const url = require('url');
const slack_url = 'https://hooks.slack.com/<webhook_url>';
const slack_req_opts = url.parse(slack_url);
slack_req_opts.method = 'POST';
slack_req_opts.headers = {'Content-Type': 'application/json'};
 
exports.handler = function(event, context) {
  (event.Records || []).forEach(function (rec) {
    if (rec.Sns) {
      var req = https.request(slack_req_opts, function (res) {
        if (res.statusCode === 200) {
          context.succeed('posted to slack');
        } else {
          context.fail('status code: ' + res.statusCode);
        }
      });
      
      req.on('error', function(e) {
        console.log('problem with request: ' + e.message);
        context.fail(e.message);
      });
      
      // この辺で適当にslack postするテキストを調整する.
      var message = JSON.parse(rec.Sns.Message);
      var status = message.NewStateValue;
      if (status === "ALARM") {
          status = ":exclamation: " + status;
      }
      if (status === "OK") {
          status = ":+1: " + status;
      }
      var str = "*" +
                status +
                ": " +
                message.AlarmDescription +
                "*" +
                "\n" +
                message.NewStateReason;

      req.write(JSON.stringify({text: str}));
      
      req.end();
    }
  });
};
```

![Kobito.t6lspE.png](https://qiita-image-store.s3.amazonaws.com/0/1329/7959d45d-86fb-4e5d-8158-d115c580f607.png "Kobito.t6lspE.png")

これを Basic execution role の function として登録する。role を作ってなければ、登録時に一緒につくる。

## 登録した Lambda function に SNS Topic を Subscribe 設定する

CloudWatch の Alarm 通知先になっている Topic に、作成した Lambda function を Subscribe させる。

![Kobito.CYM5pM.png](https://qiita-image-store.s3.amazonaws.com/0/1329/d5d78b9f-8ec0-02ef-1c30-3ee390613eab.png "Kobito.CYM5pM.png")

# 動作イメージ

![Kobito.c8O4gA.png](https://qiita-image-store.s3.amazonaws.com/0/1329/2acf4458-5b17-c740-97e4-5092418364ea.png "Kobito.c8O4gA.png")

# 注意事項

* AlarmDescription に日本語が入っていると、うまく通知されないぽい

# 参考

* [AWS Lambda使ってCloudWatchのAlertをSlackに飛ばしてみた](http://qiita.com/shigure_onishi/items/92be0075f0573af80d1b)
* [AWS Lambda function for forwarding SNS notifications to Slack](https://gist.github.com/vgeshel/1dba698aed9e8b39a464)
* [AWS Lambda Developer Guide](https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html)