Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion packages/@aws-cdk/toolkit-lib/lib/api/refactoring/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface RefactoringContextOptions {
overrides?: ResourceMapping[];
assumeRoleArn?: string;
ignoreModifications?: boolean;
toolkitStackName?: string;
}

/**
Expand All @@ -38,6 +39,7 @@ export class RefactoringContext {
private readonly ambiguousMoves: ResourceMove[] = [];
private readonly localStacks: CloudFormationStack[];
private readonly assumeRoleArn?: string;
private readonly toolkitStackName?: string;
public readonly environment: Environment;

constructor(props: RefactoringContextOptions) {
Expand All @@ -49,6 +51,7 @@ export class RefactoringContext {
this.ambiguousMoves = ambiguousMoves;
this.localStacks = props.localStacks;
this.assumeRoleArn = props.assumeRoleArn;
this.toolkitStackName = props.toolkitStackName;

this._mappings = resourceMappings(nonAmbiguousMoves);
}
Expand Down Expand Up @@ -102,7 +105,7 @@ export class RefactoringContext {
}

private async checkBootstrapVersion(sdk: SDK, ioHelper: IoHelper) {
const environmentResourcesRegistry = new EnvironmentResourcesRegistry();
const environmentResourcesRegistry = new EnvironmentResourcesRegistry(this.toolkitStackName);
const envResources = environmentResourcesRegistry.for(this.environment, sdk, ioHelper);
let bootstrapVersion: number | undefined = undefined;
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as util from 'node:util';
import type { Environment } from '@aws-cdk/cx-api';
import type { Environment } from '@aws-cdk/cloud-assembly-api';
import type { StackDefinition } from '@aws-sdk/client-cloudformation';
import chalk from 'chalk';
import type { CloudFormationStack, ResourceMapping } from './cloudformation';
Expand All @@ -23,6 +23,7 @@ export async function generateStackDefinitions(
environment: Environment,
sdkProvider: SdkProvider,
ioHelper: IoHelper,
toolkitStackName?: string,
): Promise<StackDefinition[]> {
const deployedStackMap: Map<string, CloudFormationStack> = new Map(deployedStacks.map((s) => [s.stackName, s]));

Expand Down Expand Up @@ -96,7 +97,7 @@ export async function generateStackDefinitions(
}

const sdk = (await sdkProvider.forEnvironment(environment, Mode.ForWriting)).sdk;
const environmentResourcesRegistry = new EnvironmentResourcesRegistry();
const environmentResourcesRegistry = new EnvironmentResourcesRegistry(toolkitStackName);
const envResources = environmentResourcesRegistry.for(environment, sdk, ioHelper);
const toolkitInfo = await envResources.lookupToolkit();

Expand Down
11 changes: 10 additions & 1 deletion packages/@aws-cdk/toolkit-lib/lib/toolkit/toolkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,7 @@ export class Toolkit extends CloudAssemblySourceBuilder {
localStacks,
assumeRoleArn: options.roleArn,
overrides: getOverrides(environment, deployedStacks, localStacks),
toolkitStackName: this.toolkitStackName,
});

const mappings = context.mappings;
Expand All @@ -1637,7 +1638,15 @@ export class Toolkit extends CloudAssemblySourceBuilder {
let refactorMessage = formatTypedMappings(typedMappings);
const refactorResult: RefactorResult = { typedMappings };

const stackDefinitions = await generateStackDefinitions(mappings, deployedStacks, localStacks, environment, sdkProvider, ioHelper);
const stackDefinitions = await generateStackDefinitions(
mappings,
deployedStacks,
localStacks,
environment,
sdkProvider,
ioHelper,
this.toolkitStackName,
);

if (context.ambiguousPaths.length > 0) {
const paths = context.ambiguousPaths;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1659,4 +1659,103 @@ describe(generateStackDefinitions, () => {
const templateSize = JSON.stringify(smallResources).length;
expect(templateSize).toBeLessThan(50 * 1024);
});

test('looks up the toolkit stack under the given custom name', async () => {
const largeResources: any = {};
for (let i = 0; i < 500; i++) {
largeResources[`Bucket${i}`] = {
Type: 'AWS::S3::Bucket',
Properties: {
BucketName: `my-bucket-${i}`,
Tags: [
{ Key: 'Environment', Value: 'Production' },
{ Key: 'Application', Value: 'MyApp' },
{ Key: 'Owner', Value: 'TeamA' },
{ Key: 'CostCenter', Value: '12345' },
],
},
};
}

const deployedStack: CloudFormationStack = {
environment,
stackName: 'Stack1',
template: {
Resources: {
Bucket1: {
Type: 'AWS::S3::Bucket',
},
},
},
};

const localStack: CloudFormationStack = {
environment,
stackName: 'Stack1',
template: {
Resources: largeResources,
},
};

const result = await generateStackDefinitions(
[], [deployedStack], [localStack], environment, mockSdkProvider, mockIoHelper, 'MyCustomToolkit',
);

expect(result[0].TemplateURL).toBeDefined();
expect(ToolkitInfo.lookup).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
expect.anything(),
'MyCustomToolkit',
);
});

test('falls back to the default toolkit stack name when none is given', async () => {
const largeResources: any = {};
for (let i = 0; i < 500; i++) {
largeResources[`Bucket${i}`] = {
Type: 'AWS::S3::Bucket',
Properties: {
BucketName: `my-bucket-${i}`,
Tags: [
{ Key: 'Environment', Value: 'Production' },
{ Key: 'Application', Value: 'MyApp' },
{ Key: 'Owner', Value: 'TeamA' },
{ Key: 'CostCenter', Value: '12345' },
],
},
};
}

const deployedStack: CloudFormationStack = {
environment,
stackName: 'Stack1',
template: {
Resources: {
Bucket1: {
Type: 'AWS::S3::Bucket',
},
},
},
};

const localStack: CloudFormationStack = {
environment,
stackName: 'Stack1',
template: {
Resources: largeResources,
},
};

await generateStackDefinitions(
[], [deployedStack], [localStack], environment, mockSdkProvider, mockIoHelper,
);

expect(ToolkitInfo.lookup).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
expect.anything(),
undefined,
);
});
});
5 changes: 5 additions & 0 deletions packages/aws-cdk/lib/cli/cli-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,11 @@ export async function makeConfig(): Promise<CliConfig> {
default: false,
desc: 'Whether to do the refactor without asking for confirmation',
},
'toolkit-stack-name': {
type: 'string',
requiresArg: true,
desc: 'The name of the existing CDK toolkit stack (used to find the staging bucket for templates that are too large to be sent inline)',
},
},
arg: {
name: 'STACKS',
Expand Down
5 changes: 5 additions & 0 deletions packages/aws-cdk/lib/cli/cli-type-registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,11 @@
"type": "boolean",
"default": false,
"desc": "Whether to do the refactor without asking for confirmation"
},
"toolkit-stack-name": {
"type": "string",
"requiresArg": true,
"desc": "The name of the existing CDK toolkit stack (used to find the staging bucket for templates that are too large to be sent inline)"
}
},
"arg": {
Expand Down
2 changes: 2 additions & 0 deletions packages/aws-cdk/lib/cli/convert-to-user-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ export function convertYargsToUserInput(args: any): UserInput {
overrideFile: args.overrideFile,
revert: args.revert,
force: args.force,
toolkitStackName: args.toolkitStackName,
STACKS: args.STACKS,
};
break;
Expand Down Expand Up @@ -607,6 +608,7 @@ export function convertConfigToUserInput(config: any): UserInput {
overrideFile: config.refactor?.overrideFile,
revert: config.refactor?.revert,
force: config.refactor?.force,
toolkitStackName: config.refactor?.toolkitStackName,
};
const cliTelemetryOptions = {
enable: config.cliTelemetry?.enable,
Expand Down
6 changes: 6 additions & 0 deletions packages/aws-cdk/lib/cli/parse-command-line-arguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,12 @@ export function parseCommandLineArguments(args: Array<string>): any {
default: false,
type: 'boolean',
desc: 'Whether to do the refactor without asking for confirmation',
})
.option('toolkit-stack-name', {
default: undefined,
type: 'string',
requiresArg: true,
desc: 'The name of the existing CDK toolkit stack (used to find the staging bucket for templates that are too large to be sent inline)',
}),
)
.command('cli-telemetry', 'Enable or disable anonymous telemetry', (yargs: Argv) =>
Expand Down
7 changes: 7 additions & 0 deletions packages/aws-cdk/lib/cli/user-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1848,6 +1848,13 @@ export interface RefactorOptions {
*/
readonly force?: boolean;

/**
* The name of the existing CDK toolkit stack (used to find the staging bucket for templates that are too large to be sent inline)
*
* @default - undefined
*/
readonly toolkitStackName?: string;

Comment thread
mrgrain marked this conversation as resolved.
/**
* Positional argument for refactor
*/
Expand Down
14 changes: 14 additions & 0 deletions packages/aws-cdk/test/cli/cli-arguments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,20 @@ describe('yargs', () => {
globalOptions: expect.anything(),
});
});

test('refactor --toolkit-stack-name is correctly passed through', async () => {
const input = await parseCommandLineArguments(['refactor', '--toolkit-stack-name', 'MyCustomToolkit']);

const result = convertYargsToUserInput(input);

expect(result).toEqual({
command: 'refactor',
refactor: expect.objectContaining({
toolkitStackName: 'MyCustomToolkit',
}),
globalOptions: expect.anything(),
});
});
});

describe('config', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{"seq":0,"type":"notify","action":"refactor","level":"trace","code":"CDK_TOOLKIT_I1001","message":"Starting Synthesis ..."}
{"seq":1,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1000","message":"Starting Synthesis ..."}
{"seq":2,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1001","message":"\n✨ Synthesis time: <DURATION>\n"}
{"seq":3,"type":"notify","action":"refactor","level":"info","code":"CDK_TOOLKIT_I1000","message":"✨ Synthesis time: <DURATION>"}
{"seq":4,"type":"notify","action":"refactor","level":"info","code":null,"message":"aws://123456789012/bermuda-triangle-1\n"}
{"seq":5,"type":"notify","action":"refactor","level":"result","code":"CDK_TOOLKIT_I8900","message":"The following resources were moved or renamed:\n┌─────────────────┬───────────────────────────┬───────────────────────────┐\n│ Resource Type │ Old Construct Path │ New Construct Path │\n├─────────────────┼───────────────────────────┼───────────────────────────┤\n│ AWS::S3::Bucket │ Stack1/OldBucket/Resource │ Stack1/NewBucket/Resource │\n└─────────────────┴───────────────────────────┴───────────────────────────┘\n "}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{"seq":0,"type":"notify","action":"refactor","level":"trace","code":"CDK_TOOLKIT_I1001","message":"Starting Synthesis ..."}
{"seq":1,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1000","message":"Starting Synthesis ..."}
{"seq":2,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1001","message":"\n✨ Synthesis time: <DURATION>\n"}
{"seq":3,"type":"notify","action":"refactor","level":"info","code":"CDK_TOOLKIT_I1000","message":"✨ Synthesis time: <DURATION>"}
{"seq":4,"type":"notify","action":"refactor","level":"info","code":null,"message":"aws://123456789012/bermuda-triangle-1\n"}
{"seq":5,"type":"notify","action":"refactor","level":"result","code":"CDK_TOOLKIT_I8900","message":"The following resources were moved or renamed:\n┌─────────────────┬──────────────────────────┬──────────────────────────┐\n│ Resource Type │ Old Construct Path │ New Construct Path │\n├─────────────────┼──────────────────────────┼──────────────────────────┤\n│ AWS::S3::Bucket │ Stack1/MyBucket/Resource │ Stack2/MyBucket/Resource │\n└─────────────────┴──────────────────────────┴──────────────────────────┘\n "}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{"seq":0,"type":"notify","action":"refactor","level":"trace","code":"CDK_TOOLKIT_I1001","message":"Starting Synthesis ..."}
{"seq":1,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1000","message":"Starting Synthesis ..."}
{"seq":2,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1001","message":"\n✨ Synthesis time: <DURATION>\n"}
{"seq":3,"type":"notify","action":"refactor","level":"info","code":"CDK_TOOLKIT_I1000","message":"✨ Synthesis time: <DURATION>"}
{"seq":4,"type":"notify","action":"refactor","level":"info","code":null,"message":"aws://123456789012/bermuda-triangle-1\n"}
{"seq":5,"type":"notify","action":"refactor","level":"result","code":"CDK_TOOLKIT_I8900","message":"The following resources were moved or renamed:\n┌─────────────────┬─────────────────────────┬─────────────────────────┐\n│ Resource Type │ Old Construct Path │ New Construct Path │\n├─────────────────┼─────────────────────────┼─────────────────────────┤\n│ AWS::S3::Bucket │ Stack1/Bucket3/Resource │ Stack1/Bucket1/Resource │\n├─────────────────┼─────────────────────────┼─────────────────────────┤\n│ AWS::S3::Bucket │ Stack1/Bucket4/Resource │ Stack1/Bucket2/Resource │\n└─────────────────┴─────────────────────────┴─────────────────────────┘\n "}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{"seq":0,"type":"notify","action":"refactor","level":"trace","code":"CDK_TOOLKIT_I1001","message":"Starting Synthesis ..."}
{"seq":1,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1000","message":"Starting Synthesis ..."}
{"seq":2,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1001","message":"\n✨ Synthesis time: <DURATION>\n"}
{"seq":3,"type":"notify","action":"refactor","level":"info","code":"CDK_TOOLKIT_I1000","message":"✨ Synthesis time: <DURATION>"}
{"seq":4,"type":"notify","action":"refactor","level":"info","code":null,"message":"aws://123456789012/bermuda-triangle-1\n"}
{"seq":5,"type":"notify","action":"refactor","level":"result","code":"CDK_TOOLKIT_I8900","message":"The following resources were moved or renamed:\n┌─────────────────┬─────────────────────────┬─────────────────────────┐\n│ Resource Type │ Old Construct Path │ New Construct Path │\n├─────────────────┼─────────────────────────┼─────────────────────────┤\n│ AWS::S3::Bucket │ Stack1/Bucket1/Resource │ Stack1/Bucket3/Resource │\n├─────────────────┼─────────────────────────┼─────────────────────────┤\n│ AWS::S3::Bucket │ Stack1/Bucket2/Resource │ Stack1/Bucket4/Resource │\n└─────────────────┴─────────────────────────┴─────────────────────────┘\n "}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{"seq":0,"type":"notify","action":"refactor","level":"trace","code":"CDK_TOOLKIT_I1001","message":"Starting Synthesis ..."}
{"seq":1,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1000","message":"Starting Synthesis ..."}
{"seq":2,"type":"notify","action":"refactor","level":"trace","code":"CDK_CLI_I1001","message":"\n✨ Synthesis time: <DURATION>\n"}
{"seq":3,"type":"notify","action":"refactor","level":"info","code":"CDK_TOOLKIT_I1000","message":"✨ Synthesis time: <DURATION>"}
{"seq":4,"type":"notify","action":"refactor","level":"info","code":null,"message":"aws://123456789012/bermuda-triangle-1\n"}
{"seq":5,"type":"notify","action":"refactor","level":"result","code":"CDK_TOOLKIT_I8900","message":"Detected ambiguities:\n┌───┬─────────────────────────┐\n│ │ Resource │\n├───┼─────────────────────────┤\n│ - │ Stack1/Bucket1/Resource │\n│ │ Stack1/Bucket2/Resource │\n├───┼─────────────────────────┤\n│ + │ Stack1/Bucket3/Resource │\n│ │ Stack1/Bucket4/Resource │\n└───┴─────────────────────────┘\n \nPlease provide an override file to resolve these ambiguous mappings.\n "}
Loading
Loading