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

fix(cli): cdk destroy does not throw error for a non-existent stack #27293

Closed
wants to merge 10 commits into from
10 changes: 9 additions & 1 deletion packages/aws-cdk/lib/cdk-toolkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import * as cxapi from '@aws-cdk/cx-api';
import * as chalk from 'chalk';
import * as chokidar from 'chokidar';
import * as fs from 'fs-extra';
import { minimatch } from 'minimatch';
import * as promptly from 'promptly';
import * as semver from 'semver';
import { DeploymentMethod } from './api';
import { SdkProvider } from './api/aws-auth';
import { Bootstrapper, BootstrapEnvironmentOptions } from './api/bootstrap';
Expand All @@ -26,6 +28,7 @@ import { validateSnsTopicArn } from './util/validate-notification-arn';
import { Concurrency, WorkGraph } from './util/work-graph';
import { WorkGraphBuilder } from './util/work-graph-builder';
import { AssetBuildNode, AssetPublishNode, StackNode } from './util/work-graph-types';
import { versionNumber } from './version';
import { environmentsFromDescriptors, globEnvironmentsFromStacks, looksLikeGlob } from '../lib/api/cxapp/environments';

export interface CdkToolkitProps {
Expand Down Expand Up @@ -769,7 +772,12 @@ export class CdkToolkit {
defaultBehavior: DefaultSelection.OnlySingle,
});

// No validation
const notExistPatterns = selector.patterns.filter(pattern => !stacks.stackArtifacts.find(stack =>
minimatch(stack.hierarchicalId, pattern) || (stack.id === pattern && semver.major(versionNumber()) < 2),
));
if (notExistPatterns.length > 0) {
throw new Error(`Stacks not exist: ${notExistPatterns.join(', ')}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please change the error message to be something more informative as to what does not exist and how they might be able to fix it?

Copy link
Contributor Author

@go-to-k go-to-k Oct 12, 2023

Choose a reason for hiding this comment

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

@SankyRed

For example, if you specify stacks stack-A, stack-X, and stack-Y in cdk destroy, and only stack-A exists in your app.

In this code, the error message is to be following, Stacks not exist: stack-X, stack-Y. So you can know which of stacks do not exist.

how they might be able to fix it?

I think it is to difficult to know this. If you enter non-existent stacks, CDK does not know the way how to fix it unless it gets all the stacks and does a fuzzy search on all of them. Even if we did that, you probably wouldn't get the expected and accurate output.

Copy link
Contributor

Choose a reason for hiding this comment

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

A tad more context here might be helpful, if we can provide it. Maybe something like Cannot run cdk destroy on stack(s) ${stacks.join(', ')}. ${notExistPatterns.join(', ')} are not deployed in account: ${account}, region: ${region}.

Copy link
Contributor Author

@go-to-k go-to-k Oct 22, 2023

Choose a reason for hiding this comment

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

@TheRealAmazonKendra

A tad more context here might be helpful, if we can provide it. Maybe something like Cannot run cdk destroy on stack(s) ${stacks.join(', ')}. ${notExistPatterns.join(', ')} are not deployed in account: ${account}, region: ${region}.

I think the format is difficult.

This notExistPattern handling and cdk destroy check the non-existence stacks by looking not the AWS account but stack instance definitions in the cdk app (that is cloud-assembly).

My understanding is that cdk destroy does not run the command by specifying an account or region, but looks at the stack list (CloudFormationStackArtifact[]) in cloud-assembly and if each stack has a region/account, it is used; otherwise, the default region/account is used. Actually there is no --region option in cdk destroy.

So we can see that the stack entered does not exist in the CDK app in the first place, but we cannot know WHICH account/region it does not exist in. (We may know that "the stack does not exist in the DEFAULT or ANY region and account", but perhaps that is not the information the user wants to know.)

Then, how about the following message?:

Cannot run cdk destroy on stack(s) ${stacks.join(', ')}. ${notExistPatterns.join(', ')} not exist.

}

return stacks;
}
Expand Down
13 changes: 13 additions & 0 deletions packages/aws-cdk/test/cdk-toolkit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,19 @@ describe('destroy', () => {
});
}).resolves;
});

test('fail on non-existent stack', async () => {
const toolkit = defaultToolkitSetup();

await expect(() => {
return toolkit.destroy({
selector: { patterns: ['Test-Stack-A/Test-Stack-C', 'Test-Stack-X', 'Test-Stack-Y'] },
exclusively: true,
force: true,
fromDeploy: true,
});
}).rejects.toThrowError('Stacks not exist: Test-Stack-X, Test-Stack-Y');
});
});

describe('watch', () => {
Expand Down
Loading