先日発表したChatOps事例のスライドを共有します。
www.slideshare.net
連携のハマりどころ
この発表でちゃんと伝えてないので補足です。
APIGatewayとLambdaの連携
APIGatewayを使うにあたりSlack連携で、GETリクエストを受け取るのは簡単なんですが、POSTリクエストが実はちょっと面倒なんですね。
p18でも書いてますが、Slackから飛んでくるリクエストがJsonではなくFormなんです。
Slackから飛ぶForm内容は、以下のような感じなんですが、
token=xxxxxxxxxxxxx team_id=T0001 team_domain=example channel_id=C1234567 channel_name=test user_id=U1234567 user_name=Steve command=/weather text=its\ time\ to\ wake\ up response_url=https://hooks.slack.com/commands/1234/5678
これがAPIGatewayだとTemplateマッピングってシロモノを使わなきゃできない感じなんです。(と思っていた。)
対処方法としては、
- テンプレートマッピングを使う
- lambdaプロキシを使う
テンプレートマッピング使い方
テンプレートマッピングに関しての使い方は公式に詳しく書いてあるので、こちらを参照にしてみてください。
API Gateway API リクエストとレスポンスペイロードのマッピングテンプレートのリファレンス - Amazon API Gateway
実際自分が作ったものだと
APIGateway→メソッドを選択→統合リクエストを選択→本文マッピングテンプレートで以下のようなテンプレートを記載しました。
ContentTypeは"application/x-www-form-urlencoded"と記載。
{ "body": $input.json("$") }これは、formのインプットに対して、bodyをキーにしたjsonに変換するという処理です。
実際受け取るときは、
{ "body": {"token":"xxxxxxxxxxxxx", "team_id":"T0001", ... } }みたいな感じに変換されてLambdaに渡されます。
Lambdaプロキシを使う
テンプレートマッピングって独自仕様すぎてわかりづらいですよね。
そこでlambdaブロキシを使うと楽できます。
"Lambda プロキシ統合の使用"にチェックを入れると以下のようなリクエストが渡されます。
{
'body': 'token=xxxxxxxxxxxxx&team_id=T0001&team_domain=example&channel_id=C1234567&channel_name=test&user_id=U1234567&user_name=Steve&command=/weather&text=its\ time\ to\ wake\ up&response_url=https://hooks.slack.com/commands/1234/5678',
'resource': '/start-stop-api',
'requestContext': {
'resourceId': 'xxxx',
'apiId': 'xxxxxx',
'resourcePath': '/test',
'httpMethod': 'POST',
'requestId': 'xxxxxxxx',
'accountId': 'xxxxxxxx',
'identity': {
'apiKey': None,
'userArn': None,
'cognitoAuthenticationType': None,
'accessKey': None,
'caller': None,
'userAgent': 'Slackbot 1.0 (+https://api.slack.com/robots)',
'user': None,
'cognitoIdentityPoolId': None,
'cognitoIdentityId': None,
'cognitoAuthenticationProvider': None,
'sourceIp': '', // AWSのIP
'accountId': None
},
'stage': 'dev'
},
'queryStringParameters': None,
'httpMethod': 'POST',
'pathParameters': None,
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Via': '1.1 xxxxxxxxxxxxxxx.cloudfront.net (CloudFront)',
'Accept-Encoding': 'gzip,deflate',
'CloudFront-Is-SmartTV-Viewer': 'false',
'CloudFront-Forwarded-Proto': 'https',
'X-Forwarded-For': '',
'CloudFront-Viewer-Country': 'US',
'Accept': 'application/json,*/*',
'User-Agent': 'Slackbot 1.0 (+https://api.slack.com/robots)',
'Host': 'xxxxx.execute-api.ap-northeast-1.amazonaws.com',
'X-Forwarded-Proto': 'https',
'X-Amz-Cf-Id': 'xxxxxx',
'CloudFront-Is-Tablet-Viewer': 'false',
'X-Forwarded-Port': '443',
'CloudFront-Is-Mobile-Viewer': 'false',
'CloudFront-Is-Desktop-Viewer': 'true'
},
'stageVariables': None,
'path': '/test',
'isBase64Encoded': False
}これを使えば、テンプレートマッピングなんかしなくても、bodyにformの値が入ってくれるので、パースできちゃいます。
CloudWatchのログ設定
自分は、グループの作成に関しては、以下のような名前で手動で実施しました。
/aws/lambda/{lambda名}
AMIに以下の権限を付与してあげれば、作成されます。
{
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricStatistics",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
TIPS
lambda自体のTIPSですが、boto3は重いです。
なので、pythonコードとしてimport するときは、
from boto3 import resource
みたいな感じで、必要のないimportを無くすように心がけましょう。
lambdaは実行時間課金なので、無駄な処理は極力削除!!
ということで、ChatOpsどんどんやっていきましょー。