AWS Lambda の Slack 連携機能を使ってEC2インスタンスの起動状況を Slack 上で確認できるようにする


Lambda に　Slack 連携の blueprint が追加されました。
Slack-echo-command と Cloudwatch-alarm-to-slack の二種類があるのですが、今回は前者の Slack から Lambda を叩ける機能を用いて Slack 上で EC2 の起動状態を確認できるようにしてみます。

やることは下記の通りです。

* Slack 側で Slash Command の初期設定を行う *
* Slash Command の token の暗号化を行う *
* Lambda ファンクションの作成
* IAM ロールの作成
* API Gateway の作成 *
* Slash Command に API Gateway のエンドポイントを設定する *

*が付いている部分については、クラスメソッドさんのブログ「[【新機能】AWS LambdaにSlack連携のBluePrintが登場。ChatOpsがより手軽に](http://dev.classmethod.jp/cloud/aws/slack-integration-blueprint-for-aws-lambda/)」を参考にさせていただきましたので、今回は割愛したいと思います。


## Lambda ファンクションの作成

今回は Python で書いていきたいと思います。
blueprint「slack-echo-command-python」を選択してください。

```python:slack_aws.py
# -*- coding: utf-8 -*-

import boto3
from base64 import b64decode
from urlparse import parse_qs
import logging

ENCRYPTED_EXPECTED_TOKEN = "***" # Enter the base-64 encoded, encrypted Slack command token (CiphertextBlob)

kms = boto3.client('kms')
expected_token = kms.decrypt(CiphertextBlob = b64decode(ENCRYPTED_EXPECTED_TOKEN))['Plaintext']

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    req_body = event['body']
    params = parse_qs(req_body)
    token = params['token'][0]
    if token != expected_token:
        logger.error("Request token (%s) does not match exptected", token)
        raise Exception("Invalid request token")

    command_text = params['text'][0]
    
    instances_info = ""
    if command_text == "instances":
        for reservation in boto3.client('ec2').describe_instances()["Reservations"]:
            for instance in reservation["Instances"]:
                instances_info = instances_info + instance["InstanceId"] + "->" + instance["State"]["Name"] + " "
    
    return instances_info
```


## IAM ロールの作成

* EC2 の操作権限（本当は参照だけでいいのですが全てつけてしまっています）
* CloudWatchLogs への Put 権限
* KMS の Decrypt 権限

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1448895482556",
      "Action": "ec2:*",
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
```

```
{
         "Version": "2012-10-17",
         "Statement": [
           {
             "Effect": "Allow",
             "Action": [
               "kms:Decrypt"
             ],
             "Resource": [
               "arn:aws:kms:ap-northeast-1:894357485438:key/xxxxxxxx"
             ]
           }
         ]
}
```

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}
```

## テスト

![スクリーンショット 2016-01-28 0.36.56.png](https://qiita-image-store.s3.amazonaws.com/0/52494/03e4261b-322f-96ae-09ef-31f240869f55.png "スクリーンショット 2016-01-28 0.36.56.png")
上記のように Slash コマンドを叩くと、、

![スクリーンショット 2016-01-28 0.37.32.png](https://qiita-image-store.s3.amazonaws.com/0/52494/65637e57-0227-9dfd-3bb7-060ea71ebe13.png "スクリーンショット 2016-01-28 0.37.32.png")
というようにインスタンスIDと状態を返してくれます。



/aws のあとに続く文字列が command_text に入ってくるので、その内容によって返す情報を変更してあげることで、AWS の様々な情報を Slack 上で確認することができるようになります！


## 課題

#### 1) タイムアウト対応

たまに下記にようにタイムアウトが発生します。

![スクリーンショット 2016-01-28 0.37.15.png](https://qiita-image-store.s3.amazonaws.com/0/52494/a3743e1d-92e5-6ae3-7bf3-38449cffa539.png "スクリーンショット 2016-01-28 0.37.15.png")

調べてみると、3,000ms 以上経過するとタイムアウトになる模様。([stackoverflow](http://stackoverflow.com/questions/34896954/how-to-avoid-slack-command-timeout-error))
対応しようと思えばできるみたいなので、いつかやろうと思います。

#### 2) Slack に表示するインスタンス情報の改行

改行文字を返すだけではダメでした。

![スクリーンショット 2016-01-28 0.53.58.png](https://qiita-image-store.s3.amazonaws.com/0/52494/9acbdea1-8f00-0f9c-e87b-7e6110e8768a.png "スクリーンショット 2016-01-28 0.53.58.png")

対応方法ご存知の方は教えていただきたいです。

## まとめ

色々わかっていないところもあるのですが、Lambda を使うことで簡単に ChatOps 環境が作れる気がします。
次は、Cloudwatch-alarm-to-slack の方を使って何かやってみたいです。