From 0f8965f60c40a50f59794d274d8818074f1c070b Mon Sep 17 00:00:00 2001 From: tmokmss Date: Sun, 19 Nov 2023 23:07:54 +0900 Subject: [PATCH 01/15] feat(cli): support ImportExstingResources --- .../tests/cli-integ-tests/cli.integtest.ts | 22 +++++++++++++++++++ packages/aws-cdk/README.md | 2 ++ packages/aws-cdk/lib/api/deploy-stack.ts | 13 +++++++++-- packages/aws-cdk/lib/api/deployments.ts | 1 + packages/aws-cdk/lib/cli.ts | 10 ++++++--- 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index ccdf07b166f33..8cc1e68958dd1 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -280,6 +280,28 @@ integTest('deploy without execute a named change set', withDefaultFixture(async expect(changeSets[0].Status).toEqual('CREATE_COMPLETE'); })); +integTest('deploy with import-existing-resources true', withDefaultFixture(async (fixture) => { + const stackArn = await fixture.cdkDeploy('test-3', { + options: ['--no-execute', '--import-existing-resources', 'true'], + captureStderr: false, + }); + // verify that we only deployed a single stack (there's a single ARN in the output) + expect(stackArn.split('\n').length).toEqual(1); + + const response = await fixture.aws.cloudFormation('describeStacks', { + StackName: stackArn, + }); + expect(response.Stacks?.[0].StackStatus).toEqual('REVIEW_IN_PROGRESS'); + + //verify a change set was successfully + const changeSetResponse = await fixture.aws.cloudFormation('listChangeSets', { + StackName: stackArn, + }); + const changeSets = changeSetResponse.Summaries || []; + expect(changeSets.length).toEqual(1); + expect(changeSets[0].Status).toEqual('CREATE_COMPLETE'); +})); + integTest('security related changes without a CLI are expected to fail', withDefaultFixture(async (fixture) => { // redirect /dev/null to stdin, which means there will not be tty attached // since this stack includes security-related changes, the deployment should diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 864c7de02c968..b926bfeb86570 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -559,6 +559,8 @@ To import an existing resource to a CDK stack, follow the following steps: 5. When `cdk import` reports success, the resource is managed by CDK. Any subsequent changes in the construct configuration will be reflected on the resource. +You can also import existing resources by `--import-existing-resources` option of `cdk deploy` command. This parameter only works for resources that you can set custom physical names, such as S3 bucket, DynamoDB table, etc. For more information, see [`ImportResourceResources` parameter](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_CreateChangeSet.html#API_CreateChangeSet_RequestParameters) in AWS CloudFormation API reference. + #### Limitations This feature currently has the following limitations: diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index 9ae5ac4e65000..6af0af9f4a1b1 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -231,6 +231,13 @@ export interface ChangeSetDeploymentMethod { * If not provided, a name will be generated automatically. */ readonly changeSetName?: string; + + /** + * Indicates if the stack set imports resources that already exist. + * + * @default false + */ + readonly importExistingResources?: boolean; } const LARGE_TEMPLATE_SIZE_KB = 50; @@ -382,7 +389,8 @@ class FullCloudFormationDeployment { private async changeSetDeployment(deploymentMethod: ChangeSetDeploymentMethod): Promise { const changeSetName = deploymentMethod.changeSetName ?? 'cdk-deploy-change-set'; const execute = deploymentMethod.execute ?? true; - const changeSetDescription = await this.createChangeSet(changeSetName, execute); + const importExistingResources = deploymentMethod.importExistingResources ?? false; + const changeSetDescription = await this.createChangeSet(changeSetName, execute, importExistingResources); await this.updateTerminationProtection(); if (changeSetHasNoChanges(changeSetDescription)) { @@ -402,7 +410,7 @@ class FullCloudFormationDeployment { return this.executeChangeSet(changeSetDescription); } - private async createChangeSet(changeSetName: string, willExecute: boolean) { + private async createChangeSet(changeSetName: string, willExecute: boolean, importExistingResources: boolean) { await this.cleanupOldChangeset(changeSetName); debug(`Attempting to create ChangeSet with name ${changeSetName} to ${this.verb} stack ${this.stackName}`); @@ -414,6 +422,7 @@ class FullCloudFormationDeployment { ResourcesToImport: this.options.resourcesToImport, Description: `CDK Changeset for execution ${this.uuid}`, ClientToken: `create${this.uuid}`, + ImportExistingResources: importExistingResources, ...this.commonPrepareOptions(), }).promise(); diff --git a/packages/aws-cdk/lib/api/deployments.ts b/packages/aws-cdk/lib/api/deployments.ts index e6c2254c70ebb..266019b6323c9 100644 --- a/packages/aws-cdk/lib/api/deployments.ts +++ b/packages/aws-cdk/lib/api/deployments.ts @@ -357,6 +357,7 @@ export class Deployments { if (deploymentMethod) { throw new Error('You cannot supply both \'deploymentMethod\' and \'changeSetName/execute\'. Supply one or the other.'); } + // actually, deploymentMethod should not be undefined here deploymentMethod = { method: 'change-set', changeSetName: options.changeSetName, diff --git a/packages/aws-cdk/lib/cli.ts b/packages/aws-cdk/lib/cli.ts index 85e3bdaaf4996..dadb1bf287782 100644 --- a/packages/aws-cdk/lib/cli.ts +++ b/packages/aws-cdk/lib/cli.ts @@ -130,6 +130,7 @@ async function parseCommandLineArguments(args: string[]) { requiresArg: true, desc: 'How to perform the deployment. Direct is a bit faster but lacks progress information', }) + .option('import-existing-resources', { type: 'boolean', desc: 'Indicates if the stack set imports resources that already exist.', default: false }) .option('force', { alias: 'f', type: 'boolean', desc: 'Always deploy stack even if templates are identical', default: false }) .option('parameters', { type: 'array', desc: 'Additional parameters passed to CloudFormation at deploy time (STACK:KEY=VALUE)', nargs: 1, requiresArg: true, default: {} }) .option('outputs-file', { type: 'string', alias: 'O', desc: 'Path to file where stack outputs will be written as JSON', requiresArg: true }) @@ -547,16 +548,19 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise Date: Sun, 19 Nov 2023 23:59:11 +0900 Subject: [PATCH 02/15] update aws-sdk, but I'm not sure if it's allowed maybe revert later --- packages/aws-cdk/package.json | 2 +- yarn.lock | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index ee7b47080e881..12afbcd163482 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -102,7 +102,7 @@ "@aws-cdk/region-info": "0.0.0", "@jsii/check-node": "1.92.0", "archiver": "^5.3.2", - "aws-sdk": "^2.1498.0", + "aws-sdk": "^2.1499.0", "camelcase": "^6.3.0", "cdk-assets": "0.0.0", "cdk-from-cfn": "^0.69.0", diff --git a/yarn.lock b/yarn.lock index 7aa5486facbd9..185b85066c5a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5821,6 +5821,22 @@ aws-sdk@^2.1231.0, aws-sdk@^2.1492.0, aws-sdk@^2.1498.0, aws-sdk@^2.928.0: uuid "8.0.0" xml2js "0.5.0" +aws-sdk@^2.1499.0: + version "2.1499.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1499.0.tgz#d6af6d068c26f31687fa88f582ee6fa0be4e4323" + integrity sha512-kh89lcXx7lP83uVjzRPkOueRoM8gQlep86W9+l3qCTHSLiVJuc0MiPmqCLMPlOAZil+35roFkwWIP2FJ1WcdXg== + dependencies: + buffer "4.9.2" + events "1.1.1" + ieee754 "1.1.13" + jmespath "0.16.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + util "^0.12.4" + uuid "8.0.0" + xml2js "0.5.0" + axios@^0.27.2: version "0.27.2" resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" From ca9cd2571a1dff6936d69a51565634beb7cc2d55 Mon Sep 17 00:00:00 2001 From: tmokmss Date: Mon, 20 Nov 2023 00:10:01 +0900 Subject: [PATCH 03/15] Update cli.integtest.ts --- .../cli-integ/tests/cli-integ-tests/cli.integtest.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index 8cc1e68958dd1..da4de046f38ee 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -293,7 +293,8 @@ integTest('deploy with import-existing-resources true', withDefaultFixture(async }); expect(response.Stacks?.[0].StackStatus).toEqual('REVIEW_IN_PROGRESS'); - //verify a change set was successfully + // verify a change set was successfully created + // Here, we do not test whether a resource is actually imported, because that is a CloudFormation feature, not a CDK feature. const changeSetResponse = await fixture.aws.cloudFormation('listChangeSets', { StackName: stackArn, }); From e803106ca8f997b32b42afd62481e13be994c9fd Mon Sep 17 00:00:00 2001 From: tmokmss Date: Mon, 20 Nov 2023 09:32:48 +0900 Subject: [PATCH 04/15] fix integ --- .../cli-integ/tests/cli-integ-tests/cli.integtest.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index da4de046f38ee..57321c4c6d158 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -281,7 +281,7 @@ integTest('deploy without execute a named change set', withDefaultFixture(async })); integTest('deploy with import-existing-resources true', withDefaultFixture(async (fixture) => { - const stackArn = await fixture.cdkDeploy('test-3', { + const stackArn = await fixture.cdkDeploy('test-2', { options: ['--no-execute', '--import-existing-resources', 'true'], captureStderr: false, }); @@ -301,6 +301,7 @@ integTest('deploy with import-existing-resources true', withDefaultFixture(async const changeSets = changeSetResponse.Summaries || []; expect(changeSets.length).toEqual(1); expect(changeSets[0].Status).toEqual('CREATE_COMPLETE'); + expect(changeSets[0].ImportExistingResources).toEqual(true); })); integTest('security related changes without a CLI are expected to fail', withDefaultFixture(async (fixture) => { From a2fa8b429d7d1a16ef331faf3f0428df08d0fd05 Mon Sep 17 00:00:00 2001 From: tmokmss Date: Mon, 20 Nov 2023 09:32:56 +0900 Subject: [PATCH 05/15] also update aws-sdk --- packages/@aws-cdk-testing/cli-integ/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk-testing/cli-integ/package.json b/packages/@aws-cdk-testing/cli-integ/package.json index b16031931890e..d228f0f4363e1 100644 --- a/packages/@aws-cdk-testing/cli-integ/package.json +++ b/packages/@aws-cdk-testing/cli-integ/package.json @@ -39,7 +39,7 @@ }, "dependencies": { "@octokit/rest": "^18.12.0", - "aws-sdk": "^2.1498.0", + "aws-sdk": "^2.1499.0", "axios": "^1.6.2", "fs-extra": "^9.1.0", "glob": "^7.2.3", From d66b937600dfe825838ce4cba7c9db519e2fabe8 Mon Sep 17 00:00:00 2001 From: tmokmss Date: Mon, 20 Nov 2023 14:03:28 +0900 Subject: [PATCH 06/15] Update deployments.ts --- packages/aws-cdk/lib/api/deployments.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/aws-cdk/lib/api/deployments.ts b/packages/aws-cdk/lib/api/deployments.ts index 266019b6323c9..e6c2254c70ebb 100644 --- a/packages/aws-cdk/lib/api/deployments.ts +++ b/packages/aws-cdk/lib/api/deployments.ts @@ -357,7 +357,6 @@ export class Deployments { if (deploymentMethod) { throw new Error('You cannot supply both \'deploymentMethod\' and \'changeSetName/execute\'. Supply one or the other.'); } - // actually, deploymentMethod should not be undefined here deploymentMethod = { method: 'change-set', changeSetName: options.changeSetName, From 7e04e542ac37f2002ce96333415017ab93bd733c Mon Sep 17 00:00:00 2001 From: tmokmss Date: Mon, 20 Nov 2023 14:19:57 +0900 Subject: [PATCH 07/15] possible refactor to remove dead code --- packages/aws-cdk/lib/api/deployments.ts | 30 +------------------------ packages/aws-cdk/lib/cdk-toolkit.ts | 2 -- packages/aws-cdk/lib/cli.ts | 4 ++-- 3 files changed, 3 insertions(+), 33 deletions(-) diff --git a/packages/aws-cdk/lib/api/deployments.ts b/packages/aws-cdk/lib/api/deployments.ts index e6c2254c70ebb..613776db68d81 100644 --- a/packages/aws-cdk/lib/api/deployments.ts +++ b/packages/aws-cdk/lib/api/deployments.ts @@ -98,22 +98,6 @@ export interface DeployStackOptions { */ readonly tags?: Tag[]; - /** - * Stage the change set but don't execute it - * - * @default - true - * @deprecated Use 'deploymentMethod' instead - */ - readonly execute?: boolean; - - /** - * Optional name to use for the CloudFormation change set. - * If not provided, a name will be generated automatically. - * - * @deprecated Use 'deploymentMethod' instead - */ - readonly changeSetName?: string; - /** * Select the deployment method (direct or using a change set) * @@ -352,18 +336,6 @@ export class Deployments { } public async deployStack(options: DeployStackOptions): Promise { - let deploymentMethod = options.deploymentMethod; - if (options.changeSetName || options.execute !== undefined) { - if (deploymentMethod) { - throw new Error('You cannot supply both \'deploymentMethod\' and \'changeSetName/execute\'. Supply one or the other.'); - } - deploymentMethod = { - method: 'change-set', - changeSetName: options.changeSetName, - execute: options.execute, - }; - } - const { stackSdk, resolvedEnvironment, @@ -390,7 +362,7 @@ export class Deployments { reuseAssets: options.reuseAssets, envResources, tags: options.tags, - deploymentMethod, + deploymentMethod: options.deploymentMethod, force: options.force, parameters: options.parameters, usePreviousParameters: options.usePreviousParameters, diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index d2faab3a274c9..3f8832407480c 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -293,8 +293,6 @@ export class CdkToolkit { reuseAssets: options.reuseAssets, notificationArns: options.notificationArns, tags, - execute: options.execute, - changeSetName: options.changeSetName, deploymentMethod: options.deploymentMethod, force: options.force, parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]), diff --git a/packages/aws-cdk/lib/cli.ts b/packages/aws-cdk/lib/cli.ts index dadb1bf287782..020367c7513a7 100644 --- a/packages/aws-cdk/lib/cli.ts +++ b/packages/aws-cdk/lib/cli.ts @@ -542,7 +542,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise Date: Mon, 20 Nov 2023 14:20:21 +0900 Subject: [PATCH 08/15] revert refactor; might do this in another PR --- packages/aws-cdk/lib/api/deployments.ts | 30 ++++++++++++++++++++++++- packages/aws-cdk/lib/cdk-toolkit.ts | 2 ++ packages/aws-cdk/lib/cli.ts | 4 ++-- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/packages/aws-cdk/lib/api/deployments.ts b/packages/aws-cdk/lib/api/deployments.ts index 613776db68d81..e6c2254c70ebb 100644 --- a/packages/aws-cdk/lib/api/deployments.ts +++ b/packages/aws-cdk/lib/api/deployments.ts @@ -98,6 +98,22 @@ export interface DeployStackOptions { */ readonly tags?: Tag[]; + /** + * Stage the change set but don't execute it + * + * @default - true + * @deprecated Use 'deploymentMethod' instead + */ + readonly execute?: boolean; + + /** + * Optional name to use for the CloudFormation change set. + * If not provided, a name will be generated automatically. + * + * @deprecated Use 'deploymentMethod' instead + */ + readonly changeSetName?: string; + /** * Select the deployment method (direct or using a change set) * @@ -336,6 +352,18 @@ export class Deployments { } public async deployStack(options: DeployStackOptions): Promise { + let deploymentMethod = options.deploymentMethod; + if (options.changeSetName || options.execute !== undefined) { + if (deploymentMethod) { + throw new Error('You cannot supply both \'deploymentMethod\' and \'changeSetName/execute\'. Supply one or the other.'); + } + deploymentMethod = { + method: 'change-set', + changeSetName: options.changeSetName, + execute: options.execute, + }; + } + const { stackSdk, resolvedEnvironment, @@ -362,7 +390,7 @@ export class Deployments { reuseAssets: options.reuseAssets, envResources, tags: options.tags, - deploymentMethod: options.deploymentMethod, + deploymentMethod, force: options.force, parameters: options.parameters, usePreviousParameters: options.usePreviousParameters, diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index 3f8832407480c..d2faab3a274c9 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -293,6 +293,8 @@ export class CdkToolkit { reuseAssets: options.reuseAssets, notificationArns: options.notificationArns, tags, + execute: options.execute, + changeSetName: options.changeSetName, deploymentMethod: options.deploymentMethod, force: options.force, parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]), diff --git a/packages/aws-cdk/lib/cli.ts b/packages/aws-cdk/lib/cli.ts index 020367c7513a7..dadb1bf287782 100644 --- a/packages/aws-cdk/lib/cli.ts +++ b/packages/aws-cdk/lib/cli.ts @@ -542,7 +542,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise Date: Thu, 7 Dec 2023 09:59:50 +0900 Subject: [PATCH 09/15] Update yarn.lock --- yarn.lock | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8046d822799ef..618912028d629 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5815,22 +5815,6 @@ aws-sdk@^2.1231.0, aws-sdk@^2.1513.0, aws-sdk@^2.928.0: uuid "8.0.0" xml2js "0.5.0" -aws-sdk@^2.1499.0: - version "2.1499.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1499.0.tgz#d6af6d068c26f31687fa88f582ee6fa0be4e4323" - integrity sha512-kh89lcXx7lP83uVjzRPkOueRoM8gQlep86W9+l3qCTHSLiVJuc0MiPmqCLMPlOAZil+35roFkwWIP2FJ1WcdXg== - dependencies: - buffer "4.9.2" - events "1.1.1" - ieee754 "1.1.13" - jmespath "0.16.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - util "^0.12.4" - uuid "8.0.0" - xml2js "0.5.0" - axios@^0.27.2: version "0.27.2" resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" From 2a6aae5c011521f63917c1b1f34121ab85348cc7 Mon Sep 17 00:00:00 2001 From: tmokmss Date: Wed, 13 Dec 2023 10:58:09 +0900 Subject: [PATCH 10/15] Update README.md --- packages/aws-cdk/README.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index b926bfeb86570..425d53cf98a90 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -382,6 +382,29 @@ $ cdk deploy --method=prepare-change-set --change-set-name MyChangeSetName For more control over when stack changes are deployed, the CDK can generate a CloudFormation change set but not execute it. +#### Import existing resources +You can pass the `--import-existing-resources` flag to the `deploy` command: + +```console +$ cdk deploy --import-existing-resources +``` + +This allows you to automatically import the resources in your template that already exist in your AWS account during CloudFormation deployments. With this feature, you can reduce the manual effort of import operations and avoid deployment failures because of naming conflicts. + +To review which resources are imported or not before actually executing a change set, use `--method=prepare-change-set` flag. You can inspect the change set created by CDK from the management console or other external tools. + +```console +$ cdk deploy --import-existing-resources --method=prepare-change-set +``` + +To enable this feature only for a specific stack, use `--exclusively` flag. + +```console +$ cdk deploy --import-existing-resources --exclusively StackName +``` + +This parameter can only import resources that have custom names in templates. For more information, see [name type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-name.html) in the AWS CloudFormation User Guide. To import resources that do not accept custom names, such as EC2 instances, use the `cdk import` instead. You can find more details [here](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_CreateChangeSet.html#API_CreateChangeSet_RequestParameters). + #### Hotswap deployments for faster development You can pass the `--hotswap` flag to the `deploy` command: @@ -559,7 +582,7 @@ To import an existing resource to a CDK stack, follow the following steps: 5. When `cdk import` reports success, the resource is managed by CDK. Any subsequent changes in the construct configuration will be reflected on the resource. -You can also import existing resources by `--import-existing-resources` option of `cdk deploy` command. This parameter only works for resources that you can set custom physical names, such as S3 bucket, DynamoDB table, etc. For more information, see [`ImportResourceResources` parameter](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_CreateChangeSet.html#API_CreateChangeSet_RequestParameters) in AWS CloudFormation API reference. +NOTE: You can also import existing resources by `--import-existing-resources` option of `cdk deploy` command. This parameter only works for resources that you can set custom physical names, such as S3 bucket, DynamoDB table, etc. For more information, see [`ImportResourceResources` parameter](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_CreateChangeSet.html#API_CreateChangeSet_RequestParameters) in AWS CloudFormation API reference. #### Limitations From 07fa30640cbf47127653ec9ab57e0ee35d2e995a Mon Sep 17 00:00:00 2001 From: tmokmss Date: Wed, 13 Dec 2023 11:15:39 +0900 Subject: [PATCH 11/15] Update cli.integtest.ts --- .../tests/cli-integ-tests/cli.integtest.ts | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index 57321c4c6d158..b6b6b451b99fe 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -282,7 +282,7 @@ integTest('deploy without execute a named change set', withDefaultFixture(async integTest('deploy with import-existing-resources true', withDefaultFixture(async (fixture) => { const stackArn = await fixture.cdkDeploy('test-2', { - options: ['--no-execute', '--import-existing-resources', 'true'], + options: ['--no-execute', '--import-existing-resources'], captureStderr: false, }); // verify that we only deployed a single stack (there's a single ARN in the output) @@ -304,6 +304,29 @@ integTest('deploy with import-existing-resources true', withDefaultFixture(async expect(changeSets[0].ImportExistingResources).toEqual(true); })); +integTest('deploy without import-existing-resources', withDefaultFixture(async (fixture) => { + const stackArn = await fixture.cdkDeploy('test-2', { + options: ['--no-execute'], + captureStderr: false, + }); + // verify that we only deployed a single stack (there's a single ARN in the output) + expect(stackArn.split('\n').length).toEqual(1); + + const response = await fixture.aws.cloudFormation('describeStacks', { + StackName: stackArn, + }); + expect(response.Stacks?.[0].StackStatus).toEqual('REVIEW_IN_PROGRESS'); + + // verify a change set was successfully created and ImportExistingResources = false + const changeSetResponse = await fixture.aws.cloudFormation('listChangeSets', { + StackName: stackArn, + }); + const changeSets = changeSetResponse.Summaries || []; + expect(changeSets.length).toEqual(1); + expect(changeSets[0].Status).toEqual('CREATE_COMPLETE'); + expect(changeSets[0].ImportExistingResources).toEqual(false); +})); + integTest('security related changes without a CLI are expected to fail', withDefaultFixture(async (fixture) => { // redirect /dev/null to stdin, which means there will not be tty attached // since this stack includes security-related changes, the deployment should From 526daedb87e135d7e6f9c9a8ecbae251f3e30c0d Mon Sep 17 00:00:00 2001 From: tmokmss Date: Wed, 13 Dec 2023 11:19:34 +0900 Subject: [PATCH 12/15] Update README.md --- packages/aws-cdk/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 425d53cf98a90..c32c1c86c5c8d 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -383,6 +383,7 @@ For more control over when stack changes are deployed, the CDK can generate a CloudFormation change set but not execute it. #### Import existing resources + You can pass the `--import-existing-resources` flag to the `deploy` command: ```console From d5f41e68d0c0a31ed6d20180526e7c3a3da5744f Mon Sep 17 00:00:00 2001 From: tmokmss Date: Wed, 13 Dec 2023 12:00:28 +0900 Subject: [PATCH 13/15] Update deploy-stack.test.ts --- .../aws-cdk/test/api/deploy-stack.test.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/aws-cdk/test/api/deploy-stack.test.ts b/packages/aws-cdk/test/api/deploy-stack.test.ts index 440d95cbff8b2..b3f7deade3a5f 100644 --- a/packages/aws-cdk/test/api/deploy-stack.test.ts +++ b/packages/aws-cdk/test/api/deploy-stack.test.ts @@ -861,6 +861,41 @@ describe('disable rollback', () => { }); +describe('import-existing-resources', () => { + test('by default, ', async () => { + // WHEN + await deployStack({ + ...standardDeployStackArguments(), + deploymentMethod: { + method: 'change-set', + }, + }); + + // THEN + expect(cfnMocks.createChangeSet).toHaveBeenCalledTimes(1); + expect(cfnMocks.createChangeSet).toHaveBeenCalledWith(expect.objectContaining({ + ImportExistingResources: false, + })); + }); + + test('enabled', async () => { + // WHEN + await deployStack({ + ...standardDeployStackArguments(), + deploymentMethod: { + method: 'change-set', + importExistingResources: true, + }, + }); + + // THEN + expect(cfnMocks.createChangeSet).toHaveBeenCalledTimes(1); + expect(cfnMocks.createChangeSet).toHaveBeenCalledWith(expect.objectContaining({ + ImportExistingResources: true, + })); + }); +}); + /** * Set up the mocks so that it looks like the stack exists to start with * From 2abaeba55ef0c1f77b3270fa513a6e5ff92aa8ac Mon Sep 17 00:00:00 2001 From: tmokmss Date: Wed, 13 Dec 2023 12:01:25 +0900 Subject: [PATCH 14/15] Update deploy-stack.test.ts --- packages/aws-cdk/test/api/deploy-stack.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/test/api/deploy-stack.test.ts b/packages/aws-cdk/test/api/deploy-stack.test.ts index b3f7deade3a5f..b03cabe87ef6f 100644 --- a/packages/aws-cdk/test/api/deploy-stack.test.ts +++ b/packages/aws-cdk/test/api/deploy-stack.test.ts @@ -862,7 +862,7 @@ describe('disable rollback', () => { }); describe('import-existing-resources', () => { - test('by default, ', async () => { + test('by default, import-existing-resources is disabled', async () => { // WHEN await deployStack({ ...standardDeployStackArguments(), @@ -878,7 +878,7 @@ describe('import-existing-resources', () => { })); }); - test('enabled', async () => { + test('import-existing-resources is enabled', async () => { // WHEN await deployStack({ ...standardDeployStackArguments(), From 3cc542d751e583a8fe186cc85d9b8d088a3ca268 Mon Sep 17 00:00:00 2001 From: tmokmss Date: Thu, 14 Dec 2023 10:52:31 +0900 Subject: [PATCH 15/15] reject only when method=direct && importExistingResources==true --- .../cli-integ/tests/cli-integ-tests/cli.integtest.ts | 12 ++++++++++++ packages/aws-cdk/lib/cli.ts | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index b6b6b451b99fe..6b2e06157a904 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -327,6 +327,18 @@ integTest('deploy without import-existing-resources', withDefaultFixture(async ( expect(changeSets[0].ImportExistingResources).toEqual(false); })); +integTest('deploy with method=direct and import-existing-resources fails', withDefaultFixture(async (fixture) => { + const stackName = 'iam-test'; + await expect(fixture.cdkDeploy(stackName, { + options: ['--import-existing-resources', '--method=direct'], + })).rejects.toThrow('exited with error'); + + // Ensure stack was not deployed + await expect(fixture.aws.cloudFormation('describeStacks', { + StackName: fixture.fullStackName(stackName), + })).rejects.toThrow('does not exist'); +})); + integTest('security related changes without a CLI are expected to fail', withDefaultFixture(async (fixture) => { // redirect /dev/null to stdin, which means there will not be tty attached // since this stack includes security-related changes, the deployment should diff --git a/packages/aws-cdk/lib/cli.ts b/packages/aws-cdk/lib/cli.ts index dadb1bf287782..0455ab598893d 100644 --- a/packages/aws-cdk/lib/cli.ts +++ b/packages/aws-cdk/lib/cli.ts @@ -548,8 +548,8 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise