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(cli): support CloudFormation simplified resource import #28066

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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 @@ -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');
}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for adding this 👍🏼


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
Expand Down
2 changes: 2 additions & 0 deletions packages/aws-cdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
13 changes: 11 additions & 2 deletions packages/aws-cdk/lib/api/deploy-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -382,7 +389,8 @@ class FullCloudFormationDeployment {
private async changeSetDeployment(deploymentMethod: ChangeSetDeploymentMethod): Promise<DeployStackResult> {
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)) {
Expand All @@ -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}`);
Expand All @@ -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();

Expand Down
1 change: 1 addition & 0 deletions packages/aws-cdk/lib/api/deployments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
10 changes: 7 additions & 3 deletions packages/aws-cdk/lib/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down Expand Up @@ -547,16 +548,19 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
if (args.changeSetName) {
throw new Error('--change-set-name cannot be used with method=direct');
}
if (args.importExistingResources !== undefined) {
throw new Error('--import-existing-resources cannot be used with method=direct');
}
tmokmss marked this conversation as resolved.
Show resolved Hide resolved
deploymentMethod = { method: 'direct' };
break;
case 'change-set':
deploymentMethod = { method: 'change-set', execute: true, changeSetName: args.changeSetName };
deploymentMethod = { method: 'change-set', execute: true, changeSetName: args.changeSetName, importExistingResources: args.importExistingResources };
break;
case 'prepare-change-set':
deploymentMethod = { method: 'change-set', execute: false, changeSetName: args.changeSetName };
deploymentMethod = { method: 'change-set', execute: false, changeSetName: args.changeSetName, importExistingResources: args.importExistingResources };
break;
case undefined:
deploymentMethod = { method: 'change-set', execute: args.execute ?? true, changeSetName: args.changeSetName };
deploymentMethod = { method: 'change-set', execute: args.execute ?? true, changeSetName: args.changeSetName, importExistingResources: args.importExistingResources };
break;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/aws-cdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
16 changes: 16 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading