Skip to content

Commit

Permalink
fix(cfn-include): allow dynamic mappings to be used in Fn::FindInMap (a…
Browse files Browse the repository at this point in the history
…ws#13428)

The template parsing logic in cloudformation-include always searched for the Mapping
in the template based on the first argument passed to Fn::FindInMap.
However, that doesn't work if that first argument is a dynamic expression,
like `{ Ref: Param }`.

Check for that case explicitly, and don't search for the Mapping
if the first argument to Fn::FindInMap is a dynamic expression.


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
skinny85 authored and cornerwings committed Mar 8, 2021
1 parent bb65498 commit 0867b80
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"Parameters": {
"Stage": {
"Type": "String",
"AllowedValues": ["beta"],
"Default": "beta"
}
},
"Mappings": {
"beta": {
"region": {
"key1": "name"
}
}
},
"Resources": {
"Bucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": {
"Fn::FindInMap": [
{ "Ref": "Stage" },
"region",
"key1"
]
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,14 @@ describe('CDK Include', () => {
}).toThrow(/Mapping with name 'NonExistentMapping' was not found in the template/);
});

test('can ingest a template that uses Fn::FindInMap with the first argument being a dynamic reference', () => {
includeTestTemplate(stack, 'find-in-map-with-dynamic-mapping.json');

expect(stack).toMatchTemplate(
loadTestFileToJsObject('find-in-map-with-dynamic-mapping.json'),
);
});

test('handles renaming Mapping references', () => {
const cfnTemplate = includeTestTemplate(stack, 'only-mapping-and-bucket.json');
const someMapping = cfnTemplate.getMapping('SomeMapping');
Expand Down
16 changes: 12 additions & 4 deletions packages/@aws-cdk/core/lib/cfn-parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -566,11 +566,19 @@ export class CfnParser {
case 'Fn::FindInMap': {
const value = this.parseValue(object[key]);
// the first argument to FindInMap is the mapping name
const mapping = this.finder.findMapping(value[0]);
if (!mapping) {
throw new Error(`Mapping used in FindInMap expression with name '${value[0]}' was not found in the template`);
let mappingName: string;
if (Token.isUnresolved(value[0])) {
// the first argument can be a dynamic expression like Ref: Param;
// if it is, we can't find the mapping in advance
mappingName = value[0];
} else {
const mapping = this.finder.findMapping(value[0]);
if (!mapping) {
throw new Error(`Mapping used in FindInMap expression with name '${value[0]}' was not found in the template`);
}
mappingName = mapping.logicalId;
}
return Fn._findInMap(mapping.logicalId, value[1], value[2]);
return Fn._findInMap(mappingName, value[1], value[2]);
}
case 'Fn::Select': {
const value = this.parseValue(object[key]);
Expand Down

0 comments on commit 0867b80

Please sign in to comment.