Skip to content

Commit

Permalink
feat(cdk): treat the "fake" CFN intrinsics (Fn::GetArtifactAtt, Fn::G…
Browse files Browse the repository at this point in the history
…etParam) specially when stringifying JSON. (#1605)

Fn::GetArtifactAtt and Fn::GetParam are not really intrinsics,
they're functions that can be used only in CodePipeline CFN Actions,
in the `parameterOverride` property.

More information: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-parameter-override-functions.html

Fixes #1588
  • Loading branch information
skinny85 authored Jan 23, 2019
1 parent f997fd2 commit 2af2426
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@
"CfnChangeSetRole6F05F6FC",
"Arn"
]
}
},
"ParameterOverrides": "{\"BucketName\":{\"Fn::GetArtifactAtt\":[\"SourceArtifact\",\"BucketName\"]},\"ObjectKey\":{\"Fn::GetArtifactAtt\":[\"SourceArtifact\",\"ObjectKey\"]},\"Url\":{\"Fn::GetArtifactAtt\":[\"SourceArtifact\",\"URL\"]},\"OtherParam\":{\"Fn::GetParam\":[\"SourceArtifact\",\"params.json\",\"OtherParam\"]}}"
},
"InputArtifacts": [
{
Expand Down
6 changes: 6 additions & 0 deletions packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-cfn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ new cfn.PipelineCreateReplaceChangeSetAction(stack, 'DeployCFN', {
role,
templatePath: source.outputArtifact.atPath('test.yaml'),
adminPermissions: false,
parameterOverrides: {
BucketName: source.outputArtifact.bucketName,
ObjectKey: source.outputArtifact.objectKey,
Url: source.outputArtifact.url,
OtherParam: source.outputArtifact.getParam('params.json', 'OtherParam'),
},
});

app.run();
10 changes: 9 additions & 1 deletion packages/@aws-cdk/cdk/lib/cloudformation/instrinsics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,15 @@ export function isIntrinsic(x: any) {
const keys = Object.keys(x);
if (keys.length !== 1) { return false; }

return keys[0] === 'Ref' || keys[0].startsWith('Fn::');
return keys[0] === 'Ref' || isNameOfCloudFormationIntrinsic(keys[0]);
}

export function isNameOfCloudFormationIntrinsic(name: string): boolean {
if (!name.startsWith('Fn::')) {
return false;
}
// these are 'fake' intrinsics, only usable inside the parameter overrides of a CFN CodePipeline Action
return name !== 'Fn::GetArtifactAtt' && name !== 'Fn::GetParam';
}

/**
Expand Down
4 changes: 3 additions & 1 deletion packages/@aws-cdk/cdk/test/cloudformation/evaluate-cfn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*
* Note that this function is not production quality, it exists to support tests.
*/
import { isNameOfCloudFormationIntrinsic } from '../../lib/cloudformation/instrinsics';

export function evaluateCFN(object: any, context: {[key: string]: string} = {}): any {
const intrinsics: any = {
'Fn::Join'(separator: string, args: string[]) {
Expand Down Expand Up @@ -34,7 +36,7 @@ export function evaluateCFN(object: any, context: {[key: string]: string} = {}):

if (typeof obj === 'object') {
const keys = Object.keys(obj);
if (keys.length === 1 && (keys[0].startsWith('Fn::') || keys[0] === 'Ref')) {
if (keys.length === 1 && (isNameOfCloudFormationIntrinsic(keys[0]) || keys[0] === 'Ref')) {
return evaluateIntrinsic(keys[0], obj[keys[0]]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,29 @@ export = {
test.done();
},

'fake intrinsics are serialized to objects'(test: Test) {
const stack = new Stack();
const fakeIntrinsics = new Token(() => ({
a: {
'Fn::GetArtifactAtt': {
key: 'val',
},
},
b: {
'Fn::GetParam': [
'val1',
'val2',
],
},
}));

const stringified = CloudFormationJSON.stringify(fakeIntrinsics, stack);
test.equal(evaluateCFN(stack.node.resolve(stringified)),
'{"a":{"Fn::GetArtifactAtt":{"key":"val"}},"b":{"Fn::GetParam":["val1","val2"]}}');

test.done();
},

'embedded string literals in intrinsics are escaped when calling TokenJSON.stringify()'(test: Test) {
// GIVEN
const stack = new Stack();
Expand Down

0 comments on commit 2af2426

Please sign in to comment.