cloudpack あら便利カレンダー 2019 の記事となります。誕生秘話 はこちら。
AWS CloudFormationのLambda-backedカスタムリソースを利用するとAWS CloudFormationで管理できないリソースも管理することができますが、Lambda-backedで作成したリソースの更新・削除するのにリソースのIDをどうやって取り回そうか悩みました。
下記は解決策の1案となりますが、他に良い方法があれば教えてほしいです!
前提
- AWSアカウントがある
- AWS CLIが利用できる
- AWS Lambda、CloudFormationの作成権限がある
CloudFormationのテンプレート作成
> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> touch cfn-template.yaml
Lambda-backedカスタムリソースを利用して何かしらのリソースを作成・更新・削除するテンプレートとなります。
ポイントとしてはCreateResource
のひとつで完結できたら良かったのですが、CreateResource
で作成したリソースのIDを自前で取り回せなかったので、更新と削除を別リソースUpdateResource
で行うようにしました。うーん、めんどうです
Resources:
CreateResource:
Type: Custom::CustomResource
Properties:
ServiceToken: !GetAtt CreateResourceFunction.Arn
UpdateResource:
Type: Custom::CustomResource
Properties:
ServiceToken: !GetAtt UpdateResourceFunction.Arn
ResourceId: !GetAtt CreateResource.Id
CreateResourceFunction:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Role: !GetAtt FunctionExecutionRole.Arn
Code:
ZipFile: !Sub |
import cfnresponse
def handler(event, context):
if event['RequestType'] == 'Create':
# なんかリソース作成
response = {'Id': 'hoge'}
print('create resources ' + response['Id'])
cfnresponse.send(event, context, cfnresponse.SUCCESS, response)
return
# 他のRequestTypeは無視
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
Runtime: python3.7
UpdateResourceFunction:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Role: !GetAtt FunctionExecutionRole.Arn
Code:
ZipFile: !Sub |
import cfnresponse
def handler(event, context):
Id = event['ResourceProperties']['ResourceId']
if event['RequestType'] == 'Update':
# なんかリソース更新
print('update resources ' + Id)
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
return
if event['RequestType'] == 'Delete':
# なんかリソース削除
print('delete resources ' + Id)
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
return
# 他のRequestTypeは無視
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
Runtime: python3.7
FunctionExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: root
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "arn:aws:logs:*:*:*"
動作確認
スタック作成
> aws cloudformation create-stack \
--stack-name cfn-lambda-backed-test \
--template-body file://cfn-template.yaml \
--capabilities CAPABILITY_IAM
{
"StackId": "arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/cfn-lambda-backed-test/3bed13d0-96e9-11e9-90fb-122d883fe268"
}
スタック作成して各リソースが作成できたらLambda関数のログを確認します。
各リソースと関数のPhysicalResourceId
をパラメータにaws logs get-log-events
コマンドで取得します。
> aws cloudformation list-stack-resources \
--stack-name cfn-lambda-backed-test
{
"StackResourceSummaries": [
{
"LogicalResourceId": "CreateResource",
"PhysicalResourceId": "2019/06/25/[$LATEST]587b7bbfa5b74a38a54846ff44a9a592",
"ResourceType": "Custom::CustomResource",
"LastUpdatedTimestamp": "2019-06-25T01:33:55.358Z",
"ResourceStatus": "CREATE_COMPLETE",
"DriftInformation": {
"StackResourceDriftStatus": "NOT_CHECKED"
}
},
{
"LogicalResourceId": "CreateResourceFunction",
"PhysicalResourceId": "cfn-lambda-backed-test-CreateResourceFunction-LBG1WB6FV88B",
"ResourceType": "AWS::Lambda::Function",
"LastUpdatedTimestamp": "2019-06-25T01:33:49.819Z",
"ResourceStatus": "CREATE_COMPLETE",
"DriftInformation": {
"StackResourceDriftStatus": "NOT_CHECKED"
}
},
{
"LogicalResourceId": "FunctionExecutionRole",
"PhysicalResourceId": "cfn-lambda-backed-test-FunctionExecutionRole-17PMYTJ3NS41Z",
"ResourceType": "AWS::IAM::Role",
"LastUpdatedTimestamp": "2019-06-25T01:33:46.370Z",
"ResourceStatus": "CREATE_COMPLETE",
"DriftInformation": {
"StackResourceDriftStatus": "NOT_CHECKED"
}
},
{
"LogicalResourceId": "UpdateResource",
"PhysicalResourceId": "2019/06/25/[$LATEST]59ec7f3b07ec48f5b5feab288384b268",
"ResourceType": "Custom::CustomResource",
"LastUpdatedTimestamp": "2019-06-25T01:34:01.068Z",
"ResourceStatus": "CREATE_COMPLETE",
"DriftInformation": {
"StackResourceDriftStatus": "NOT_CHECKED"
}
},
{
"LogicalResourceId": "UpdateResourceFunction",
"PhysicalResourceId": "cfn-lambda-backed-test-UpdateResourceFunction-BMXD99ZLKXP0",
"ResourceType": "AWS::Lambda::Function",
"LastUpdatedTimestamp": "2019-06-25T01:33:49.516Z",
"ResourceStatus": "CREATE_COMPLETE",
"DriftInformation": {
"StackResourceDriftStatus": "NOT_CHECKED"
}
}
]
}
> aws logs get-log-events \
--log-group-name /aws/lambda/cfn-lambda-backed-test-CreateResourceFunction-LBG1WB6FV88B \
--log-stream-name '2019/06/25/[$LATEST]587b7bbfa5b74a38a54846ff44a9a592' \
--output=text \
--query "events[*].message"
START RequestId: e8ad68ad-86be-4ea1-ad3f-736617882ce7 Version: $LATEST
create resources hoge
https://cloudformation-custom-resource-response-useast1.s3.amazonaws.com/(略)
Response body:
{"Status": "SUCCESS", "Reason": "See the details in CloudWatch Log Stream: 2019/06/25/[$LATEST]587b7bbfa5b74a38a54846ff44a9a592", "PhysicalResourceId": "2019/06/25/[$LATEST]587b7bbfa5b74a38a54846ff44a9a592", "StackId": "arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/cfn-lambda-backed-test/3bed13d0-96e9-11e9-90fb-122d883fe268", "RequestId": "1cb162f1-979f-4e6f-b277-dd7e729d23cc", "LogicalResourceId": "CreateResource", "NoEcho": false, "Data": {"Id": "hoge"}}
Status code: OK
END RequestId: e8ad68ad-86be-4ea1-ad3f-736617882ce7
REPORT RequestId: e8ad68ad-86be-4ea1-ad3f-736617882ce7 Duration: 292.74 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 29 MB
> aws logs get-log-events \
--log-group-name /aws/lambda/cfn-lambda-backed-test-UpdateResourceFunction-BMXD99ZLKXP0 \
--log-stream-name '2019/06/25/[$LATEST]59ec7f3b07ec48f5b5feab288384b268' \
--output=text \
--query "events[*].message"
START RequestId: d593f33a-9231-4284-8157-97b5b799f70e Version: $LATEST
https://cloudformation-custom-resource-response-useast1.s3.amazonaws.com/(略)
Response body:
{"Status": "SUCCESS", "Reason": "See the details in CloudWatch Log Stream: 2019/06/25/[$LATEST]59ec7f3b07ec48f5b5feab288384b268", "PhysicalResourceId": "2019/06/25/[$LATEST]59ec7f3b07ec48f5b5feab288384b268", "StackId": "arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/cfn-lambda-backed-test/3bed13d0-96e9-11e9-90fb-122d883fe268", "RequestId": "fe1b2ba8-0aff-44a6-ac1f-f46863594b0f", "LogicalResourceId": "UpdateResource", "NoEcho": false, "Data": {}}
Status code: OK
END RequestId: d593f33a-9231-4284-8157-97b5b799f70e
REPORT RequestId: d593f33a-9231-4284-8157-97b5b799f70e Duration: 242.26 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 29 MB
スタック作成時にはCreateResource
でリソースの作成、UpdateResource
は呼び出しのみとなることが確認できました。
スタック削除
スタックを削除して動作を確認します。
> aws cloudformation delete-stack \
--stack-name cfn-lambda-backed-test
{
"StackId": "arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/cfn-lambda-backed-test/3bed13d0-96e9-11e9-90fb-122d883fe268"
}
スタック削除すると当然のことながらリソースが取得できなくなるので、ログストリーム名を取得してからログを確認します。
> aws logs describe-log-streams \
--log-group-name /aws/lambda/cfn-lambda-backed-test-CreateResourceFunction-LBG1WB6FV88B \
--output=text \
--query "logStreams[*].logStreamName"
2019/06/25/[$LATEST]587b7bbfa5b74a38a54846ff44a9a592 2019/06/25/[$LATEST]8d6fac4288674ecbb7b6f7a577b8b932
> aws logs get-log-events \
--log-group-name /aws/lambda/cfn-lambda-backed-test-CreateResourceFunction-LBG1WB6FV88B \
--log-stream-name '2019/06/25/[$LATEST]8d6fac4288674ecbb7b6f7a577b8b932' \
--output=text \
--query "events[*].message"
START RequestId: 8a0c34a7-8c3a-47b5-9128-3a49748aca52 Version: $LATEST
> aws logs describe-log-streams \
--log-group-name /aws/lambda/cfn-lambda-backed-test-UpdateResourceFunction-BMXD99ZLKXP0 \
--output=text \
--query "logStreams[*].logStreamName"
2019/06/25/[$LATEST]0c2223e7635d4ee0b04c508e0fc76511 2019/06/25/[$LATEST]59ec7f3b07ec48f5b5feab288384b268
> aws logs get-log-events \
--log-group-name /aws/lambda/cfn-lambda-backed-test-UpdateResourceFunction-BMXD99ZLKXP0 \
--log-stream-name '2019/06/25/[$LATEST]0c2223e7635d4ee0b04c508e0fc76511' \
--output=text \
--query "events[*].message"
START RequestId: fcde5258-b444-4e33-aef6-d2dcff63e2c2 Version: $LATEST
delete resources hoge
https://cloudformation-custom-resource-response-useast1.s3.amazonaws.com/(略)
Response body:
{"Status": "SUCCESS", "Reason": "See the details in CloudWatch Log Stream: 2019/06/25/[$LATEST]0c2223e7635d4ee0b04c508e0fc76511", "PhysicalResourceId": "2019/06/25/[$LATEST]0c2223e7635d4ee0b04c508e0fc76511", "StackId": "arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/cfn-lambda-backed-test/3bed13d0-96e9-11e9-90fb-122d883fe268", "RequestId": "5d390a57-55b6-4ddd-8820-0104c94ab705", "LogicalResourceId": "UpdateResource", "NoEcho": false, "Data": {}}
Status code: OK
END RequestId: fcde5258-b444-4e33-aef6-d2dcff63e2c2
REPORT RequestId: fcde5258-b444-4e33-aef6-d2dcff63e2c2 Duration: 644.07 ms Billed Duration: 700 ms Memory Size: 128 MB Max Memory Used: 56 MB
スタック削除時にはCreateResource
は呼び出しのみ、UpdateResource
でリソースの削除がされることが確認できました。
まとめ
若干定義が面倒になりますがAWS CloudFormationのLambda-backedカスタムリソースを利用してリソースを更新・削除できることが確認できました。
参考
Blue21: lambdaのログを aws-cli で見る
https://blue21neo.blogspot.com/2018/02/lambda-aws-cli.html