前提条件
Lambdaへの権限
Lambdaに対してフル権限があること。
AWS CLI
以下のバージョンで動作確認済
- AWS CLI 1.10.58
コマンド
aws --version
結果(例)
aws-cli/1.10.58 Python/2.7.11 Darwin/15.6.0 botocore/1.4.48
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": "AROAXXXXXXXXXXXXXXXXX",
"CreateDate": "2015-10-26T01:55:54Z",
"RoleName": "lambdaBasicExecution",
"Path": "/",
"Arn": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution"
}
}
IAMロールが存在しない場合、http://qiita.com/tcsh/items/6353876a5c4fef63b4d8 の手順に従って作成してください。
Slack
Slackのチーム管理権限があること
0. 準備
0.1. リージョンの決定
変数の設定
export AWS_DEFAULT_REGION='ap-northeast-1'
0.2. 変数の確認
プロファイルが想定のものになっていることを確認します。
変数の確認
aws configure list
結果(例)
Name Value Type Location
---- ----- ---- --------
profile lambdaFull-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.3. IAM RoleのARN取得
コマンド
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
0.4. Slackの設定
まず、Slash Commandの追加を行います。
-
https://${SLACK_TEAM_NAME}.slack.com/apps にアクセスします。(App Directory 画面)
- 検索窓に 'Slash Commands' と入力します。
- 'Slash Commands'が表示されるので、クリックします。
-
Browse Apps > Slash Commands (画面)
- Add Configurationをクリックします。
-
New configuration (画面)
- Choose a Command(入力欄)に下記の文字列を入力します。
- /sayhello
- Add Slash Command Integrationをクリックします。
- Choose a Command(入力欄)に下記の文字列を入力します。
-
Edit configuration (画面)
- 'Integration Settings'欄の'Token'の値をメモに保存します。
- 例: DxAoIy9PdXXEXe08mvH9VsQL
- 'Integration Settings'欄の'Token'の値をメモに保存します。
変数の設定
SLACK_TOKEN='<SlackのTokenの値>'
1. 事前作業
1.1. Lambda関数名の決定
変数の設定
LAMBDA_FUNC_NAME="slack-echo-command-$( date '+%Y%m%d' )" \
&& echo ${LAMBDA_FUNC_NAME}
同名の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:slack-echo-command-20160829
1.2. Lambda関数
変数の設定
FILE_LAMBDA_FUNC="${LAMBDA_FUNC_NAME}.py"
PY_FUNC_NAME='lambda_handler'
変数の確認
cat << ETX
FILE_LAMBDA_FUNC: ${FILE_LAMBDA_FUNC}
PY_FUNC_NAME: ${PY_FUNC_NAME}
SLACK_TOKEN: ${SLACK_TOKEN}
ETX
コマンド
cat << EOF > ${FILE_LAMBDA_FUNC}
import boto3
from base64 import b64decode
from urlparse import parse_qs
import logging
#ENCRYPTED_EXPECTED_TOKEN = "<kmsEncryptedToken>" # Enter the base-64 encoded, encrypted Slack command token (CiphertextBlob)
#kms = boto3.client('kms')
#expected_token = kms.decrypt(CiphertextBlob = b64decode(ENCRYPTED_EXPECTED_TOKEN))['Plaintext']
expected_token = '${SLACK_TOKEN}'
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")
user = params['user_name'][0]
command = params['command'][0]
channel = params['channel_name'][0]
command_text = params['text'][0]
return "%s invoked %s in %s with the following text: %s" % (user, command, channel, command_text)
EOF
cat ${FILE_LAMBDA_FUNC}
コマンド
zip ${LAMBDA_FUNC_NAME}.zip ${FILE_LAMBDA_FUNC}
結果(例)
adding: slack-echo-command-20160829.py (deflated 43%)
2. Lambda関数の作成
変数の設定
LAMBDA_FUNC_DESC='A function that handles a Slack slash command and echoes the details back to the user.'
LAMBDA_RUNTIME='python2.7'
LAMBDA_HANDLER="${LAMBDA_FUNC_NAME}.${PY_FUNC_NAME}"
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": "WnGd6iPBS0rGCJor4zyuOaGBtzQ3I/OgHerXWqZzbL8=",
"FunctionName": "slack-echo-command-20160829",
"CodeSize": 350,
"MemorySize": 128,
"FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:slack-echo-command-20160829",
"Version": "$LATEST",
"Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution",
"Timeout": 3,
"LastModified": "2016-08-28T01:23:45.678+0000",
"Handler": "slack-echo-command-20160829.lambda_handler",
"Runtime": "python2.7",
"Description": "A function that handles a Slack slash command and echoes the details back to the user."
}
コマンド
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/HelloWorld-2979ba79-b08f-495d-9ee6-46397c95ba13?x-amz-security-token=AQoDYXdzEDoa8AMR6t8h66eOXhN3%2Fx7XpuRxvf7pVn7IuWV4cEmwx0CtZT6yxCJ1%2BWmigYXqGoyQHuBYOWnxbhmwEcTg839qMuhSu1fk0fXpXf0oJOLkhKMudNqhdElyFQpzyT6Q8GDfhAsfbX9wvwCDTty4imxz7MczF%2FQl6tgvTYdip08ap5fAyrknZGV1%2B1Ggnp5w6JOjydYxuUsWwhoxoEWzi7SoVTmpRQQA91c4VW9lNotOAHACFxo6klzDPM8mxR9RJl66WxFugL0wQJyLUpmtjS9XoArD86sEWWiIccMpV2BQipTPQlzL%2F1Hoy%2BDF6QUxyPUihlDjPBoJTISTP8W1wxmzW%2BLbilAfFQRPY7CFjzR0k%2FA%2FIX5x9iyz52Pu1Q0ASTw1l%2Fq%2Fo3pRbvzWR79QS%2BpxXrwbYzoQHKiK62DSTsQo5tqKPsiDCYzrPxbq8lm7pNBPG%2FsxjePRWBVJeRl08WxEjSjoRRwBOPX5mz1BCUoUBPGG5tEENp87A%2FCdDgibFWM5DdYhwtaYPY7FTmi8DvqjQHL9jOmP8YuVteBTBcv8nFW6UbErPjwwn79FKG1u5M9HoTWUqUMBByz6D4tTRSEw6iJU7XdCujFnhnHe5V8imZ1KGI7fDWpciJhrhml0wnKPCK%2Fe9lK1P2kO7ldSWc7zn5hcIOD2tbEF&AWSAccessKeyId=ASIAJFVALOKV5SJVYPPA&Expires=1445825978&Signature=bvwu1Ny34LgTmZeOO3q4sn7x3Fg%3D"
},
"Configuration": {
"Version": "$LATEST",
"CodeSha256": "WnGd6iPBS0rGCJor4zyuOaGBtzQ3I/OgHerXWqZzbL8=",
"FunctionName": "slack-echo-command-20160829",
"MemorySize": 128,
"CodeSize": 350,
"FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:slack-echo-command-20160829",
"Handler": "slack-echo-command-20160829.lambda_handler",
"Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution",
"Timeout": 3,
"LastModified": "2016-08-28T01:23:45.678+0000",
"Runtime": "python2.7",
"Description": "A function that handles a Slack slash command and echoes the details back to the user."
}
}
3. Lambda関数の動作確認
3.1. サンプルデータの作成
コマンド関連の変数の指定
変数の設定
STR_COMMAND='sayhello'
STR_CHANNEL_NAME='general'
変数の設定
STR_TEXT='ec2'
STR_USER_NAME='Steve'
変数の設定
FILE_INPUT="${LAMBDA_FUNC_NAME}-data.json" \
&& echo ${FILE_INPUT}
変数の確認
cat << ETX
SLACK_TOKEN: ${SLACK_TOKEN}
STR_COMMAND: ${STR_COMMAND}
STR_TEXT: ${STR_TEXT}
STR_USER_NAME: ${STR_USER_NAME}
STR_CHANNEL_NAME: ${STR_CHANNEL_NAME}
FILE_INPUT: ${FILE_INPUT}
ETX
サンプルデータ
cat << EOF > ${FILE_INPUT}
{
"body": "token=${SLACK_TOKEN}&command=/sayhello&text=ec2&user_name=Steve&channel_name=general"
}
EOF
cat ${FILE_INPUT}
JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。
コマンド
jsonlint -q ${FILE_INPUT}
エラーが出力されなければOKです。
3.2. lambda関数の手動実行
変数の設定
FILE_OUTPUT_LAMBDA="${LAMBDA_FUNC_NAME}-out.txt"
FILE_LOG_LAMBDA="${LAMBDA_FUNC_NAME}-$(date +%Y%m%d%H%M%S).log"
変数の確認
cat << ETX
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
FILE_INPUT: ${FILE_INPUT}
FILE_OUTPUT_LAMBDA: ${FILE_OUTPUT_LAMBDA}
FILE_LOG_LAMBDA: ${FILE_LOG_LAMBDA}
ETX
コマンド
aws lambda invoke \
--function-name ${LAMBDA_FUNC_NAME} \
--log-type Tail \
--payload file://${FILE_INPUT} \
${FILE_OUTPUT_LAMBDA} \
> ${FILE_LOG_LAMBDA}
コマンド
cat ${FILE_LOG_LAMBDA} \
| jp.py 'StatusCode'
結果(例)
200
3.3. lambda関数の実行結果の確認
コマンド
cat ${FILE_OUTPUT_LAMBDA}
結果(例)
"Steve invoked /sayhello in general with the following text: ec2"
3.4. lambda関数のログの確認
コマンド
cat ${FILE_LOG_LAMBDA} \
| jp.py 'LogResult' \
| sed 's/"//' \
| base64 --decode
結果(例)
START RequestId: 6a466adf-6cec-11e6-9e83-f3993fe0dc41 Version: $LATEST
END RequestId: 6a466adf-6cec-11e6-9e83-f3993fe0dc41
REPORT RequestId: 6a466adf-6cec-11e6-9e83-f3993fe0dc41 Duration: 0.34 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 45 MB
完了
Lambdaの実行許可は、RestAPI作成後に行います。