Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
dba2c09
bootstrap action
iankhou Feb 19, 2025
6e3e58a
import ordering
iankhou Feb 19, 2025
29973ef
bootstrap template YAML
iankhou Feb 19, 2025
73d8aee
fix the sdk provider mock
iankhou Feb 19, 2025
f2769f5
modified .projenrc.ts to add a post-compile task that copies the boot…
iankhou Feb 19, 2025
e972af1
delete copied bootstrap-template.yaml file
iankhou Feb 19, 2025
91b9ae8
some import optimizations
iankhou Feb 19, 2025
35a789b
use toolkit's toolkitStackName
iankhou Feb 19, 2025
f8d8f4e
new api and tests for custom bootstrap template
iankhou Feb 19, 2025
8ff4156
chore: self mutation
invalid-email-address Feb 19, 2025
4e14148
bootstrap scoped to environment level
iankhou Feb 20, 2025
52c9154
remove extra comment
iankhou Feb 20, 2025
e48ae89
chore: self mutation
invalid-email-address Feb 20, 2025
71e8b71
Simple refactoring, removed usage of deprecated .success() method, us…
iankhou Feb 21, 2025
9e43a8f
remove unnecessary files from cli-lib-alpha
iankhou Feb 21, 2025
b7f757f
copy bootstrap templates at build time instead of as a post-compile step
iankhou Feb 21, 2025
7ab7957
BootstrapEnvironment class enables running bootstrap with either cx o…
iankhou Feb 21, 2025
997540a
Merge branch 'main' into iankhou-toolkit-bootstrap
iankhou Feb 21, 2025
2fcf944
some renaming
iankhou Feb 21, 2025
e454a86
remove console log
iankhou Feb 21, 2025
792f145
chore: self mutation
invalid-email-address Feb 21, 2025
f6497a2
bootstrap parameter changes
iankhou Feb 21, 2025
f0dd065
line too long
iankhou Feb 23, 2025
28ecc6a
chore: self mutation
invalid-email-address Feb 23, 2025
536d2f7
Merge branch 'main' into iankhou-toolkit-bootstrap
iankhou Feb 24, 2025
64880df
merge changes
iankhou Feb 24, 2025
103f7cd
chore: self mutation
invalid-email-address Feb 24, 2025
fa8e75b
chore: self mutation
invalid-email-address Feb 24, 2025
9450502
chore: self mutation
invalid-email-address Feb 24, 2025
dbcb73e
modifed wrong projen file
iankhou Feb 24, 2025
849f7f9
tests for parameters
iankhou Feb 24, 2025
bacd260
chore: self mutation
invalid-email-address Feb 24, 2025
1a7588a
Merge branch 'main' into iankhou-toolkit-bootstrap
iankhou Feb 25, 2025
1b3100d
merge conflicts
iankhou Feb 25, 2025
89acec0
use CodeInfo code instead of string codes for bootstrap action and tests
iankhou Feb 25, 2025
d86a8b7
missed a status code
iankhou Feb 25, 2025
d2fd48b
code registry update and used string codes in tests
iankhou Feb 25, 2025
70e7082
linting
iankhou Feb 25, 2025
4e941da
move bootstrap example custom template to toolkit-lib test directory
iankhou Feb 27, 2025
95df4bf
Merge branch 'main' into iankhou-toolkit-bootstrap
iankhou Feb 28, 2025
5021e60
Revert bundle.mjs
iankhou Feb 28, 2025
a77119a
fix unbound method
iankhou Feb 28, 2025
7fab3ae
use allowed example account number
iankhou Feb 28, 2025
6024708
Merge branch 'main' into iankhou-toolkit-bootstrap
iankhou Feb 28, 2025
e86cb81
Merge branch 'main' into iankhou-toolkit-bootstrap
iankhou Mar 3, 2025
de076c3
Merge branch 'main' into iankhou-toolkit-bootstrap
mrgrain Mar 3, 2025
17fd77e
interface cleanup
mrgrain Mar 3, 2025
afdbef8
public bootstrap types
mrgrain Mar 3, 2025
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
28 changes: 28 additions & 0 deletions packages/@aws-cdk/tmp-toolkit-helpers/src/util/directories.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { ToolkitError } from '../api/toolkit-error';

/**
* Return a location that will be used as the CDK home directory.
Expand Down Expand Up @@ -34,3 +35,30 @@ export function cdkHomeDir() {
export function cdkCacheDir() {
return path.join(cdkHomeDir(), 'cache');
}

/**
* From the start location, find the directory that contains the bundled package's package.json
*
* You must assume the caller of this function will be bundled and the package root dir
* is not going to be the same as the package the caller currently lives in.
*/
export function bundledPackageRootDir(start: string): string;
export function bundledPackageRootDir(start: string, fail: true): string;
export function bundledPackageRootDir(start: string, fail: false): string | undefined;
export function bundledPackageRootDir(start: string, fail?: boolean) {
function _rootDir(dirname: string): string | undefined {
const manifestPath = path.join(dirname, 'package.json');
if (fs.existsSync(manifestPath)) {
return dirname;
}
if (path.dirname(dirname) === dirname) {
if (fail ?? true) {
throw new ToolkitError('Unable to find package manifest');
}
return undefined;
}
return _rootDir(path.dirname(dirname));
}

return _rootDir(start);
}
3 changes: 3 additions & 0 deletions packages/@aws-cdk/toolkit-lib/CODE_REGISTRY.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
| CDK_TOOLKIT_I7010 | Confirm destroy stacks | info | n/a |
| CDK_TOOLKIT_E7010 | Action was aborted due to negative confirmation of request | error | n/a |
| CDK_TOOLKIT_E7900 | Stack deletion failed | error | n/a |
| CDK_TOOLKIT_I9000 | Provides bootstrap times | info | n/a |
| CDK_TOOLKIT_I9900 | Bootstrap results on success | info | n/a |
| CDK_TOOLKIT_E9900 | Bootstrap failed | error | n/a |
| CDK_ASSEMBLY_I0042 | Writing updated context | debug | n/a |
| CDK_ASSEMBLY_I0241 | Fetching missing context | debug | n/a |
| CDK_ASSEMBLY_I1000 | Cloud assembly output starts | debug | n/a |
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/toolkit-lib/build-tools/bundle.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ await Promise.all([
copyFromCli(['build-info.json']),
copyFromCli(['/db.json.gz']),
copyFromCli(['lib', 'index_bg.wasm']),
copyFromCli(['lib', 'api', 'bootstrap', 'bootstrap-template.yaml']),
]);

// # Copy all resources that aws_cdk/generate.sh produced, and some othersCall the generator for the
// cp -R $aws_cdk/lib/init-templates ./lib/
// mkdir -p ./lib/api/bootstrap/ && cp $aws_cdk/lib/api/bootstrap/bootstrap-template.yaml ./lib/api/bootstrap/

await esbuild.build({
outdir: 'lib',
Expand Down
229 changes: 229 additions & 0 deletions packages/@aws-cdk/toolkit-lib/lib/actions/bootstrap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import * as cxapi from '@aws-cdk/cx-api';
import { environmentsFromDescriptors } from './private';
import type { Tag } from '../../api/aws-cdk';
import type { ICloudAssemblySource } from '../../api/cloud-assembly';
import { ALL_STACKS } from '../../api/cloud-assembly/private';
import { assemblyFromSource } from '../../toolkit/private';

/**
* Create manage bootstrap environments
*/
export class BootstrapEnvironments {
/**
* Create from a list of environment descriptors
* List of strings like `['aws://012345678912/us-east-1', 'aws://234567890123/eu-west-1']`
*/
static fromList(environments: string[]): BootstrapEnvironments {
return new BootstrapEnvironments(environmentsFromDescriptors(environments));
}

/**
* Create from a cloud assembly source
*/
static fromCloudAssemblySource(cx: ICloudAssemblySource): BootstrapEnvironments {
return new BootstrapEnvironments(async () => {
const assembly = await assemblyFromSource(cx);
const stackCollection = assembly.selectStacksV2(ALL_STACKS);
return stackCollection.stackArtifacts.map(stack => stack.environment);
});
}

private constructor(private readonly envProvider: cxapi.Environment[] | (() => Promise<cxapi.Environment[]>)) {
}

async getEnvironments(): Promise<cxapi.Environment[]> {
if (Array.isArray(this.envProvider)) {
return this.envProvider;
}
return this.envProvider();
}
}

/**
* Options for Bootstrap
*/
export interface BootstrapOptions {

/**
* Bootstrap environment parameters for CloudFormation used when deploying the bootstrap stack
* @default BootstrapEnvironmentParameters.onlyExisting()
*/
readonly parameters?: BootstrapStackParameters;

/**
* The template source of the bootstrap stack
*
* @default BootstrapSource.default()
*/
readonly source?: { source: 'default' } | { source: 'custom'; templateFile: string };

/**
* Whether to execute the changeset or only create it and leave it in review
* @default true
*/
readonly execute?: boolean;

/**
* Tags for cdktoolkit stack
*
* @default []
*/
readonly tags?: Tag[];

/**
* Whether the stacks created by the bootstrap process should be protected from termination
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-protect-stacks.html
* @default true
*/
readonly terminationProtection?: boolean;
}

/**
* Parameter values for the bootstrapping template
*/
export interface BootstrapParameters {
/**
* The name to be given to the CDK Bootstrap bucket
* By default, a name is generated by CloudFormation
*
* @default - No value, optional argument
*/
readonly bucketName?: string;

/**
* The ID of an existing KMS key to be used for encrypting items in the bucket
* By default, the default KMS key is used
*
* @default - No value, optional argument
*/
readonly kmsKeyId?: string;

/**
* Whether or not to create a new customer master key (CMK)
*
* Only applies to modern bootstrapping
* Legacy bootstrapping will never create a CMK, only use the default S3 key
*
* @default false
*/
readonly createCustomerMasterKey?: boolean;

/**
* The list of AWS account IDs that are trusted to deploy into the environment being bootstrapped
*
* @default []
*/
readonly trustedAccounts?: string[];

/**
* The list of AWS account IDs that are trusted to look up values in the environment being bootstrapped
*
* @default []
*/
readonly trustedAccountsForLookup?: string[];

/**
* The list of AWS account IDs that should not be trusted by the bootstrapped environment
* If these accounts are already trusted, they will be removed on bootstrapping
*
* @default []
*/
readonly untrustedAccounts?: string[];

/**
* The ARNs of the IAM managed policies that should be attached to the role performing CloudFormation deployments
* In most cases, this will be the AdministratorAccess policy
* At least one policy is required if `trustedAccounts` were passed
*
* @default []
*/
readonly cloudFormationExecutionPolicies?: string[];

/**
* Identifier to distinguish multiple bootstrapped environments
* The default qualifier is an arbitrary but unique string
*
* @default - 'hnb659fds'
*/
readonly qualifier?: string;

/**
* Whether or not to enable S3 Staging Bucket Public Access Block Configuration
*
* @default true
*/
readonly publicAccessBlockConfiguration?: boolean;

/**
* Flag for using the default permissions boundary for bootstrapping
*
* @default - No value, optional argument
*/
readonly examplePermissionsBoundary?: boolean;

/**
* Name for the customer's custom permissions boundary for bootstrapping
*
* @default - No value, optional argument
*/
readonly customPermissionsBoundary?: string;
}

/**
* Parameters of the bootstrapping template with flexible configuration options
*/
export class BootstrapStackParameters {
/**
* Use only existing parameters on the stack.
*/
public static onlyExisting() {
return new BootstrapStackParameters({}, true);
}

/**
* Use exactly these parameters and remove any other existing parameters from the stack.
*/
public static exactly(params: BootstrapParameters) {
return new BootstrapStackParameters(params, false);
}

/**
* Define additional parameters for the stack, while keeping existing parameters for unspecified values.
*/
public static withExisting(params: BootstrapParameters) {
return new BootstrapStackParameters(params, true);
}

/**
* The parameters as a Map for easy access and manipulation
*/
public readonly parameters?: BootstrapParameters;
public readonly keepExistingParameters: boolean;

private constructor(params?: BootstrapParameters, usePreviousParameters = true) {
this.keepExistingParameters = usePreviousParameters;
this.parameters = params;
}
}

/**
* Source configuration for bootstrap operations
*/
export class BootstrapSource {
/**
* Use the default bootstrap template
*/
static default(): BootstrapOptions['source'] {
return { source: 'default' };
}

/**
* Use a custom bootstrap template
*/
static customTemplate(templateFile: string): BootstrapOptions['source'] {
return {
source: 'custom',
templateFile,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as cxapi from '@aws-cdk/cx-api';
import { ToolkitError } from '../../../api/shared-public';

/**
* Given a set of "<account>/<region>" strings, construct environments for them
*/
export function environmentsFromDescriptors(envSpecs: string[]): cxapi.Environment[] {
const ret = new Array<cxapi.Environment>();

for (const spec of envSpecs) {
const parts = spec.replace(/^aws:\/\//, '').split('/');
if (parts.length !== 2) {
throw new ToolkitError(`Expected environment name in format 'aws://<account>/<region>', got: ${spec}`);
}

ret.push({
name: spec,
account: parts[0],
region: parts[1],
});
}

return ret;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './helpers';
1 change: 1 addition & 0 deletions packages/@aws-cdk/toolkit-lib/lib/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './bootstrap';
export * from './deploy';
export * from './destroy';
export * from './list';
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk/toolkit-lib/lib/api/aws-cdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ export { formatSdkLoggerContent, SdkProvider } from '../../../../aws-cdk/lib/api
export { Context, PROJECT_CONTEXT } from '../../../../aws-cdk/lib/api/context';
export { Deployments, type SuccessfulDeployStackResult } from '../../../../aws-cdk/lib/api/deployments';
export { Settings } from '../../../../aws-cdk/lib/api/settings';
export { tagsForStack, Tag } from '../../../../aws-cdk/lib/api/tags';
export { type Tag, tagsForStack } from '../../../../aws-cdk/lib/api/tags';
export { DEFAULT_TOOLKIT_STACK_NAME } from '../../../../aws-cdk/lib/api/toolkit-info';
export { ResourceMigrator } from '../../../../aws-cdk/lib/api/resource-import';
export { CloudWatchLogEventMonitor, findCloudWatchLogGroups } from '../../../../aws-cdk/lib/api/logs';
export { type WorkGraph, WorkGraphBuilder, AssetBuildNode, AssetPublishNode, StackNode, Concurrency } from '../../../../aws-cdk/lib/api/work-graph';
export { Bootstrapper } from '../../../../aws-cdk/lib/api/bootstrap';

// Context Providers
export * as contextproviders from '../../../../aws-cdk/lib/context-providers';
Expand Down
15 changes: 15 additions & 0 deletions packages/@aws-cdk/toolkit-lib/lib/api/io/private/codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,21 @@ export const CODES = {
}),

// 9: Bootstrap
CDK_TOOLKIT_I9000: codeInfo({
code: 'CDK_TOOLKIT_I9000',
description: 'Provides bootstrap times',
level: 'info',
}),
CDK_TOOLKIT_I9900: codeInfo({
code: 'CDK_TOOLKIT_I9900',
description: 'Bootstrap results on success',
level: 'info',
}),
CDK_TOOLKIT_E9900: codeInfo({
code: 'CDK_TOOLKIT_E9900',
description: 'Bootstrap failed',
level: 'error',
}),

// Assembly codes
CDK_ASSEMBLY_I0042: codeInfo({
Expand Down
5 changes: 3 additions & 2 deletions packages/@aws-cdk/toolkit-lib/lib/api/io/private/timer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class Timer {
* Ends the current timer as a specified timing and notifies the IoHost.
* @returns the elapsed time
*/
public async endAs(ioHost: ActionAwareIoHost, type: 'synth' | 'deploy' | 'rollback' | 'destroy') {
public async endAs(ioHost: ActionAwareIoHost, type: 'synth' | 'deploy' | 'rollback' | 'destroy' | 'bootstrap') {
const duration = this.end();
const { code, text } = timerMessageProps(type);

Expand All @@ -49,7 +49,7 @@ export class Timer {
}
}

function timerMessageProps(type: 'synth' | 'deploy' | 'rollback'| 'destroy'): {
function timerMessageProps(type: 'synth' | 'deploy' | 'rollback'| 'destroy' | 'bootstrap'): {
code: CodeInfo;
text: string;
} {
Expand All @@ -58,5 +58,6 @@ function timerMessageProps(type: 'synth' | 'deploy' | 'rollback'| 'destroy'): {
case 'deploy': return { code: CODES.CDK_TOOLKIT_I5000, text: 'Deployment' };
case 'rollback': return { code: CODES.CDK_TOOLKIT_I6000, text: 'Rollback' };
case 'destroy': return { code: CODES.CDK_TOOLKIT_I7000, text: 'Destroy' };
case 'bootstrap': return { code: CODES.CDK_TOOLKIT_I9000, text: 'Bootstrap' };
}
}
Loading