Skip to content

Commit 623675d

Browse files
authored
fix(cfn-include): allow dynamic mappings to be used in Fn::FindInMap (#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*
1 parent 22b9b3d commit 623675d

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"Parameters": {
3+
"Stage": {
4+
"Type": "String",
5+
"AllowedValues": ["beta"],
6+
"Default": "beta"
7+
}
8+
},
9+
"Mappings": {
10+
"beta": {
11+
"region": {
12+
"key1": "name"
13+
}
14+
}
15+
},
16+
"Resources": {
17+
"Bucket": {
18+
"Type": "AWS::S3::Bucket",
19+
"Properties": {
20+
"BucketName": {
21+
"Fn::FindInMap": [
22+
{ "Ref": "Stage" },
23+
"region",
24+
"key1"
25+
]
26+
}
27+
}
28+
}
29+
}
30+
}

packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,14 @@ describe('CDK Include', () => {
746746
}).toThrow(/Mapping with name 'NonExistentMapping' was not found in the template/);
747747
});
748748

749+
test('can ingest a template that uses Fn::FindInMap with the first argument being a dynamic reference', () => {
750+
includeTestTemplate(stack, 'find-in-map-with-dynamic-mapping.json');
751+
752+
expect(stack).toMatchTemplate(
753+
loadTestFileToJsObject('find-in-map-with-dynamic-mapping.json'),
754+
);
755+
});
756+
749757
test('handles renaming Mapping references', () => {
750758
const cfnTemplate = includeTestTemplate(stack, 'only-mapping-and-bucket.json');
751759
const someMapping = cfnTemplate.getMapping('SomeMapping');

packages/@aws-cdk/core/lib/cfn-parse.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -566,11 +566,19 @@ export class CfnParser {
566566
case 'Fn::FindInMap': {
567567
const value = this.parseValue(object[key]);
568568
// the first argument to FindInMap is the mapping name
569-
const mapping = this.finder.findMapping(value[0]);
570-
if (!mapping) {
571-
throw new Error(`Mapping used in FindInMap expression with name '${value[0]}' was not found in the template`);
569+
let mappingName: string;
570+
if (Token.isUnresolved(value[0])) {
571+
// the first argument can be a dynamic expression like Ref: Param;
572+
// if it is, we can't find the mapping in advance
573+
mappingName = value[0];
574+
} else {
575+
const mapping = this.finder.findMapping(value[0]);
576+
if (!mapping) {
577+
throw new Error(`Mapping used in FindInMap expression with name '${value[0]}' was not found in the template`);
578+
}
579+
mappingName = mapping.logicalId;
572580
}
573-
return Fn._findInMap(mapping.logicalId, value[1], value[2]);
581+
return Fn._findInMap(mappingName, value[1], value[2]);
574582
}
575583
case 'Fn::Select': {
576584
const value = this.parseValue(object[key]);

0 commit comments

Comments
 (0)