Skip to content

Commit 095da14

Browse files
author
Elad Ben-Israel
authored
fix(toolkit): support multiple toolkit stacks in the same environment (#1427)
The `--toolkit-stack-name` option can be used to specify the name for the toolkit stack. However, since the the toolkit stack outputs had "Export"s, which must be unique within an environment, it was impossible to deploy multiple toolkit stacks. This change removes the "Export"s as they are actually not used or needed and also adds an integration test to verify that multiple toolkit stacks can be deployed into the same environment. `toolkitStackName` can also be specified in `cdk.json` or `~/.cdk.json`. Updated the toolkit documentation topic to describe this. Fixes #1416
1 parent 1dd56d4 commit 095da14

File tree

4 files changed

+64
-16
lines changed

4 files changed

+64
-16
lines changed

docs/src/tools.rst

+23
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,29 @@ Here are the actions you can take on your CDK app
9696
If one of cdk.json or ~/.cdk.json exists, options specified there will be used
9797
as defaults. Settings in cdk.json take precedence.
9898
99+
.. _config-files:
100+
101+
Configuration
102+
=============
103+
104+
The CDK toolkit resolves its configuration by reading files in the following order:
105+
106+
1. ``~/.cdk.json``: user-level configuration file
107+
2. ``cdk.json``: project configuration file
108+
3. Command line arguments
109+
110+
The following options are supported in **cdk.json**:
111+
112+
* ``app`` (string): the command-line to use in order to invoke your CDK app.
113+
* ``browser`` (string): the command to use to open the browser, using %u as a placeholder for the path of the file to open
114+
* ``context`` (hash): key-value pairs of context values which can later be read by ``Construct.getContext(key)``
115+
* ``language`` (string): programming langauge to use for **cdk-init**
116+
* ``pathMetadata`` (boolean): Include "aws:cdk:path" CloudFormation metadata for each resource (enabled by default)
117+
* ``plugin`` (array): Name or path of a node package that extend the CDK features
118+
* ``requireApproval`` (string): what security-sensitive changes need manual approval (choices: "never", "any-change", "broadening")
119+
* ``toolkitStackName`` (string): the name of the CDK toolkit stack
120+
* ``versionReporting`` (boolean): Include the "AWS::CDK::Metadata" resource in synthesized templates
121+
99122
.. _security-changes:
100123
101124
Security-related changes

packages/aws-cdk/bin/cdk.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,15 @@ async function parseCommandLineArguments() {
4646
.option('version-reporting', { type: 'boolean', desc: 'Include the "AWS::CDK::Metadata" resource in synthesized templates (enabled by default)', default: undefined })
4747
.option('path-metadata', { type: 'boolean', desc: 'Include "aws:cdk:path" CloudFormation metadata for each resource (enabled by default)', default: true })
4848
.option('role-arn', { type: 'string', alias: 'r', desc: 'ARN of Role to use when invoking CloudFormation', default: undefined })
49+
.option('toolkit-stack-name', { type: 'string', desc: 'The name of the CDK toolkit stack' })
4950
.command([ 'list', 'ls' ], 'Lists all stacks in the app', yargs => yargs
5051
.option('long', { type: 'boolean', default: false, alias: 'l', desc: 'display environment information for each stack' }))
5152
.command([ 'synthesize [STACKS..]', 'synth [STACKS..]' ], 'Synthesizes and prints the CloudFormation template for this stack', yargs => yargs
5253
.option('interactive', { type: 'boolean', alias: 'i', desc: 'interactively watch and show template updates' })
5354
.option('output', { type: 'string', alias: 'o', desc: 'write CloudFormation template for requested stacks to the given directory' }))
54-
.command('bootstrap [ENVIRONMENTS..]', 'Deploys the CDK toolkit stack into an AWS environment', yargs => yargs
55-
.option('toolkit-stack-name', { type: 'string', desc: 'the name of the CDK toolkit stack' }))
55+
.command('bootstrap [ENVIRONMENTS..]', 'Deploys the CDK toolkit stack into an AWS environment')
5656
.command('deploy [STACKS..]', 'Deploys the stack(s) named STACKS into your AWS account', yargs => yargs
57-
.option('require-approval', { type: 'string', choices: [RequireApproval.Never, RequireApproval.AnyChange, RequireApproval.Broadening], desc: 'what security-sensitive changes need manual approval' })
58-
.option('toolkit-stack-name', { type: 'string', desc: 'the name of the CDK toolkit stack' }))
57+
.option('require-approval', { type: 'string', choices: [RequireApproval.Never, RequireApproval.AnyChange, RequireApproval.Broadening], desc: 'what security-sensitive changes need manual approval' }))
5958
.command('destroy [STACKS..]', 'Destroy the stack(s) named STACKS', yargs => yargs
6059
.option('force', { type: 'boolean', alias: 'f', desc: 'Do not ask for confirmation before destroying the stacks' }))
6160
.command('diff [STACK]', 'Compares the specified stack with the deployed stack or a local template file', yargs => yargs
@@ -144,6 +143,10 @@ async function initCommandLine() {
144143
async function main(command: string, args: any): Promise<number | string | {} | void> {
145144
const toolkitStackName: string = configuration.combined.get(['toolkitStackName']) || DEFAULT_TOOLKIT_STACK_NAME;
146145

146+
if (toolkitStackName !== DEFAULT_TOOLKIT_STACK_NAME) {
147+
print(`Toolkit stack: ${colors.bold(toolkitStackName)}`);
148+
}
149+
147150
args.STACKS = args.STACKS || [];
148151
args.ENVIRONMENTS = args.ENVIRONMENTS || [];
149152

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
scriptdir=$(cd $(dirname $0) && pwd)
4+
source ${scriptdir}/common.bash
5+
# ----------------------------------------------------------
6+
7+
setup
8+
9+
toolkit_stack_name_1="toolkit-stack-1-${RANDOM}"
10+
toolkit_stack_name_2="toolkit-stack-2-${RANDOM}"
11+
12+
# deploy two toolkit stacks into the same environment (see #1416)
13+
cdk bootstrap --toolkit-stack-name ${toolkit_stack_name_1}
14+
cdk bootstrap --toolkit-stack-name ${toolkit_stack_name_2}
15+
16+
# just check that the new stack exists
17+
aws cloudformation describe-stack-resources --stack-name ${toolkit_stack_name_1}
18+
aws cloudformation describe-stack-resources --stack-name ${toolkit_stack_name_2}
19+
20+
# clean up
21+
aws cloudformation delete-stack --stack-name ${toolkit_stack_name_1}
22+
aws cloudformation delete-stack --stack-name ${toolkit_stack_name_2}
23+
24+
echo "✅ success"

packages/aws-cdk/lib/api/bootstrap-environment.ts

+10-12
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,26 @@ export const BUCKET_DOMAIN_NAME_OUTPUT = 'BucketDomainName';
1010
export async function bootstrapEnvironment(environment: Environment, aws: SDK, toolkitStackName: string, roleArn: string | undefined): Promise<DeployStackResult> {
1111
const synthesizedStack: SynthesizedStack = {
1212
environment,
13-
metadata: { },
13+
metadata: {},
1414
template: {
1515
Description: "The CDK Toolkit Stack. It cas created by `cdk bootstrap` and manages resources necessary for managing your Cloud Applications with AWS CDK.",
1616
Resources: {
1717
StagingBucket: {
18-
Type: "AWS::S3::Bucket",
19-
Properties: {
20-
AccessControl: "Private",
21-
BucketEncryption: { ServerSideEncryptionConfiguration: [ { ServerSideEncryptionByDefault: { SSEAlgorithm: "aws:kms" } } ] }
22-
}
18+
Type: "AWS::S3::Bucket",
19+
Properties: {
20+
AccessControl: "Private",
21+
BucketEncryption: { ServerSideEncryptionConfiguration: [{ ServerSideEncryptionByDefault: { SSEAlgorithm: "aws:kms" } }] }
22+
}
2323
}
2424
},
2525
Outputs: {
2626
[BUCKET_NAME_OUTPUT]: {
27-
Description: "The name of the S3 bucket owned by the CDK toolkit stack",
28-
Value: { Ref: "StagingBucket" },
29-
Export: { Name: "CDKToolkit:BucketName" }
27+
Description: "The name of the S3 bucket owned by the CDK toolkit stack",
28+
Value: { Ref: "StagingBucket" }
3029
},
3130
[BUCKET_DOMAIN_NAME_OUTPUT]: {
32-
Description: "The domain name of the S3 bucket owned by the CDK toolkit stack",
33-
Value: { "Fn::GetAtt": [ "StagingBucket", "DomainName" ] },
34-
Export: { Name: "CDKToolkit:BucketDomainName" }
31+
Description: "The domain name of the S3 bucket owned by the CDK toolkit stack",
32+
Value: { "Fn::GetAtt": ["StagingBucket", "DomainName"] }
3533
}
3634
}
3735
},

0 commit comments

Comments
 (0)