Skip to content

Commit

Permalink
fix(custom-resources): unable to use a resource attributes as diction…
Browse files Browse the repository at this point in the history
…ary keys in AwsCustomResource (#13074)

AWS calls sometimes require to specify resource names or ARNs in dictionary keys (e.g. `dynamodb:BatchWriteItem`). Since resource attributes resolve only during deployment, we
expect to be able to pass them in dictionary keys. This does not work out of the box because JSON only allows strings in dictionary keys and attributes in CFN are modeled as JSON objects (`{ "Fn::GetAtt": ["X", "Y" ] }`, etc).

To address this, we simply encode `Create`, `Update` and `Delete` properties passed to the custom resource as token-aware JSON strings using `stack.toJsonString()`, and decode them in the custom resource.

Since the entire object is encoded, the special-casing for boolean encoding is no longer needed.

Additionally, we added support for `toJSON()` in the token resolution logic (`stack.resolve()`). If resolve encounters an object that has a `toJSON()` method, it will call it and continue resolution with the output value. This is needed here before `AwsCustomResource` uses this standard JS behavior to encode physical name references in requests.

We also made `CfnJson.value` public to allow directly accessing the referenced value in case it is needed (this could have been used as an alternative to the built-in support for token-aware stringification if we didn’t support it in AwsCustomResource) - see referenced issue.

Resolves #13063


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
Elad Ben-Israel authored Feb 24, 2021
1 parent 703b39a commit 3cb3104
Show file tree
Hide file tree
Showing 29 changed files with 1,107 additions and 1,410 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3491,4 +3491,4 @@
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1111,56 +1111,36 @@
]
},
"Create": {
"service": "SQS",
"action": "sendMessage",
"parameters": {
"QueueUrl": {
"Ref": "nameserviceTaskRecordManagerEventsQueueF805A6C1"
},
"DelaySeconds": 10,
"MessageBody": "{ \"prime\": true }",
"MessageAttributes": {
"HostedZoneId": {
"DataType": "String",
"StringValue": {
"Ref": "zoneEB40FF1E"
}
"Fn::Join": [
"",
[
"{\"service\":\"SQS\",\"action\":\"sendMessage\",\"parameters\":{\"QueueUrl\":\"",
{
"Ref": "nameserviceTaskRecordManagerEventsQueueF805A6C1"
},
"RecordName": {
"DataType": "String",
"StringValue": "test-record"
}
}
},
"physicalResourceId": {
"responsePath": "MessageId"
}
"\",\"DelaySeconds\":10,\"MessageBody\":\"{ \\\"prime\\\": true }\",\"MessageAttributes\":{\"HostedZoneId\":{\"DataType\":\"String\",\"StringValue\":\"",
{
"Ref": "zoneEB40FF1E"
},
"\"},\"RecordName\":{\"DataType\":\"String\",\"StringValue\":\"test-record\"}}},\"physicalResourceId\":{\"responsePath\":\"MessageId\"}}"
]
]
},
"Update": {
"service": "SQS",
"action": "sendMessage",
"parameters": {
"QueueUrl": {
"Ref": "nameserviceTaskRecordManagerEventsQueueF805A6C1"
},
"DelaySeconds": 10,
"MessageBody": "{ \"prime\": true }",
"MessageAttributes": {
"HostedZoneId": {
"DataType": "String",
"StringValue": {
"Ref": "zoneEB40FF1E"
}
"Fn::Join": [
"",
[
"{\"service\":\"SQS\",\"action\":\"sendMessage\",\"parameters\":{\"QueueUrl\":\"",
{
"Ref": "nameserviceTaskRecordManagerEventsQueueF805A6C1"
},
"RecordName": {
"DataType": "String",
"StringValue": "test-record"
}
}
},
"physicalResourceId": {
"responsePath": "MessageId"
}
"\",\"DelaySeconds\":10,\"MessageBody\":\"{ \\\"prime\\\": true }\",\"MessageAttributes\":{\"HostedZoneId\":{\"DataType\":\"String\",\"StringValue\":\"",
{
"Ref": "zoneEB40FF1E"
},
"\"},\"RecordName\":{\"DataType\":\"String\",\"StringValue\":\"test-record\"}}},\"physicalResourceId\":{\"responsePath\":\"MessageId\"}}"
]
]
},
"InstallLatestAwsSdk": true
},
Expand Down Expand Up @@ -1210,7 +1190,7 @@
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3Bucket38F1BB8E"
"Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904"
},
"S3Key": {
"Fn::Join": [
Expand All @@ -1223,7 +1203,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0"
"Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF"
}
]
}
Expand All @@ -1236,7 +1216,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0"
"Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF"
}
]
}
Expand Down Expand Up @@ -1286,17 +1266,17 @@
"Type": "String",
"Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\""
},
"AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3Bucket38F1BB8E": {
"AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904": {
"Type": "String",
"Description": "S3 bucket for asset \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\""
"Description": "S3 bucket for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\""
},
"AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0": {
"AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF": {
"Type": "String",
"Description": "S3 key for asset version \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\""
"Description": "S3 key for asset version \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\""
},
"AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94ArtifactHash782948FC": {
"AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343ArtifactHash0C561FF5": {
"Type": "String",
"Description": "Artifact hash for asset \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\""
"Description": "Artifact hash for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\""
}
},
"Outputs": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2235,4 +2235,4 @@
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,49 +53,9 @@ export = {
'Arn',
],
},
Create: {
action: 'createDeploymentConfig',
service: 'CodeDeploy',
parameters: {
computePlatform: 'Lambda',
deploymentConfigName: 'CustomConfig.LambdaCanary5Percent1Minutes',
trafficRoutingConfig: {
timeBasedCanary: {
canaryPercentage: '5',
canaryInterval: '1',
},
type: 'TimeBasedCanary',
},
},
physicalResourceId: {
id: 'CustomConfig.LambdaCanary5Percent1Minutes',
},
},
Update: {
action: 'createDeploymentConfig',
service: 'CodeDeploy',
parameters: {
computePlatform: 'Lambda',
deploymentConfigName: 'CustomConfig.LambdaCanary5Percent1Minutes',
trafficRoutingConfig: {
timeBasedCanary: {
canaryPercentage: '5',
canaryInterval: '1',
},
type: 'TimeBasedCanary',
},
},
physicalResourceId: {
id: 'CustomConfig.LambdaCanary5Percent1Minutes',
},
},
Delete: {
action: 'deleteDeploymentConfig',
service: 'CodeDeploy',
parameters: {
deploymentConfigName: 'CustomConfig.LambdaCanary5Percent1Minutes',
},
},
Create: '{"service":"CodeDeploy","action":"createDeploymentConfig","parameters":{"deploymentConfigName":"CustomConfig.LambdaCanary5Percent1Minutes","computePlatform":"Lambda","trafficRoutingConfig":{"type":"TimeBasedCanary","timeBasedCanary":{"canaryInterval":"1","canaryPercentage":"5"}}},"physicalResourceId":{"id":"CustomConfig.LambdaCanary5Percent1Minutes"}}',
Update: '{"service":"CodeDeploy","action":"createDeploymentConfig","parameters":{"deploymentConfigName":"CustomConfig.LambdaCanary5Percent1Minutes","computePlatform":"Lambda","trafficRoutingConfig":{"type":"TimeBasedCanary","timeBasedCanary":{"canaryInterval":"1","canaryPercentage":"5"}}},"physicalResourceId":{"id":"CustomConfig.LambdaCanary5Percent1Minutes"}}',
Delete: '{"service":"CodeDeploy","action":"deleteDeploymentConfig","parameters":{"deploymentConfigName":"CustomConfig.LambdaCanary5Percent1Minutes"}}',
}));

expect(stack).to(haveResource('AWS::IAM::Policy', {
Expand Down Expand Up @@ -134,27 +94,9 @@ export = {

// THEN
expect(stack).to(haveResourceLike('Custom::AWS', {
Create: {
parameters: {
deploymentConfigName: 'MyDeploymentConfig',
},
physicalResourceId: {
id: 'MyDeploymentConfig',
},
},
Update: {
parameters: {
deploymentConfigName: 'MyDeploymentConfig',
},
physicalResourceId: {
id: 'MyDeploymentConfig',
},
},
Delete: {
parameters: {
deploymentConfigName: 'MyDeploymentConfig',
},
},
Create: '{"service":"CodeDeploy","action":"createDeploymentConfig","parameters":{"deploymentConfigName":"MyDeploymentConfig","computePlatform":"Lambda","trafficRoutingConfig":{"type":"TimeBasedCanary","timeBasedCanary":{"canaryInterval":"1","canaryPercentage":"5"}}},"physicalResourceId":{"id":"MyDeploymentConfig"}}',
Update: '{"service":"CodeDeploy","action":"createDeploymentConfig","parameters":{"deploymentConfigName":"MyDeploymentConfig","computePlatform":"Lambda","trafficRoutingConfig":{"type":"TimeBasedCanary","timeBasedCanary":{"canaryInterval":"1","canaryPercentage":"5"}}},"physicalResourceId":{"id":"MyDeploymentConfig"}}',
Delete: '{"service":"CodeDeploy","action":"deleteDeploymentConfig","parameters":{"deploymentConfigName":"MyDeploymentConfig"}}',
}));
test.done();
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,32 +71,36 @@
]
},
"Create": {
"service": "CognitoIdentityServiceProvider",
"action": "describeUserPoolDomain",
"parameters": {
"Domain": {
"Ref": "UserPoolDomainD0EA232A"
}
},
"physicalResourceId": {
"id": {
"Ref": "UserPoolDomainD0EA232A"
}
}
"Fn::Join": [
"",
[
"{\"service\":\"CognitoIdentityServiceProvider\",\"action\":\"describeUserPoolDomain\",\"parameters\":{\"Domain\":\"",
{
"Ref": "UserPoolDomainD0EA232A"
},
"\"},\"physicalResourceId\":{\"id\":\"",
{
"Ref": "UserPoolDomainD0EA232A"
},
"\"}}"
]
]
},
"Update": {
"service": "CognitoIdentityServiceProvider",
"action": "describeUserPoolDomain",
"parameters": {
"Domain": {
"Ref": "UserPoolDomainD0EA232A"
}
},
"physicalResourceId": {
"id": {
"Ref": "UserPoolDomainD0EA232A"
}
}
"Fn::Join": [
"",
[
"{\"service\":\"CognitoIdentityServiceProvider\",\"action\":\"describeUserPoolDomain\",\"parameters\":{\"Domain\":\"",
{
"Ref": "UserPoolDomainD0EA232A"
},
"\"},\"physicalResourceId\":{\"id\":\"",
{
"Ref": "UserPoolDomainD0EA232A"
},
"\"}}"
]
]
},
"InstallLatestAwsSdk": true
},
Expand Down Expand Up @@ -142,7 +146,7 @@
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3Bucket38F1BB8E"
"Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904"
},
"S3Key": {
"Fn::Join": [
Expand All @@ -155,7 +159,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0"
"Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF"
}
]
}
Expand All @@ -168,7 +172,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0"
"Ref": "AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF"
}
]
}
Expand Down Expand Up @@ -209,17 +213,17 @@
}
},
"Parameters": {
"AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3Bucket38F1BB8E": {
"AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3Bucket65227904": {
"Type": "String",
"Description": "S3 bucket for asset \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\""
"Description": "S3 bucket for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\""
},
"AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94S3VersionKeyCCDC67C0": {
"AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343S3VersionKey3AF0E7DF": {
"Type": "String",
"Description": "S3 key for asset version \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\""
"Description": "S3 key for asset version \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\""
},
"AssetParametersb64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94ArtifactHash782948FC": {
"AssetParameters0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343ArtifactHash0C561FF5": {
"Type": "String",
"Description": "Artifact hash for asset \"b64b129569a5ac7a9abf88a18ac0b504d1fb1208872460476ed3fd435830eb94\""
"Description": "Artifact hash for asset \"0625b1566df06e0ffd948f0f65f97a3d22d48242e66196d3f72b480f5309b343\""
}
}
}
32 changes: 26 additions & 6 deletions packages/@aws-cdk/aws-elasticsearch/test/domain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,17 +382,37 @@ describe('log groups', () => {
// Domain1
expect(stack).toHaveResourceLike('Custom::CloudwatchLogResourcePolicy', {
Create: {
parameters: {
policyName: 'ESLogPolicyc836fd92f07ec41eb70c2f6f08dc4b43cfb7c25391',
},
'Fn::Join': [
'',
[
'{"service":"CloudWatchLogs","action":"putResourcePolicy","parameters":{"policyName":"ESLogPolicyc836fd92f07ec41eb70c2f6f08dc4b43cfb7c25391","policyDocument":"{\\"Statement\\":[{\\"Action\\":[\\"logs:PutLogEvents\\",\\"logs:CreateLogStream\\"],\\"Effect\\":\\"Allow\\",\\"Principal\\":{\\"Service\\":\\"es.amazonaws.com\\"},\\"Resource\\":\\"',
{
'Fn::GetAtt': [
'Domain1AppLogs6E8D1D67',
'Arn',
],
},
'\\"}],\\"Version\\":\\"2012-10-17\\"}"},"physicalResourceId":{"id":"ESLogGroupPolicyc836fd92f07ec41eb70c2f6f08dc4b43cfb7c25391"}}',
],
],
},
});
// Domain2
expect(stack).toHaveResourceLike('Custom::CloudwatchLogResourcePolicy', {
Create: {
parameters: {
policyName: 'ESLogPolicyc8f05f015be3baf6ec1ee06cd1ee5cc8706ebbe5b2',
},
'Fn::Join': [
'',
[
'{"service":"CloudWatchLogs","action":"putResourcePolicy","parameters":{"policyName":"ESLogPolicyc8f05f015be3baf6ec1ee06cd1ee5cc8706ebbe5b2","policyDocument":"{\\"Statement\\":[{\\"Action\\":[\\"logs:PutLogEvents\\",\\"logs:CreateLogStream\\"],\\"Effect\\":\\"Allow\\",\\"Principal\\":{\\"Service\\":\\"es.amazonaws.com\\"},\\"Resource\\":\\"',
{
'Fn::GetAtt': [
'Domain2AppLogs810876E2',
'Arn',
],
},
'\\"}],\\"Version\\":\\"2012-10-17\\"}"},"physicalResourceId":{"id":"ESLogGroupPolicyc8f05f015be3baf6ec1ee06cd1ee5cc8706ebbe5b2"}}',
],
],
},
});
});
Expand Down
Loading

0 comments on commit 3cb3104

Please sign in to comment.