@go-to-k/cdkd 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -596
- package/dist/cli.js +103 -29
- package/dist/cli.js.map +3 -3
- package/dist/go-to-k-cdkd-0.30.0.tgz +0 -0
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.29.0.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -1304,14 +1304,14 @@ async function resolveStateBucketWithDefaultAndSource(cliBucket, region) {
|
|
|
1304
1304
|
const logger = getLogger();
|
|
1305
1305
|
logger.debug("No state bucket specified, resolving default from account...");
|
|
1306
1306
|
const { GetCallerIdentityCommand: GetCallerIdentityCommand11 } = await import("@aws-sdk/client-sts");
|
|
1307
|
-
const { S3Client:
|
|
1307
|
+
const { S3Client: S3Client12 } = await import("@aws-sdk/client-s3");
|
|
1308
1308
|
const { getAwsClients: getAwsClients2 } = await Promise.resolve().then(() => (init_aws_clients(), aws_clients_exports));
|
|
1309
1309
|
const awsClients = getAwsClients2();
|
|
1310
1310
|
const identity = await awsClients.sts.send(new GetCallerIdentityCommand11({}));
|
|
1311
1311
|
const accountId = identity.Account;
|
|
1312
1312
|
const newName = getDefaultStateBucketName(accountId);
|
|
1313
1313
|
const legacyName = getLegacyStateBucketName(accountId, region);
|
|
1314
|
-
const probe = new
|
|
1314
|
+
const probe = new S3Client12({ region: "us-east-1" });
|
|
1315
1315
|
try {
|
|
1316
1316
|
const newExists = await bucketExists(probe, newName);
|
|
1317
1317
|
const legacyExists = await bucketExists(probe, legacyName);
|
|
@@ -35330,6 +35330,7 @@ import {
|
|
|
35330
35330
|
waitUntilStackUpdateComplete,
|
|
35331
35331
|
waitUntilStackDeleteComplete
|
|
35332
35332
|
} from "@aws-sdk/client-cloudformation";
|
|
35333
|
+
import { S3Client as S3Client11, PutObjectCommand as PutObjectCommand5, DeleteObjectCommand as DeleteObjectCommand4 } from "@aws-sdk/client-s3";
|
|
35333
35334
|
var STABLE_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
35334
35335
|
"CREATE_COMPLETE",
|
|
35335
35336
|
"UPDATE_COMPLETE",
|
|
@@ -35338,9 +35339,11 @@ var STABLE_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
|
35338
35339
|
"IMPORT_ROLLBACK_COMPLETE"
|
|
35339
35340
|
]);
|
|
35340
35341
|
var TEMPLATE_BODY_LIMIT = 51200;
|
|
35342
|
+
var TEMPLATE_URL_LIMIT = 1048576;
|
|
35343
|
+
var MIGRATE_TMP_PREFIX = "cdkd-migrate-tmp";
|
|
35341
35344
|
async function retireCloudFormationStack(options) {
|
|
35342
35345
|
const logger = getLogger();
|
|
35343
|
-
const { cfnStackName, cfnClient, yes } = options;
|
|
35346
|
+
const { cfnStackName, cfnClient, yes, stateBucket, s3ClientOpts } = options;
|
|
35344
35347
|
logger.info(`[1/4] Inspecting CloudFormation stack '${cfnStackName}'...`);
|
|
35345
35348
|
const desc = await cfnClient.send(new DescribeStacksCommand({ StackName: cfnStackName }));
|
|
35346
35349
|
const stack = desc.Stacks?.[0];
|
|
@@ -35370,39 +35373,69 @@ async function retireCloudFormationStack(options) {
|
|
|
35370
35373
|
return { outcome: "cancelled" };
|
|
35371
35374
|
}
|
|
35372
35375
|
}
|
|
35373
|
-
let updateRan = false;
|
|
35374
35376
|
if (!modified) {
|
|
35375
35377
|
logger.info(`[2/4] Template already has Retain on every resource \u2014 skipping UpdateStack.`);
|
|
35376
35378
|
} else {
|
|
35377
35379
|
logger.info(`[2/4] Injected DeletionPolicy=Retain and UpdateReplacePolicy=Retain.`);
|
|
35378
|
-
if (newBody.length >
|
|
35380
|
+
if (newBody.length > TEMPLATE_URL_LIMIT) {
|
|
35379
35381
|
throw new Error(
|
|
35380
|
-
`Modified template is ${newBody.length} bytes, exceeds the
|
|
35382
|
+
`Modified template is ${newBody.length} bytes, exceeds the CloudFormation UpdateStack TemplateURL limit (${TEMPLATE_URL_LIMIT}). cdkd state has already been written; retire the stack manually with (1) shrink the template, then (2) UpdateStack with Retain policies, (3) DeleteStack \u2014 or split the stack and retry.`
|
|
35381
35383
|
);
|
|
35382
35384
|
}
|
|
35383
|
-
|
|
35384
|
-
|
|
35385
|
-
|
|
35386
|
-
|
|
35387
|
-
|
|
35388
|
-
|
|
35389
|
-
|
|
35390
|
-
})
|
|
35385
|
+
let updateInput;
|
|
35386
|
+
let s3Cleanup;
|
|
35387
|
+
if (newBody.length <= TEMPLATE_BODY_LIMIT) {
|
|
35388
|
+
updateInput = { TemplateBody: newBody };
|
|
35389
|
+
} else {
|
|
35390
|
+
logger.info(
|
|
35391
|
+
` Template is ${newBody.length} bytes (over ${TEMPLATE_BODY_LIMIT} inline limit) \u2014 uploading to state bucket '${stateBucket}'.`
|
|
35391
35392
|
);
|
|
35392
|
-
|
|
35393
|
-
|
|
35394
|
-
|
|
35395
|
-
|
|
35396
|
-
|
|
35397
|
-
}
|
|
35398
|
-
|
|
35399
|
-
|
|
35393
|
+
const uploaded = await uploadTemplateForUpdateStack({
|
|
35394
|
+
bucket: stateBucket,
|
|
35395
|
+
body: newBody,
|
|
35396
|
+
cfnStackName,
|
|
35397
|
+
...s3ClientOpts && { s3ClientOpts }
|
|
35398
|
+
});
|
|
35399
|
+
updateInput = { TemplateURL: uploaded.url };
|
|
35400
|
+
s3Cleanup = uploaded.cleanup;
|
|
35400
35401
|
}
|
|
35401
|
-
|
|
35402
|
-
|
|
35403
|
-
|
|
35404
|
-
|
|
35405
|
-
|
|
35402
|
+
try {
|
|
35403
|
+
logger.info(`[3/4] Updating CloudFormation stack with Retain policies...`);
|
|
35404
|
+
let updateRan = false;
|
|
35405
|
+
try {
|
|
35406
|
+
await cfnClient.send(
|
|
35407
|
+
new UpdateStackCommand({
|
|
35408
|
+
StackName: cfnStackName,
|
|
35409
|
+
...updateInput,
|
|
35410
|
+
Capabilities: capabilities
|
|
35411
|
+
})
|
|
35412
|
+
);
|
|
35413
|
+
updateRan = true;
|
|
35414
|
+
} catch (err) {
|
|
35415
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
35416
|
+
if (/No updates are to be performed/i.test(msg)) {
|
|
35417
|
+
logger.info(` CloudFormation reports no updates needed \u2014 proceeding to delete.`);
|
|
35418
|
+
} else {
|
|
35419
|
+
throw err;
|
|
35420
|
+
}
|
|
35421
|
+
}
|
|
35422
|
+
if (updateRan) {
|
|
35423
|
+
await waitUntilStackUpdateComplete(
|
|
35424
|
+
{ client: cfnClient, maxWaitTime: 1800 },
|
|
35425
|
+
{ StackName: cfnStackName }
|
|
35426
|
+
);
|
|
35427
|
+
}
|
|
35428
|
+
} finally {
|
|
35429
|
+
if (s3Cleanup) {
|
|
35430
|
+
try {
|
|
35431
|
+
await s3Cleanup();
|
|
35432
|
+
} catch (cleanupErr) {
|
|
35433
|
+
const msg = cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr);
|
|
35434
|
+
logger.warn(
|
|
35435
|
+
`Failed to delete temporary template upload from '${stateBucket}'. Clean up manually under prefix '${MIGRATE_TMP_PREFIX}/'. Cause: ${msg}`
|
|
35436
|
+
);
|
|
35437
|
+
}
|
|
35438
|
+
}
|
|
35406
35439
|
}
|
|
35407
35440
|
}
|
|
35408
35441
|
logger.info(`[4/4] Deleting CloudFormation stack '${cfnStackName}' (resources retained)...`);
|
|
@@ -35416,6 +35449,41 @@ async function retireCloudFormationStack(options) {
|
|
|
35416
35449
|
);
|
|
35417
35450
|
return { outcome: modified ? "retired" : "no-template-change" };
|
|
35418
35451
|
}
|
|
35452
|
+
async function uploadTemplateForUpdateStack(args) {
|
|
35453
|
+
const { bucket, body, cfnStackName, s3ClientOpts } = args;
|
|
35454
|
+
const region = await resolveBucketRegion(bucket, {
|
|
35455
|
+
...s3ClientOpts?.profile && { profile: s3ClientOpts.profile },
|
|
35456
|
+
...s3ClientOpts?.credentials && { credentials: s3ClientOpts.credentials }
|
|
35457
|
+
});
|
|
35458
|
+
const s3 = new S3Client11({
|
|
35459
|
+
region,
|
|
35460
|
+
...s3ClientOpts?.profile && { profile: s3ClientOpts.profile },
|
|
35461
|
+
...s3ClientOpts?.credentials && { credentials: s3ClientOpts.credentials }
|
|
35462
|
+
});
|
|
35463
|
+
const key = `${MIGRATE_TMP_PREFIX}/${cfnStackName}/${Date.now()}.json`;
|
|
35464
|
+
try {
|
|
35465
|
+
await s3.send(
|
|
35466
|
+
new PutObjectCommand5({
|
|
35467
|
+
Bucket: bucket,
|
|
35468
|
+
Key: key,
|
|
35469
|
+
Body: body,
|
|
35470
|
+
ContentType: "application/json"
|
|
35471
|
+
})
|
|
35472
|
+
);
|
|
35473
|
+
} catch (err) {
|
|
35474
|
+
s3.destroy();
|
|
35475
|
+
throw err;
|
|
35476
|
+
}
|
|
35477
|
+
const url = `https://${bucket}.s3.${region}.amazonaws.com/${key}`;
|
|
35478
|
+
const cleanup = async () => {
|
|
35479
|
+
try {
|
|
35480
|
+
await s3.send(new DeleteObjectCommand4({ Bucket: bucket, Key: key }));
|
|
35481
|
+
} finally {
|
|
35482
|
+
s3.destroy();
|
|
35483
|
+
}
|
|
35484
|
+
};
|
|
35485
|
+
return { url, cleanup };
|
|
35486
|
+
}
|
|
35419
35487
|
function injectRetainPolicies(templateBody, cfnStackName) {
|
|
35420
35488
|
let parsed;
|
|
35421
35489
|
try {
|
|
@@ -35695,7 +35763,13 @@ async function importCommand(stackArg, options) {
|
|
|
35695
35763
|
await retireCloudFormationStack({
|
|
35696
35764
|
cfnStackName: migrationCfnStackName,
|
|
35697
35765
|
cfnClient: awsClients.cloudFormation,
|
|
35698
|
-
yes: options.yes
|
|
35766
|
+
yes: options.yes,
|
|
35767
|
+
// Reuse cdkd's state bucket as transient storage for the
|
|
35768
|
+
// Retain-injected template when it exceeds the 51,200-byte
|
|
35769
|
+
// inline UpdateStack limit. Forward `--profile` so the
|
|
35770
|
+
// upload identity matches the one that just wrote cdkd state.
|
|
35771
|
+
stateBucket,
|
|
35772
|
+
...options.profile && { s3ClientOpts: { profile: options.profile } }
|
|
35699
35773
|
});
|
|
35700
35774
|
}
|
|
35701
35775
|
} finally {
|
|
@@ -35988,7 +36062,7 @@ function reorderArgs(argv) {
|
|
|
35988
36062
|
}
|
|
35989
36063
|
async function main() {
|
|
35990
36064
|
const program = new Command13();
|
|
35991
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
36065
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.30.0");
|
|
35992
36066
|
program.addCommand(createBootstrapCommand());
|
|
35993
36067
|
program.addCommand(createSynthCommand());
|
|
35994
36068
|
program.addCommand(createListCommand());
|