cloudpack あら便利カレンダー 2019 の記事となります。誕生秘話 はこちら。
前回、AWS CloudFormation(CFn)のLambda-BackedカスタムリソースでネストされたJSONを返しても!GetAtt
で参照できないことがわかったのですが、よくよく調べてみるとネストで返せそうだったのでさらに調べてみました。
AWS CloudFormationのLambda-BackedカスタムリソースでネストされたJSONを返しても参照できない - Qiita
https://qiita.com/kai_kou/items/61a2b3c69ae2af4f2e40
結論
import cfnresponse
def handler(event, context):
data = {
"hoge": "hoge",
"foo.hoge": "hoge"
}
cfnresponse.send(event, context, cfnresponse.SUCCESS, data)
ってするとそれっぽくなります。(白目
調べたこと
CFnのGetAtt
関数ドキュメントにあるテンプレート例でSourceSecurityGroupOwnerId: !GetAtt myELB.SourceSecurityGroup.GroupName
とmyELB
リソースに対してネストされてる(っぽい)値SourceSecurityGroup.GroupName
を参照しているのをみつけました。
Fn::GetAtt - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html
LoadBalancerのドキュメントをみると戻り値として確かにSourceSecurityGroup.GroupName
は定義されています。
AWS::ElasticLoadBalancing::LoadBalancer - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-elb.html#aws-properties-ec2-elb-ref
通常のリソースの場合はネストされた情報が取り扱えるのでしょうか?
GetAttドキュメントの属性を確認すると、コンマ区切りで定義されている項目が確認できます。
Fn::GetAtt - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html#intrinsic-function-reference-getatt-attrib
Lambda-Backedカスタムリソースでネストされてるっぽくしてみる
Lambda-Backedカスタムリソースでも同じように参照できるレスポンスデータの返し方を考えてみました。
テンプレート定義
Lambda関数でフラットなJSONを返しますが、名前をfoo.hoge
とします(安直)。
Resources:
CustomResource:
Type: Custom::CustomResource
Properties:
ServiceToken: !GetAtt CustomResourceFunction.Arn
CustomResourceFunction:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Role: !GetAtt FunctionExecutionRole.Arn
Code:
ZipFile: !Sub |
import cfnresponse
def handler(event, context):
data = {
"hoge": "hoge",
"foo.hoge": "hoge"
}
cfnresponse.send(event, context, cfnresponse.SUCCESS, data)
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:*:*:*"
Outputs:
hoge:
Value: !GetAtt CustomResource.hoge
foo:
Value: !GetAtt CustomResource.foo.hoge
スタック作成して確認してみる
> aws cloudformation create-stack \
--stack-name cfn-response-test \
--template-body file://cfn-template.yaml \
--capabilities CAPABILITY_IAM
{
"StackId": "arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/cfn-response-test/cea96c90-97b7-11e9-b384-0e75601403f8"
}
> aws cloudformation describe-stacks \
--stack-name cfn-response-test
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/cfn-response-test/cea96c90-97b7-11e9-b384-0e75601403f8",
"StackName": "cfn-response-test",
"CreationTime": "2019-06-26T02:12:11.362Z",
"RollbackConfiguration": {},
"StackStatus": "CREATE_COMPLETE",
"DisableRollback": false,
"NotificationARNs": [],
"Capabilities": [
"CAPABILITY_IAM"
],
"Outputs": [
{
"OutputKey": "hoge",
"OutputValue": "hoge"
},
{
"OutputKey": "foo",
"OutputValue": "hoge"
}
],
"Tags": [],
"EnableTerminationProtection": false,
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
}
}
]
}
無事に!GetAtt CustomResource.foo.hoge
で値が参照できました。
一応関数のログを確認しておきます。
> aws cloudformation list-stack-resources \
--stack-name cfn-response-test
{
"StackResourceSummaries": [
{
"LogicalResourceId": "CustomResource",
"PhysicalResourceId": "2019/06/26/[$LATEST]0f6645081f974de7a40c44ac5a6b1493",
"ResourceType": "Custom::CustomResource",
"LastUpdatedTimestamp": "2019-06-26T02:12:38.029Z",
"ResourceStatus": "CREATE_COMPLETE",
"DriftInformation": {
"StackResourceDriftStatus": "NOT_CHECKED"
}
},
{
"LogicalResourceId": "CustomResourceFunction",
"PhysicalResourceId": "cfn-response-test-CustomResourceFunction-RUGERLT0O78L",
"ResourceType": "AWS::Lambda::Function",
"LastUpdatedTimestamp": "2019-06-26T02:12:33.223Z",
"ResourceStatus": "CREATE_COMPLETE",
"DriftInformation": {
"StackResourceDriftStatus": "NOT_CHECKED"
}
},
(略)
]
}
> aws logs get-log-events \
--log-group-name /aws/lambda/cfn-response-test-CustomResourceFunction-RUGERLT0O78L \
--log-stream-name '2019/06/26/[$LATEST]0f6645081f974de7a40c44ac5a6b1493' \
--output=text \
--query "events[*].message"
START RequestId: 9fb7a4fa-44b4-49ee-a5b7-bcbc57d40961 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/26/[$LATEST]0f6645081f974de7a40c44ac5a6b1493", "PhysicalResourceId": "2019/06/26/[$LATEST]0f6645081f974de7a40c44ac5a6b1493", "StackId": "arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/cfn-response-test/cea96c90-97b7-11e9-b384-0e75601403f8", "RequestId": "bc048c80-c2f9-42ab-a596-6e031d8299f3", "LogicalResourceId": "CustomResource", "NoEcho": false, "Data": {"hoge": "hoge", "foo.hoge": "hoge"}}
Status code: OK
END RequestId: 9fb7a4fa-44b4-49ee-a5b7-bcbc57d40961
REPORT RequestId: 9fb7a4fa-44b4-49ee-a5b7-bcbc57d40961 Duration: 351.55 ms Billed Duration: 400 ms Memory Size: 128 MB Max Memory Used: 24 MB
フラットですがネストされてるっぽく参照できるData
を返していることが確認できます。
まとめ
微妙に納得できない感じですが、テンプレートでどうしてもリソース情報のネスト構造を維持したまま参照したい場合にLambda-Backedカスタムリソース側で吸収するのに使えそうです。
参考
AWS CloudFormationのLambda-BackedカスタムリソースでネストされたJSONを返しても参照できない - Qiita
https://qiita.com/kai_kou/items/61a2b3c69ae2af4f2e40
Fn::GetAtt - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html
AWS::ElasticLoadBalancing::LoadBalancer - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-elb.html#aws-properties-ec2-elb-ref