Lambda関数を作成して、slackのIncoming Webhooksに投稿してみます。
今回は、CloudWatch Eventsで定期実行できるように、データは関数の内部で持たせます。
前提条件
Lambdaへの権限
Lambdaに対してフル権限があること。
AWS CLI
以下のバージョンで動作確認済
- AWS CLI 1.10.17
コマンド
aws --version
結果(例):
aws-cli/1.10.6 Python/2.7.5 Darwin/13.4.0 botocore/1.3.28
IAM Role
'lambdaBasicExecution'ロールが存在すること。
変数の設定
IAM_ROLE_NAME='lambdaBasicExecution'
コマンド
aws iam get-role \
--role-name ${IAM_ROLE_NAME}
結果(例)
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
},
"RoleId": "AROAI2DMAFJEPZE7RBSUG",
"CreateDate": "2015-10-26T01:55:54Z",
"RoleName": "lambdaBasicExecution",
"Path": "/",
"Arn": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution"
}
}
存在しない場合は、以下の手順を実施してください。
- IAMロールの作成 (Lambda: Basic execution): http://qiita.com/tcsh/items/6353876a5c4fef63b4d8
- 準備
=======
0.1. 変数の確認
プロファイルが想定のものになっていることを確認します。
変数の確認
aws configure list
結果(例)
Name Value Type Location
---- ----- ---- --------
profile administrator-prjz-mbp13 env AWS_DEFAULT_PROFILE
access_key ****************XXXX shared-credentials-file
secret_key ****************XXXX shared-credentials-file
region ap-northeast-1 env AWS_DEFAULT_REGION
プロファイルが想定のものになっていることを確認します。
0.2. IAM RoleのARN取得
変数の設定
IAM_ROLE_NAME='lambdaBasicExecution'
コマンド
IAM_ROLE_ARN=$( \
aws iam get-role \
--role-name ${IAM_ROLE_NAME} \
--query 'Role.Arn' \
--output text \
) \
&& echo ${IAM_ROLE_ARN}
結果(例)
arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution'
- 事前作業
===========
1.1. Lambda関数名の決定
変数の設定
LAMBDA_FUNC_NAME='good_morning_lambda'
同名のLambda関数の不存在確認
コマンド
aws lambda get-function \
--function-name ${LAMBDA_FUNC_NAME}
結果(例)
A client error (ResourceNotFoundException) occurred when calling the GetFunction operation: Function not found: arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:good_morning_lambda
1.2. Slack関連の設定
変数の設定
URL_SLACK_IN=<slackのIncoming WebHookのURL>
CHANNEL_SLACK='20160411'
USERNAME_SLACK='おはようLambda'
ICON_EMOJI_SLACK='sunrise'
TEXT_SLACK="Good Morning\!\`\`\`\'おはよう\!\'\`\`\`"
1.3. Lambda関数
変数の設定
FILE_LAMBDA_FUNC="${LAMBDA_FUNC_NAME}.js"
変数の確認
cat << ETX
FILE_LAMBDA_FUNC: ${FILE_LAMBDA_FUNC}
URL_SLACK_IN: ${URL_SLACK_IN}
CHANNEL_SLACK: ${CHANNEL_SLACK}
USERNAME_SLACK: ${USERNAME_SLACK}
ICON_EMOJI_SLACK: ${ICON_EMOJI_SLACK}
TEXT_SLACK: ${TEXT_SLACK}
ETX
コマンド
cat << EOF > ${FILE_LAMBDA_FUNC}
var Slack = require('slack-node');
console.log('Loading function');
exports.handler = function(event, context) {
slack = new Slack();
slack.setWebhook('${URL_SLACK_IN}');
slack.webhook({
channel: "#" + "${CHANNEL_SLACK}",
username: "${USERNAME_SLACK}",
icon_emoji: ":" + "${ICON_EMOJI_SLACK}" + ":",
text: "${TEXT_SLACK}"
}, function(err, response) {
console.log(response);
context.succeed(response);
});
};
EOF
cat ${FILE_LAMBDA_FUNC}
コマンド(任意)
eslint ${FILE_LAMBDA_FUNC}
コマンド
npm install slack-node
結果(例)
slack-node@0.2.0 node_modules/slack-node
└── requestretry@1.6.0 (when@3.7.7, fg-lodash@0.0.2, request@2.69.0)
コマンド
zip -r ${LAMBDA_FUNC_NAME}.zip ${FILE_LAMBDA_FUNC} node_modules \
&& ls -l ${LAMBDA_FUNC_NAME}.zip
結果(例)
-rw-r--r-- 1 lab-office staff 3122259 4 10 19:42 good_morning_lambda.zip
- Lambda関数の作成
===================
変数の設定
LAMBDA_FUNC_DESC='AWS Lambda function for post slack incoming webhook.'
LAMBDA_RUNTIME='nodejs'
LAMBDA_HANDLER="${LAMBDA_FUNC_NAME}.handler"
FILE_LAMBDA_ZIP="${LAMBDA_FUNC_NAME}.zip"
変数の確認
cat << ETX
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
LAMBDA_FUNC_DESC: "${LAMBDA_FUNC_DESC}"
LAMBDA_RUNTIME: ${LAMBDA_RUNTIME}
FILE_LAMBDA_ZIP ${FILE_LAMBDA_ZIP}
IAM_ROLE_ARN: ${IAM_ROLE_ARN}
LAMBDA_HANDLER: ${LAMBDA_HANDLER}
ETX
コマンド
aws lambda create-function \
--function-name ${LAMBDA_FUNC_NAME} \
--description "${LAMBDA_FUNC_DESC}" \
--zip-file fileb://${FILE_LAMBDA_ZIP} \
--runtime ${LAMBDA_RUNTIME} \
--role ${IAM_ROLE_ARN} \
--handler ${LAMBDA_HANDLER}
結果(例)
{
"CodeSha256": "8fI549wlUY+qm7LHTh5XmV/CdCkqabpBTbCOfiFJf3o=",
"FunctionName": "good_morning_lambda",
"CodeSize": 1978932,
"MemorySize": 128,
"FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:good_morning_lambda",
"Version": "$LATEST",
"Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution",
"Timeout": 3,
"LastModified": "2016-02-22T08:44:48.274+0000",
"Handler": "good_morning_lambda.handler",
"Runtime": "nodejs",
"Description": "AWS Lambda function for post slack incoming webhook."
}
コマンド
aws lambda get-function \
--function-name ${LAMBDA_FUNC_NAME}
結果(例)
{
"Code": {
"RepositoryType": "S3",
"Location": "https://awslambda-ap-ne-1-tasks.s3-ap-northeast-1.amazonaws.com/snapshots/XXXXXXXXXXXX/good_morning_lambda-ac0802dc-9a1e-4d0d-a7c8-e88bfd13fc88?x-amz-security-token=AQoDYXdzECka4AO2NeNXdEJ0XHeft0nvNiPkug4SqexqnBLBZj%2FkpT%2FleFIDbSUva%2BunE48A4%2BxVrfprD2Qg6UIusixkHBTdA%2BvFzwVDD%2FRVcSqXXK5IDPejbVP39tR%2BlVz6FvLPbQgXJ90budQsNfGGxKuN0KG5PrjNAP%2BwLXIHfgI9ZW%2BBzPRGFNMp6KZN8GyoDl2SPrmazbLXwFbmF9RNNAyQ76yJCwKWgRL1J9tEBI34U6tGJLOfiTlG4ES5e1IHGALJRCxakodS7dhE3UpVO7%2BbTbAK%2F5DdkCb2H4iENiIs0VoVwBvm2J%2FMhLHjXwa9fibMHji4zaX81qr9PN4saIT%2FwnVf3nljCJv5oKM5cC3Wzh%2Bcb6CAh4AJppjI9nNDqozQzXnvDrEvp6vzP%2Boti52FHXG%2Bp5Y4zXTrpiu35vOca19DOPD8Gc%2FxaycrXujULkXQpe8%2F%2BGjmMIw8yZGJQNfzKkg7DothBPRVvgNZe%2FvwyiXEllSft%2BrfDhWkMAk1mq24e%2FWxRQ4TGr8oBJ1yM2nsD0yx7406px1uXXPyTCOy%2FI2lH3K%2BVhJ391gJ6vdgugk4oWuTE5XK%2BHiyS17cYgWDciISf%2B0FpWufVWcQYFgV%2Bu4csHnnh6tYHiqe8McHzuvKe4UAli0goPyqtgU%3D&AWSAccessKeyId=ASIAXXXXXXXXXXXXXXXXX&Expires=1456131365&Signature=Na9a83GZbmR6cL2XnvZOOafGCN8%3D"
},
"Configuration": {
"Version": "$LATEST",
"CodeSha256": "8fI549wlUY+qm7LHTh5Xmx/CdCkqabpBTbCOfiFJx3o=",
"FunctionName": "good_morning_lambda",
"MemorySize": 128,
"CodeSize": 1978932,
"FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:good_morning_lambda",
"Handler": "good_morning_lambda.handler",
"Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution",
"Timeout": 3,
"LastModified": "2016-02-22T08:44:48.274+0000",
"Runtime": "nodejs",
"Description": "AWS Lambda function for post slack incoming webhook."
}
}
- Lambda関数の動作確認
=======================
3.1. lambda関数の手動実行
変数の設定
FILE_OUTPUT_LAMBDA="${LAMBDA_FUNC_NAME}-out.txt" \
&& echo ${FILE_OUTPUT_LAMBDA}
変数の確認
cat << ETX
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
FILE_OUTPUT_LAMBDA: ${FILE_OUTPUT_LAMBDA}
ETX
コマンド
FILE_LOG_LAMBDA="${LAMBDA_FUNC_NAME}-$(date +%Y%m%d%H%M%S).log" \
&& echo ${FILE_LOG_LAMBDA}
aws lambda invoke \
--function-name ${LAMBDA_FUNC_NAME} \
--log-type Tail \
${FILE_OUTPUT_LAMBDA} \
> ${FILE_LOG_LAMBDA} \
cat ${FILE_LOG_LAMBDA} \
| jp.py 'StatusCode'
結果(例)
200
3.2. lambda関数の実行結果の確認
コマンド
cat ${FILE_OUTPUT_LAMBDA}
結果
{"status":"ok","statusCode":200,"headers":{"content-type":"text/html","content-length":"2","connection":"keep-alive","access-control-allow-origin":"*","content-security-policy":"referrer no-referrer;","date":"Mon, 22 Feb 2016 08:50:33 GMT","server":"Apache","strict-transport-security":"max-age=31536000; includeSubDomains; preload","x-frame-options":"SAMEORIGIN","x-cache":"Miss from cloudfront","via":"1.1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)","x-amz-cf-id":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=="},"response":"ok"}
3.3. lambda関数のログの確認
コマンド
cat ${FILE_LOG_LAMBDA} \
| jp.py 'LogResult' \
| sed 's/"//' \
| base64 --decode
結果
START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST
2016-04-10T04:38:22.476Z xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx { status: 'ok',
statusCode: 200,
headers:
{ 'content-type': 'text/html',
'transfer-encoding': 'chunked',
connection: 'keep-alive',
'access-control-allow-origin': '*',
'content-security-policy': 'referrer no-referrer;',
date: 'Sun, 10 Apr 2016 04:38:22 GMT',
server: 'Apache',
'strict-transport-security': 'max-age=31536000; includeSubDomains; preload',
vary: 'Accept-Encoding',
'x-frame-options': 'SAMEORIGIN',
'x-cache': 'Miss from cloudfront',
via: '1.1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)',
'x-amz-cf-id': 'xxxxxxxxxxxxxxxxxxx_xx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx_x==' },
response: 'ok' }
END RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
REPORT RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Duration: 998.63 ms Billed Duration: 1000 ms Memory Size: 128 MB Max Memory Used: 41 MB
- permissionの追加
======================
4.1. ロールARNの取得
変数の設定
LAMBDA_RULE_ROLE_ARN=$( \
aws iam list-roles \
--query "Roles[?contains(RoleName, \`${IAM_ROLE_NAME}\`)].Arn" \
--output text \
) \
&& echo ${LAMBDA_RULE_ROLE_ARN}
4.2. Lambda実行権限の付与
変数の設定
LAMBDA_STAT_ID='AllowScheduledEvents'
LAMBDA_PERMIT_ACTION='lambda:InvokeFunction'
LAMBDA_PERMIT_PRINCIPAL='events.amazonaws.com'
変数の確認
cat << ETX
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
LAMBDA_STAT_ID: "${LAMBDA_STAT_ID}"
LAMBDA_PERMIT_ACTION: ${LAMBDA_PERMIT_ACTION}
LAMBDA_PERMIT_PRINCIPAL: ${LAMBDA_PERMIT_PRINCIPAL}
LAMBDA_RULE_ROLE_ARN: ${LAMBDA_RULE_ROLE_ARN}
ETX
コマンド
aws lambda add-permission \
--function-name ${LAMBDA_FUNC_NAME} \
--statement-id "${LAMBDA_STAT_ID}" \
--action ${LAMBDA_PERMIT_ACTION} \
--principal ${LAMBDA_PERMIT_PRINCIPAL} \
--role ${LAMBDA_RULE_ROLE_ARN}
結果(例)
{
"Statement": "{\"Action\":[\"lambda:InvokeFunction\"],\"Resource\":\"arn:aws:lambda:us-west-2:XXXXXXXXXXXX:function:good_morning_lambda\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"events.amazonaws.com\"},\"Sid\":\"AllowScheduledEvents\"}"
}