Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Parameterize bootstrap stack version #14626

Merged
merged 5 commits into from
Jun 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,15 @@ export interface DefaultStackSynthesizerProps {
* @default - DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PREFIX
*/
readonly bucketPrefix?: string;

/**
* Bootstrap stack version SSM parameter.
*
* The placeholder `${Qualifier}` will be replaced with the value of qualifier.
*
* @default DefaultStackSynthesizer.DEFAULT_BOOTSTRAP_STACK_VERSION_SSM_PARAMETER
*/
readonly bootstrapStackVersionSsmParameter?: string;
}

/**
Expand Down Expand Up @@ -227,6 +236,11 @@ export class DefaultStackSynthesizer extends StackSynthesizer {
*/
public static readonly DEFAULT_FILE_ASSET_PREFIX = '';

/**
* Default bootstrap stack version SSM parameter.
*/
public static readonly DEFAULT_BOOTSTRAP_STACK_VERSION_SSM_PARAMETER = '/cdk-bootstrap/${Qualifier}/version';

private _stack?: Stack;
private bucketName?: string;
private repositoryName?: string;
Expand All @@ -237,6 +251,7 @@ export class DefaultStackSynthesizer extends StackSynthesizer {
private lookupRoleArn?: string;
private qualifier?: string;
private bucketPrefix?: string;
private bootstrapStackVersionSsmParameter?: string;

private readonly files: NonNullable<cxschema.AssetManifest['files']> = {};
private readonly dockerImages: NonNullable<cxschema.AssetManifest['dockerImages']> = {};
Expand Down Expand Up @@ -297,6 +312,11 @@ export class DefaultStackSynthesizer extends StackSynthesizer {
this.imageAssetPublishingRoleArn = specialize(this.props.imageAssetPublishingRoleArn ?? DefaultStackSynthesizer.DEFAULT_IMAGE_ASSET_PUBLISHING_ROLE_ARN);
this.lookupRoleArn = specialize(this.props.lookupRoleArn ?? DefaultStackSynthesizer.DEFAULT_LOOKUP_ROLE_ARN);
this.bucketPrefix = specialize(this.props.bucketPrefix ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PREFIX);
this.bootstrapStackVersionSsmParameter = replaceAll(
this.props.bootstrapStackVersionSsmParameter ?? DefaultStackSynthesizer.DEFAULT_BOOTSTRAP_STACK_VERSION_SSM_PARAMETER,
'${Qualifier}',
qualifier,
);
/* eslint-enable max-len */
}

Expand Down Expand Up @@ -393,7 +413,7 @@ export class DefaultStackSynthesizer extends StackSynthesizer {
// If it's done AFTER _synthesizeTemplate(), then the template won't contain the
// right constructs.
if (this.props.generateBootstrapVersionRule ?? true) {
addBootstrapVersionRule(this.stack, MIN_BOOTSTRAP_STACK_VERSION, this.qualifier);
addBootstrapVersionRule(this.stack, MIN_BOOTSTRAP_STACK_VERSION, <string> this.bootstrapStackVersionSsmParameter);
}

this.synthesizeStackTemplate(this.stack, session);
Expand All @@ -408,7 +428,7 @@ export class DefaultStackSynthesizer extends StackSynthesizer {
cloudFormationExecutionRoleArn: this._cloudFormationExecutionRoleArn,
stackTemplateAssetObjectUrl: templateManifestUrl,
requiresBootstrapStackVersion: MIN_BOOTSTRAP_STACK_VERSION,
bootstrapStackVersionSsmParameter: `/cdk-bootstrap/${this.qualifier}/version`,
bootstrapStackVersionSsmParameter: this.bootstrapStackVersionSsmParameter,
additionalDependencies: [artifactId],
});
}
Expand Down Expand Up @@ -497,7 +517,7 @@ export class DefaultStackSynthesizer extends StackSynthesizer {
properties: {
file: manifestFile,
requiresBootstrapStackVersion: MIN_BOOTSTRAP_STACK_VERSION,
bootstrapStackVersionSsmParameter: `/cdk-bootstrap/${this.qualifier}/version`,
bootstrapStackVersionSsmParameter: this.bootstrapStackVersionSsmParameter,
},
});

Expand Down Expand Up @@ -564,7 +584,7 @@ function stackLocationOrInstrinsics(stack: Stack) {
* The CLI normally checks this, but in a pipeline the CLI is not involved
* so we encode this rule into the template in a way that CloudFormation will check it.
*/
function addBootstrapVersionRule(stack: Stack, requiredVersion: number, qualifier: string) {
function addBootstrapVersionRule(stack: Stack, requiredVersion: number, bootstrapStackVersionSsmParameter: string) {
// Because of https://github.com/aws/aws-cdk/blob/master/packages/assert-internal/lib/synth-utils.ts#L74
// synthesize() may be called more than once on a stack in unit tests, and the below would break
// if we execute it a second time. Guard against the constructs already existing.
Expand All @@ -573,7 +593,7 @@ function addBootstrapVersionRule(stack: Stack, requiredVersion: number, qualifie
const param = new CfnParameter(stack, 'BootstrapVersion', {
type: 'AWS::SSM::Parameter::Value<String>',
description: 'Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store.',
default: `/cdk-bootstrap/${qualifier}/version`,
default: bootstrapStackVersionSsmParameter,
});

// There is no >= check in CloudFormation, so we have to check the number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,33 @@ nodeunitShim({
test.done();
},

'customize version parameter'(test: Test) {
// GIVEN
const myapp = new App();

// WHEN
const mystack = new Stack(myapp, 'mystack', {
synthesizer: new DefaultStackSynthesizer({
bootstrapStackVersionSsmParameter: 'stack-version-parameter',
}),
});

mystack.synthesizer.addFileAsset({
fileName: __filename,
packaging: FileAssetPackaging.FILE,
sourceHash: 'file-asset-hash',
});

// THEN
const asm = myapp.synth();
const manifestArtifact = getAssetManifest(asm);

// THEN - the asset manifest has an SSM parameter entry
expect(manifestArtifact.bootstrapStackVersionSsmParameter).toEqual('stack-version-parameter');

test.done();
},

'generates missing context with the lookup role ARN as one of the missing context properties'(test: Test) {
// GIVEN
stack = new Stack(app, 'Stack2', {
Expand Down Expand Up @@ -246,7 +273,6 @@ nodeunitShim({
test.done();
},


'synthesis with bucketPrefix'(test: Test) {
// GIVEN
const myapp = new App();
Expand Down