diff --git a/docs/src/tools.rst b/docs/src/tools.rst index 7b47d30f831c9..4ea63202380f2 100644 --- a/docs/src/tools.rst +++ b/docs/src/tools.rst @@ -96,6 +96,29 @@ Here are the actions you can take on your CDK app If one of cdk.json or ~/.cdk.json exists, options specified there will be used as defaults. Settings in cdk.json take precedence. +.. _config-files: + +Configuration +============= + +The CDK toolkit resolves its configuration by reading files in the following order: + +1. ``~/.cdk.json``: user-level configuration file +2. ``cdk.json``: project configuration file +3. Command line arguments + +The following options are supported in **cdk.json**: + +* ``app`` (string): the command-line to use in order to invoke your CDK app. +* ``browser`` (string): the command to use to open the browser, using %u as a placeholder for the path of the file to open +* ``context`` (hash): key-value pairs of context values which can later be read by ``Construct.getContext(key)`` +* ``language`` (string): programming langauge to use for **cdk-init** +* ``pathMetadata`` (boolean): Include "aws:cdk:path" CloudFormation metadata for each resource (enabled by default) +* ``plugin`` (array): Name or path of a node package that extend the CDK features +* ``requireApproval`` (string): what security-sensitive changes need manual approval (choices: "never", "any-change", "broadening") +* ``toolkitStackName`` (string): the name of the CDK toolkit stack +* ``versionReporting`` (boolean): Include the "AWS::CDK::Metadata" resource in synthesized templates + .. _security-changes: Security-related changes diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index 32de0c5f228c1..3f45103f2cde1 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -46,16 +46,15 @@ async function parseCommandLineArguments() { .option('version-reporting', { type: 'boolean', desc: 'Include the "AWS::CDK::Metadata" resource in synthesized templates (enabled by default)', default: undefined }) .option('path-metadata', { type: 'boolean', desc: 'Include "aws:cdk:path" CloudFormation metadata for each resource (enabled by default)', default: true }) .option('role-arn', { type: 'string', alias: 'r', desc: 'ARN of Role to use when invoking CloudFormation', default: undefined }) + .option('toolkit-stack-name', { type: 'string', desc: 'The name of the CDK toolkit stack' }) .command([ 'list', 'ls' ], 'Lists all stacks in the app', yargs => yargs .option('long', { type: 'boolean', default: false, alias: 'l', desc: 'display environment information for each stack' })) .command([ 'synthesize [STACKS..]', 'synth [STACKS..]' ], 'Synthesizes and prints the CloudFormation template for this stack', yargs => yargs .option('interactive', { type: 'boolean', alias: 'i', desc: 'interactively watch and show template updates' }) .option('output', { type: 'string', alias: 'o', desc: 'write CloudFormation template for requested stacks to the given directory' })) - .command('bootstrap [ENVIRONMENTS..]', 'Deploys the CDK toolkit stack into an AWS environment', yargs => yargs - .option('toolkit-stack-name', { type: 'string', desc: 'the name of the CDK toolkit stack' })) + .command('bootstrap [ENVIRONMENTS..]', 'Deploys the CDK toolkit stack into an AWS environment') .command('deploy [STACKS..]', 'Deploys the stack(s) named STACKS into your AWS account', yargs => yargs - .option('require-approval', { type: 'string', choices: [RequireApproval.Never, RequireApproval.AnyChange, RequireApproval.Broadening], desc: 'what security-sensitive changes need manual approval' }) - .option('toolkit-stack-name', { type: 'string', desc: 'the name of the CDK toolkit stack' })) + .option('require-approval', { type: 'string', choices: [RequireApproval.Never, RequireApproval.AnyChange, RequireApproval.Broadening], desc: 'what security-sensitive changes need manual approval' })) .command('destroy [STACKS..]', 'Destroy the stack(s) named STACKS', yargs => yargs .option('force', { type: 'boolean', alias: 'f', desc: 'Do not ask for confirmation before destroying the stacks' })) .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() { async function main(command: string, args: any): Promise { const toolkitStackName: string = configuration.combined.get(['toolkitStackName']) || DEFAULT_TOOLKIT_STACK_NAME; + if (toolkitStackName !== DEFAULT_TOOLKIT_STACK_NAME) { + print(`Toolkit stack: ${colors.bold(toolkitStackName)}`); + } + args.STACKS = args.STACKS || []; args.ENVIRONMENTS = args.ENVIRONMENTS || []; diff --git a/packages/aws-cdk/integ-tests/test-cdk-multiple-toolkit-stacks.sh b/packages/aws-cdk/integ-tests/test-cdk-multiple-toolkit-stacks.sh new file mode 100755 index 0000000000000..082013b3164b2 --- /dev/null +++ b/packages/aws-cdk/integ-tests/test-cdk-multiple-toolkit-stacks.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -euo pipefail +scriptdir=$(cd $(dirname $0) && pwd) +source ${scriptdir}/common.bash +# ---------------------------------------------------------- + +setup + +toolkit_stack_name_1="toolkit-stack-1-${RANDOM}" +toolkit_stack_name_2="toolkit-stack-2-${RANDOM}" + +# deploy two toolkit stacks into the same environment (see #1416) +cdk bootstrap --toolkit-stack-name ${toolkit_stack_name_1} +cdk bootstrap --toolkit-stack-name ${toolkit_stack_name_2} + +# just check that the new stack exists +aws cloudformation describe-stack-resources --stack-name ${toolkit_stack_name_1} +aws cloudformation describe-stack-resources --stack-name ${toolkit_stack_name_2} + +# clean up +aws cloudformation delete-stack --stack-name ${toolkit_stack_name_1} +aws cloudformation delete-stack --stack-name ${toolkit_stack_name_2} + +echo "✅ success" diff --git a/packages/aws-cdk/lib/api/bootstrap-environment.ts b/packages/aws-cdk/lib/api/bootstrap-environment.ts index 9755769caa4a0..6503c5870aa02 100644 --- a/packages/aws-cdk/lib/api/bootstrap-environment.ts +++ b/packages/aws-cdk/lib/api/bootstrap-environment.ts @@ -10,28 +10,26 @@ export const BUCKET_DOMAIN_NAME_OUTPUT = 'BucketDomainName'; export async function bootstrapEnvironment(environment: Environment, aws: SDK, toolkitStackName: string, roleArn: string | undefined): Promise { const synthesizedStack: SynthesizedStack = { environment, - metadata: { }, + metadata: {}, template: { Description: "The CDK Toolkit Stack. It cas created by `cdk bootstrap` and manages resources necessary for managing your Cloud Applications with AWS CDK.", Resources: { StagingBucket: { - Type: "AWS::S3::Bucket", - Properties: { - AccessControl: "Private", - BucketEncryption: { ServerSideEncryptionConfiguration: [ { ServerSideEncryptionByDefault: { SSEAlgorithm: "aws:kms" } } ] } - } + Type: "AWS::S3::Bucket", + Properties: { + AccessControl: "Private", + BucketEncryption: { ServerSideEncryptionConfiguration: [{ ServerSideEncryptionByDefault: { SSEAlgorithm: "aws:kms" } }] } + } } }, Outputs: { [BUCKET_NAME_OUTPUT]: { - Description: "The name of the S3 bucket owned by the CDK toolkit stack", - Value: { Ref: "StagingBucket" }, - Export: { Name: "CDKToolkit:BucketName" } + Description: "The name of the S3 bucket owned by the CDK toolkit stack", + Value: { Ref: "StagingBucket" } }, [BUCKET_DOMAIN_NAME_OUTPUT]: { - Description: "The domain name of the S3 bucket owned by the CDK toolkit stack", - Value: { "Fn::GetAtt": [ "StagingBucket", "DomainName" ] }, - Export: { Name: "CDKToolkit:BucketDomainName" } + Description: "The domain name of the S3 bucket owned by the CDK toolkit stack", + Value: { "Fn::GetAtt": ["StagingBucket", "DomainName"] } } } },