問題
ずっとインジケータがぐるぐるしている
S3へのデプロイ完了後にCloudFrontのキャッシュを消すLambdaを呼びたいなーと思ったときに躓いたのでまとめ。
原因
codepipeline:PutJobSuccessResult(※)
を返却しないため
※ 失敗の場合はcodepipeline:PutJobFailedResult
PutJobSuccessResultって?
PutJobSuccessResult
ジョブワーカーによってパイプラインに返されたジョブの成功をレポートするために必要です。カスタムアクションにのみ使用されます。
https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/permissions-reference.html より引用
要約すると
CodePipelineは自身が呼び出したカスタムアクション(Lambdaとか)の結果をPutJobSuccessResult
、PutJobFailedResult
という決まった形式でしか受け取らない。
それ以外の形式で返しても無視するので、ずっとLambdaから結果こないなーまだかなーとインジケータがぐるぐるしてる。
PutJobSuccessResultを返した時
PutJobFailedResultを返した時
やったぜ。
対応
Lambda上でPutJobSuccessResult
、PutJobFailedResult
を返すコードを書くことでOK。
実際にLambdaでPutJobSuccessResult
、PutJobFailedResult
を返すための方法を言語別に。
Python
import json
import boto3
def lambda_handler(event, context):
codepipeline = boto3.client('codepipeline')
# CodePipelineに結果(成功)を返す
codepipeline.put_job_success_result(jobId = event['CodePipeline.job']['id'])
# CodePipelineに結果(失敗)を返す
# codepipeline.put_job_failure_result(
# jobId = event['CodePipeline.job']['id'],
# failureDetails={
# 'type': 'JobFailed',
# 'message': 'Failed test.'
# }
# )
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
Ruby
require 'json'
require 'aws-sdk'
def lambda_handler(event:, context:)
codepipeline = Aws::CodePipeline::Client.new()
# CodePipelineに結果(成功)を返す
codepipeline.put_job_success_result({job_id: event["CodePipeline.job"]['id']})
# CodePipelineに結果(失敗)を返す
# codepipeline.put_job_failure_result({
# job_id: event["CodePipeline.job"]['id'],
# failure_details: {
# type: "JobFailed", # accepts {JobFailed, ConfigurationError, PermissionError, RevisionOutOfSync, RevisionUnavailable, SystemUnavailable}
# message: "Failed test."
# }
# })
{ statusCode: 200, body: JSON.generate('Hello from Lambda!') }
end
Node.js
var AWS = require('aws-sdk');
exports.handler = function(event, context) {
var codepipeline = new AWS.CodePipeline();
// CodePipelineに結果(成功)を返す
codepipeline.putJobSuccessResult({jobId: event["CodePipeline.job"].id}, function(err, data) {
if(err) {
context.fail(err);
} else {
context.succeed('Success test.');
}
});
// CodePipelineに結果(失敗)を返す
// var params = {
// jobId: event["CodePipeline.job"].id,
// failureDetails: {
// message: JSON.stringify('Failed test.'),
// type: 'JobFailed',
// }
// };
// codepipeline.putJobFailureResult(params, function(err, data) {
// context.fail('Failed test.');
// });
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
普段Node.js書かないんでこれが必要最低限のコードかわっかんねー
コードコピペしたのにまだぐるぐるしてるじゃねーか!
まずLambdaのCloudWatchログを見てみよう。
AccessDeniedException
Lambdaの実行結果としてCloudWatchLogにこんなんがでる。
{
"errorType": "AccessDeniedException",
"errorMessage": "User: arn:aws:sts::1111111111111:assumed-role/codetest-role-xxxxxxxxx/codetest is not authorized to perform: codepipeline:PutJobSuccessResult",
...etc
}
LambdaからCodePipelineに結果を返すのにも権限がいるのだ...。
Lambdaに割り当てられてるIAMロールに以下のIAMポリシーを追加しておく必要あり。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:*"
],
"Effect": "Allow",
"Resource": "arn:aws:logs:*:*:*"
},
{
"Action": [
"codepipeline:PutJobSuccessResult",
"codepipeline:PutJobFailureResult"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
誤りなどあったら教えてくだせー。