@go-to-k/cdkd 0.284.38 → 0.284.39
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/dist/{asg-provider-kqBWElNc.js → asg-provider-Db6lnsaA.js} +2 -2
- package/dist/{asg-provider-kqBWElNc.js.map → asg-provider-Db6lnsaA.js.map} +1 -1
- package/dist/cli.js +335 -38
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-DyxASW-O.js → deploy-engine-rKBFVifY.js} +60 -13
- package/dist/deploy-engine-rKBFVifY.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-DyxASW-O.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as startInterruptWatch, $t as
|
|
2
|
+
import { $ as startInterruptWatch, $n as CdkdError, $t as WorkGraph, A as renderStatefulReason, An as resolveStateBucketWithDefault, At as redactSecretsForState, B as exportAliasCollisionScrubWarning, Bn as expectedOwnerParam, Bt as DiffCalculator, C as isFinalSnapshotError, Cn as synthesisStatusMessage, Cr as isMarkedNonRetryable, Ct as TEMPLATE_SOURCED_RULES, D as extractDeploymentEventError, Dn as resolveAutoAssetStorage, Dt as isSingleDynamicReferenceToken, E as makeCanonicalizePropertiesFn, En as resolveApp, Er as markNonRetryable, Et as errorCauseChain, F as green, Fn as CFN_TEMPLATE_BODY_LIMIT, Ft as s3BucketDomainName, G as collectInlinePolicyNamesManagedBySiblings, Gn as processStackMessages, Gt as TemplateParser, H as secretBearingStateKeyWarning, Hn as canonicalizeRegion, Ht as describeTypeWithThrottleRetry, I as red, In as CFN_TEMPLATE_URL_LIMIT, It as s3BucketDualStackDomainName, J as findActionableSilentDrops, Jn as AwsClients, Jt as S3StateBackend, K as clearOnUpdateRemoval, Kt as LockManager, L as yellow, Ln as MIGRATE_TMP_PREFIX, Lt as s3BucketRegionalDomainName, M as bold, Mn as resolveUseCdkBootstrapAssets, Mt as classifyReplaySecretRegion, N as cyan, Nn as stateBucketExistenceConfirmed, Nt as producerRegionsFromState, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as resolveCaptureObservedState, Ot as maskSecretsInError, P as gray, Pn as warnDeprecatedNoPrefixCliFlag, Pt as s3BucketArn, Q as isInterruptedWaitError, Qt as stringifyValue, R as collectDeclaredOutputNames, Rn as findLargeInlineResources, Rt as s3BucketWebsiteUrl, S as createPreDeleteFinalSnapshot, Sn as Synthesizer, Sr as withErrorHandling, St as STATE_SOURCED_READBACK_RULES, T as unsupportedFinalSnapshotError, Tn as getLegacyStateBucketName, Tr as isThrottlingError, Tt as dynamicReferenceTokens, U as stateKeySecretExposure, Un as derivePartitionAndUrlSuffix, Ut as withRetry, V as isExportAliasCollision, Vn as PARTITION_TABLE, Vt as INTRINSIC_KEYS, W as IAMRoleProvider, Wn as AssemblyReader, Wt as DagBuilder, X as beginCommandInterruptScope, Xn as resetAwsClients, Xt as shouldRetainResource, Y as findSilentDropProperties, Yn as getAwsClients, Yt as rebuildClientForBucketRegion, Z as endCommandInterruptScope, Zn as setAwsClients, Zt as AssetPublisher, _ as computeImplicitDeleteEdges, _n as getDockerCmd, _t as replayWarn, a as DeploymentEventsStore, an as stripControlChars, ar as LocalInvokeBuildError$1, at as carriesDynamicReference, b as buildFinalSnapshotIdentifier, bn as AssetManifestLoader, bt as requireConfigString, c as replayFailedOperations, cn as ensureAssetStorage, ct as refStateLookupFromResource, d as updatePartialReason, dn as readBootstrapMarkerBody, dr as PartialFailureError, dt as resolveExplicitPhysicalId, en as buildAssetRedirectMap, et as CloudControlProvider, f as UNSPECIFIED_SKIP_REASON, fn as validateAssetBucketName, fr as ProvisioningError, ft as assertRegionMatch, g as IMPLICIT_DELETE_DEPENDENCIES, gn as formatDockerLoginError, gr as StackTerminationProtectionError, gt as readConfigString, h as maskingRetryLogger, hn as buildDockerImage, hr as StackHasActiveImportsError, ht as configStringRefusal, i as DeploymentEventsReader, in as escapeRegExp, ir as DynamicReferenceRegionAmbiguousError, it as IntrinsicFunctionResolver, j as formatResourceLine, jn as resolveStateBucketWithDefaultAndSource, jt as scrubResourceRecord, k as isStatefulRecreateTargetSync, kn as resolveSkipPrefix, kt as maskSecretsInText, l as replayRollback, ln as getBootstrapMarkerKey, lr as MissingCdkCliError, lt as WAFv2WebACLProvider, m as withResourceDeadline, mn as buildDenyExternalAccessPolicy, mr as ResourceUpdateNotSupportedError, mt as configBooleanRefusal, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as loadPublishableAssetManifest, nt as disableInstanceApiTermination, o as planFailedOps, on as AssetModeResolver, or as LocalMigrateError, ot as cfnRefValueFromPhysicalId, p as deleteSkipReason, pn as validateContainerRepoName, pr as ResourceTimeoutError, pt as coerceCfnBoolean, q as ProviderRegistry, qn as resolveBucketRegion, qt as displaySafe, r as DeployEngine, rn as rewriteTemplateAssetReferences, rr as DeployCancelledError, rt as isTerminationProtectionPropagationError, s as planRollback, sn as BOOTSTRAP_MARKER_PREFIX, sr as LocalStartServiceError, st as getAccountInfo, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as createAssetRedirectResolver, tr as CrossAccountSecretRefusalError, tt as slowCcOperationTimeoutMs, u as updatePartialMessage, un as parseBootstrapMarker, ur as NestedStackChildDirectDestroyError, ut as normalizeAwsTagsToCfn, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as runDockerForeground, vt as requireConfigArray, w as refusesFinalSnapshot, wn as getDefaultStateBucketName, wr as isRetryableTransientError, wt as createSecretMasker, x as ccRoutedFinalSnapshotError, xn as getDockerImageBySourceHash, xr as normalizeAwsError, xt as STATE_SOURCED_CROSS_GENERATION_RULES, y as PRE_DELETE_SNAPSHOT_TYPES, yn as runDockerStreaming, yt as requireConfigObject, z as collectPublishedOutputNames, zn as uploadCfnTemplate, zt as applyRoleArnIfSet } from "./deploy-engine-rKBFVifY.js";
|
|
3
3
|
import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as getCurrentStackName, h as withStackName, i as runStackBuffered, m as withSkipPrefix, n as getLogger, o as PATTERN_B_NAME_OPTIONS, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-zRrlbaQt.js";
|
|
4
|
-
import { t as ASGProvider } from "./asg-provider-
|
|
4
|
+
import { t as ASGProvider } from "./asg-provider-Db6lnsaA.js";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
7
7
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -77,6 +77,23 @@ import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
|
77
77
|
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
78
78
|
import { WebSocketServer } from "ws";
|
|
79
79
|
|
|
80
|
+
//#region src/state/state-prefix.ts
|
|
81
|
+
/**
|
|
82
|
+
* The default S3 key prefix for cdkd state.
|
|
83
|
+
*
|
|
84
|
+
* Homed in the STATE layer rather than in `src/cli/commands/state-file-keys.ts`
|
|
85
|
+
* (which re-exports it, so its four existing importers are unchanged) because
|
|
86
|
+
* `src/state/lock-contention-message.ts` needs it to decide whether a recovery
|
|
87
|
+
* hint should spell `--state-prefix` at all, and a `src/state/**` module
|
|
88
|
+
* importing from `src/cli/commands/**` inverts the layering — the CLI sits
|
|
89
|
+
* ABOVE the state layer in the 7-layer architecture, not below it.
|
|
90
|
+
*
|
|
91
|
+
* Note this is only the DEFAULT. Other commands accept `--state-prefix`, so
|
|
92
|
+
* whole-bucket listings deliberately do not scope to it.
|
|
93
|
+
*/
|
|
94
|
+
const DEFAULT_STATE_PREFIX = "cdkd";
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
80
97
|
//#region src/cli/commands/state-file-keys.ts
|
|
81
98
|
/**
|
|
82
99
|
* Shared helpers for enumerating and describing cdkd state-bucket keys.
|
|
@@ -94,20 +111,6 @@ import { WebSocketServer } from "ws";
|
|
|
94
111
|
*/
|
|
95
112
|
const STATE_FILE_SUFFIX = "/state.json";
|
|
96
113
|
/**
|
|
97
|
-
* The prefix `cdkd bootstrap` writes under, and the one `gc` /
|
|
98
|
-
* `bootstrap --destroy` configure their own state backend with.
|
|
99
|
-
*
|
|
100
|
-
* Shared here rather than spelled per command for the same reason this module
|
|
101
|
-
* exists at all: `bootstrap-destroy.ts` and `gc.ts` each held their own copy,
|
|
102
|
-
* and it is now also the `knownPrefix` argument to {@link describeStateKey},
|
|
103
|
-
* where a copy that drifted from the backend's actual prefix would silently
|
|
104
|
-
* send every key back to the shape heuristic instead of the exact depth rule.
|
|
105
|
-
*
|
|
106
|
-
* Note this is only the DEFAULT. Other commands accept `--state-prefix`, so
|
|
107
|
-
* the whole-bucket listings deliberately do not scope to it.
|
|
108
|
-
*/
|
|
109
|
-
const DEFAULT_STATE_PREFIX = "cdkd";
|
|
110
|
-
/**
|
|
111
114
|
* Segments left under a known prefix for the legacy `{prefix}/{stack}` layout.
|
|
112
115
|
*
|
|
113
116
|
* The twin of `S3StateBackend`'s `LEGACY_KEY_DEPTH`, which counts the
|
|
@@ -58162,6 +58165,104 @@ var ECRProvider = class {
|
|
|
58162
58165
|
}
|
|
58163
58166
|
};
|
|
58164
58167
|
|
|
58168
|
+
//#endregion
|
|
58169
|
+
//#region src/state/lock-contention-message.ts
|
|
58170
|
+
/**
|
|
58171
|
+
* The message every fail-fast lock-contention site raises.
|
|
58172
|
+
*
|
|
58173
|
+
* Issue #2161 made six commands throw on `acquireLock` returning `false`
|
|
58174
|
+
* instead of running under a foreign lock. Issue #2170 is the follow-up: the
|
|
58175
|
+
* message those sites raise asked the user to decide "is another process
|
|
58176
|
+
* active?" while printing none of the evidence that would answer it, and the
|
|
58177
|
+
* recovery command it suggested could resolve against the wrong AWS account.
|
|
58178
|
+
*
|
|
58179
|
+
* Both matter more than they look, because of WHICH locks reach this message.
|
|
58180
|
+
* `LockManager.acquireLock` reaps an EXPIRED foreign lock and retries, so a
|
|
58181
|
+
* `false` return means the lock is LIVE — in practice a running `cdkd deploy`.
|
|
58182
|
+
* The user who follows a bare `cdkd force-unlock <stack>` suggestion therefore
|
|
58183
|
+
* deletes a live owner's lock and reproduces issue #2161's harm by hand, which
|
|
58184
|
+
* is the outcome #2161 exists to prevent.
|
|
58185
|
+
*
|
|
58186
|
+
* Centralising the text here also settles the third finding: the nine sites
|
|
58187
|
+
* had drifted to three spellings (`for stack` / `for nested stack` /
|
|
58188
|
+
* `for nested-stack child`), so a user grepping CI logs for one of them found
|
|
58189
|
+
* two of three. `subject` now varies only the noun.
|
|
58190
|
+
*/
|
|
58191
|
+
/**
|
|
58192
|
+
* Stand-in for a value with nothing renderable left after sanitization. Named
|
|
58193
|
+
* rather than inlined so the message and the command-suppression branch cannot
|
|
58194
|
+
* disagree about what "unrenderable" looks like.
|
|
58195
|
+
*/
|
|
58196
|
+
const UNRENDERABLE = "<unrenderable>";
|
|
58197
|
+
/** Render `expiresIn` without implying more precision than a clock skew allows. */
|
|
58198
|
+
function formatRemaining(ms) {
|
|
58199
|
+
if (!Number.isFinite(ms)) return "at an unknown time";
|
|
58200
|
+
if (ms <= 0) return "already expired";
|
|
58201
|
+
const minutes = Math.round(ms / 6e4);
|
|
58202
|
+
if (minutes < 1) return "in under a minute";
|
|
58203
|
+
return `in ~${minutes}m`;
|
|
58204
|
+
}
|
|
58205
|
+
function shellQuote(value) {
|
|
58206
|
+
return /^[A-Za-z0-9._/@:+-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
|
|
58207
|
+
}
|
|
58208
|
+
/**
|
|
58209
|
+
* The `cdkd force-unlock ...` line, carrying every flag that decides which
|
|
58210
|
+
* lock object it resolves to.
|
|
58211
|
+
*/
|
|
58212
|
+
function buildForceUnlockCommand(stackName, region, recovery) {
|
|
58213
|
+
const safeStack = displaySafe(stackName, { asciiOnly: true });
|
|
58214
|
+
const stackIsExact = safeStack === stackName;
|
|
58215
|
+
const safeRegion = region === void 0 ? void 0 : displaySafe(region, { asciiOnly: true });
|
|
58216
|
+
if (!safeStack || safeRegion === "" || !stackIsExact || !(region === void 0 || safeRegion === region)) return "";
|
|
58217
|
+
const parts = [safeRegion === void 0 ? `cdkd force-unlock ${shellQuote(safeStack)}` : `cdkd force-unlock ${shellQuote(safeStack)} --stack-region ${shellQuote(safeRegion)}`];
|
|
58218
|
+
if (recovery?.profile) parts.push(`--profile ${shellQuote(recovery.profile)}`);
|
|
58219
|
+
if (recovery?.stateBucket) parts.push(`--state-bucket ${shellQuote(recovery.stateBucket)}`);
|
|
58220
|
+
if (recovery?.statePrefix && recovery.statePrefix !== "cdkd") parts.push(`--state-prefix ${shellQuote(recovery.statePrefix)}`);
|
|
58221
|
+
return parts.join(" ");
|
|
58222
|
+
}
|
|
58223
|
+
/**
|
|
58224
|
+
* The force-quit banner's recovery sentence.
|
|
58225
|
+
*
|
|
58226
|
+
* Exported so the two `destroy-runner.ts` banners do not each decide what to
|
|
58227
|
+
* say when {@link buildForceUnlockCommand} suppresses — a banner ending in a
|
|
58228
|
+
* bare `run: ` is the shape the review found, and two copies of the branch is
|
|
58229
|
+
* how the next one drifts. Returns a leading-space clause so the caller can
|
|
58230
|
+
* concatenate it unconditionally.
|
|
58231
|
+
*/
|
|
58232
|
+
function forceQuitRecoveryClause(stackName, region, recovery) {
|
|
58233
|
+
const command = buildForceUnlockCommand(stackName, region, recovery);
|
|
58234
|
+
return command ? ` If the next run reports a lock, run: ${command}` : " Inspect the lock object directly: the name or region recorded for this stack cannot be reproduced safely on a command line, so any command shown here would address a different lock.";
|
|
58235
|
+
}
|
|
58236
|
+
/**
|
|
58237
|
+
* Build the contention message, reading the holder's identity best-effort.
|
|
58238
|
+
*
|
|
58239
|
+
* The `getLockInfo` read is one GetObject and is deliberately NOT allowed to
|
|
58240
|
+
* fail the command: the caller is already on its way to throwing, and turning
|
|
58241
|
+
* a contention refusal into an S3 error would lose the reason. A failed or
|
|
58242
|
+
* absent read degrades to the evidence-free wording rather than to a crash.
|
|
58243
|
+
*/
|
|
58244
|
+
async function buildLockContentionMessage(args) {
|
|
58245
|
+
const { lockManager, stackName, region, subject = "stack", recovery, heldClause, suffix } = args;
|
|
58246
|
+
let held = heldClause ?? "another cdkd process holds it";
|
|
58247
|
+
let sawHolder = false;
|
|
58248
|
+
try {
|
|
58249
|
+
const info = await lockManager.getLockInfo(stackName, region);
|
|
58250
|
+
if (info) {
|
|
58251
|
+
const operation = info.operation ? `, operation: ${displaySafe(info.operation)}` : "";
|
|
58252
|
+
const expires = formatRemaining(info.expiresAt - Date.now());
|
|
58253
|
+
const owner = displaySafe(info.owner);
|
|
58254
|
+
const holder = owner ? `held by ${owner}${operation}` : `held by an unnamed holder`;
|
|
58255
|
+
held = `${heldClause ? `${heldClause} — ` : ""}${holder}, expires ${expires}`;
|
|
58256
|
+
if (owner) sawHolder = true;
|
|
58257
|
+
}
|
|
58258
|
+
} catch {}
|
|
58259
|
+
const advice = sawHolder ? `That process is still running — wait for it to finish. Only if you are certain it is gone` : `Wait for it to finish, or if you are certain no other process is active`;
|
|
58260
|
+
const recoveryCommand = buildForceUnlockCommand(stackName, region, recovery);
|
|
58261
|
+
const head = `Could not acquire lock for ${subject} '${displaySafe(stackName, { asciiOnly: true }) || "<unrenderable>"}' (${displaySafe(region, { asciiOnly: true }) || "<unrenderable>"}) — ${held}.` + (suffix ? ` ${suffix}` : "");
|
|
58262
|
+
if (!recoveryCommand) return `${head} ${advice}. No recovery command can be shown: the name or region recorded for this lock contains characters that cannot be reproduced safely on a command line, so any command shown here would address a different lock — inspect the lock object directly.`;
|
|
58263
|
+
return `${head} ${advice}, run: ${recoveryCommand}`;
|
|
58264
|
+
}
|
|
58265
|
+
|
|
58165
58266
|
//#endregion
|
|
58166
58267
|
//#region src/cli/commands/destroy-runner.ts
|
|
58167
58268
|
/**
|
|
@@ -58298,9 +58399,64 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58298
58399
|
const regionForState = state.region ?? ctx.baseRegion;
|
|
58299
58400
|
if (resourceCount === 0) {
|
|
58300
58401
|
logger.info(`Stack ${stackName} has no resources, cleaning up state...`);
|
|
58301
|
-
|
|
58302
|
-
|
|
58402
|
+
let emptyLockHeld = false;
|
|
58403
|
+
let emptyInterrupted = false;
|
|
58404
|
+
const emptySigintHandler = () => {
|
|
58405
|
+
if (emptyInterrupted) {
|
|
58406
|
+
if (emptyLockHeld) {
|
|
58407
|
+
ctx.lockManager.releaseLock(stackName, regionForState).catch(() => {});
|
|
58408
|
+
process.stderr.write(`\nForce-quit: stack lock may not be released.${forceQuitRecoveryClause(stackName, regionForState, {
|
|
58409
|
+
profile: ctx.profile,
|
|
58410
|
+
stateBucket: ctx.stateBucket,
|
|
58411
|
+
statePrefix: ctx.statePrefix
|
|
58412
|
+
})}\n`);
|
|
58413
|
+
}
|
|
58414
|
+
process.exit(130);
|
|
58415
|
+
}
|
|
58416
|
+
emptyInterrupted = true;
|
|
58417
|
+
try {
|
|
58418
|
+
process.stderr.write(`\nInterrupt received - finishing the state cleanup for ${stackName} (press Ctrl-C again to force-quit)\n`);
|
|
58419
|
+
} catch {}
|
|
58420
|
+
};
|
|
58421
|
+
process.setMaxListeners(Math.max(process.getMaxListeners(), 100));
|
|
58422
|
+
process.on("SIGINT", emptySigintHandler);
|
|
58423
|
+
let emptyAcquired;
|
|
58424
|
+
try {
|
|
58425
|
+
emptyAcquired = await ctx.lockManager.acquireLock(stackName, regionForState, void 0, "destroy");
|
|
58426
|
+
} catch (acquireErr) {
|
|
58427
|
+
process.removeListener("SIGINT", emptySigintHandler);
|
|
58428
|
+
throw acquireErr;
|
|
58429
|
+
}
|
|
58430
|
+
if (!emptyAcquired) {
|
|
58431
|
+
process.removeListener("SIGINT", emptySigintHandler);
|
|
58432
|
+
throw new Error(await buildLockContentionMessage({
|
|
58433
|
+
lockManager: ctx.lockManager,
|
|
58434
|
+
stackName,
|
|
58435
|
+
region: regionForState,
|
|
58436
|
+
recovery: {
|
|
58437
|
+
profile: ctx.profile,
|
|
58438
|
+
stateBucket: ctx.stateBucket,
|
|
58439
|
+
statePrefix: ctx.statePrefix
|
|
58440
|
+
}
|
|
58441
|
+
}));
|
|
58442
|
+
}
|
|
58443
|
+
emptyLockHeld = true;
|
|
58444
|
+
try {
|
|
58445
|
+
const recheck = await ctx.stateBackend.getState(stackName, regionForState);
|
|
58446
|
+
if (!(!recheck || Object.keys(recheck.state.resources).length === 0)) throw new Error(`Stack '${stackName}' (${regionForState}) was empty when this run started but now has ${Object.keys(recheck.state.resources).length} resource(s) — another cdkd process deployed into it. Re-run the destroy to act on the current state.`);
|
|
58447
|
+
await ctx.stateBackend.deleteState(stackName, regionForState);
|
|
58448
|
+
logger.info(`${green("✓")} State deleted`);
|
|
58449
|
+
} finally {
|
|
58450
|
+
try {
|
|
58451
|
+
await ctx.lockManager.releaseLock(stackName, regionForState);
|
|
58452
|
+
} catch (releaseErr) {
|
|
58453
|
+
logger.warn(`Failed to release lock after empty-state cleanup: ${releaseErr instanceof Error ? releaseErr.message : String(releaseErr)}`);
|
|
58454
|
+
} finally {
|
|
58455
|
+
process.removeListener("SIGINT", emptySigintHandler);
|
|
58456
|
+
}
|
|
58457
|
+
}
|
|
58303
58458
|
result.skippedEmpty = true;
|
|
58459
|
+
result.interrupted ||= emptyInterrupted;
|
|
58304
58460
|
return result;
|
|
58305
58461
|
}
|
|
58306
58462
|
const needsStrongRefCheck = !!(state.outputs && Object.keys(state.outputs).length > 0);
|
|
@@ -58377,7 +58533,11 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58377
58533
|
if (draining) {
|
|
58378
58534
|
if (lockHeld) {
|
|
58379
58535
|
ctx.lockManager.releaseLock(stackName, regionForState).catch(() => {});
|
|
58380
|
-
process.stderr.write(`\nForce-quit: stack lock may not be released
|
|
58536
|
+
process.stderr.write(`\nForce-quit: stack lock may not be released.${forceQuitRecoveryClause(stackName, regionForState, {
|
|
58537
|
+
profile: ctx.profile,
|
|
58538
|
+
stateBucket: ctx.stateBucket,
|
|
58539
|
+
statePrefix: ctx.statePrefix
|
|
58540
|
+
})}\n`);
|
|
58381
58541
|
}
|
|
58382
58542
|
process.exit(130);
|
|
58383
58543
|
}
|
|
@@ -58390,7 +58550,16 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58390
58550
|
process.on("SIGINT", sigintHandler);
|
|
58391
58551
|
try {
|
|
58392
58552
|
logger.info(`\nAcquiring lock for stack ${stackName}...`);
|
|
58393
|
-
if (!await ctx.lockManager.acquireLock(stackName, regionForState, void 0, "destroy")) throw new Error(
|
|
58553
|
+
if (!await ctx.lockManager.acquireLock(stackName, regionForState, void 0, "destroy")) throw new Error(await buildLockContentionMessage({
|
|
58554
|
+
lockManager: ctx.lockManager,
|
|
58555
|
+
stackName,
|
|
58556
|
+
region: regionForState,
|
|
58557
|
+
recovery: {
|
|
58558
|
+
profile: ctx.profile,
|
|
58559
|
+
stateBucket: ctx.stateBucket,
|
|
58560
|
+
statePrefix: ctx.statePrefix
|
|
58561
|
+
}
|
|
58562
|
+
}));
|
|
58394
58563
|
} catch (error) {
|
|
58395
58564
|
restoreBaseRegionAndClients();
|
|
58396
58565
|
process.removeListener("SIGINT", sigintHandler);
|
|
@@ -58984,6 +59153,7 @@ var NestedStackProvider = class {
|
|
|
58984
59153
|
skipConfirmation: true,
|
|
58985
59154
|
...ctx.exportIndexStore && { exportIndexStore: ctx.exportIndexStore },
|
|
58986
59155
|
...ctx.destroyOptions?.profile && { profile: ctx.destroyOptions.profile },
|
|
59156
|
+
...ctx.destroyOptions?.statePrefix !== void 0 && { statePrefix: ctx.destroyOptions.statePrefix },
|
|
58987
59157
|
...deleteContext?.removeProtection === true && { removeProtection: true },
|
|
58988
59158
|
...(ctx.destroyOptions?.skipFinalSnapshot === true || ctx.options?.skipFinalSnapshot === true) && { skipFinalSnapshot: true },
|
|
58989
59159
|
...ctx.destroyOptions?.resourceWarnAfterMs !== void 0 && { resourceWarnAfterMs: ctx.destroyOptions.resourceWarnAfterMs },
|
|
@@ -59905,7 +60075,7 @@ async function deployCommand(stacks, options) {
|
|
|
59905
60075
|
let deployInterrupted = false;
|
|
59906
60076
|
const topLevelSigintHandler = () => {
|
|
59907
60077
|
if (deployInterrupted) {
|
|
59908
|
-
process.stderr.write("\nForce-quit: stack locks may not be released. If the next run reports a lock, run: cdkd force-unlock <stackName>\n");
|
|
60078
|
+
process.stderr.write("\nForce-quit: stack locks may not be released. If the next run reports a lock, run this for EACH stack it names (the region-qualified form — see the message that run prints): cdkd force-unlock <stackName> --stack-region <region>\n");
|
|
59909
60079
|
process.exit(130);
|
|
59910
60080
|
}
|
|
59911
60081
|
process.stderr.write("\nInterrupted — waiting for in-progress operations to complete...\n");
|
|
@@ -60172,6 +60342,10 @@ async function deployCommand(stacks, options) {
|
|
|
60172
60342
|
dagBuilder,
|
|
60173
60343
|
diffCalculator,
|
|
60174
60344
|
options: deployEngineOptions,
|
|
60345
|
+
destroyOptions: {
|
|
60346
|
+
statePrefix: options.statePrefix,
|
|
60347
|
+
...options.profile && { profile: options.profile }
|
|
60348
|
+
},
|
|
60175
60349
|
...assetRedirect && { assetRedirect }
|
|
60176
60350
|
}, () => stackDeployEngine.deploy(stackInfo.stackName, stackInfo.template));
|
|
60177
60351
|
logger.info(`\n${bold("Deployment Summary:")}`);
|
|
@@ -66142,6 +66316,11 @@ function setAtPath(target, path, value) {
|
|
|
66142
66316
|
*/
|
|
66143
66317
|
async function runAccept(reports, stateBackend, stateConfig, awsClients, options) {
|
|
66144
66318
|
const logger = getLogger();
|
|
66319
|
+
const lockRecovery = {
|
|
66320
|
+
profile: options.profile,
|
|
66321
|
+
stateBucket: stateConfig.bucket,
|
|
66322
|
+
statePrefix: stateConfig.prefix
|
|
66323
|
+
};
|
|
66145
66324
|
printAcceptPlan(reports);
|
|
66146
66325
|
if (options.dryRun) {
|
|
66147
66326
|
logger.info("--dry-run: state will NOT be written. Re-run without --dry-run to apply.");
|
|
@@ -66164,7 +66343,12 @@ async function runAccept(reports, stateBackend, stateConfig, awsClients, options
|
|
|
66164
66343
|
skipped: () => []
|
|
66165
66344
|
}));
|
|
66166
66345
|
if (driftedOutcomes.length === 0) continue;
|
|
66167
|
-
if (!await lockManager.acquireLock(report.stackName, report.region, owner, "drift-accept")) throw new Error(
|
|
66346
|
+
if (!await lockManager.acquireLock(report.stackName, report.region, owner, "drift-accept")) throw new Error(await buildLockContentionMessage({
|
|
66347
|
+
lockManager,
|
|
66348
|
+
stackName: report.stackName,
|
|
66349
|
+
region: report.region,
|
|
66350
|
+
recovery: lockRecovery
|
|
66351
|
+
}));
|
|
66168
66352
|
try {
|
|
66169
66353
|
const resources = { ...report.state.resources };
|
|
66170
66354
|
for (const outcome of driftedOutcomes) {
|
|
@@ -66761,6 +66945,11 @@ function deepEqualUnordered(a, b) {
|
|
|
66761
66945
|
*/
|
|
66762
66946
|
async function runRevert(reports, providerRegistry, stateBackend, stateConfig, awsClients, options) {
|
|
66763
66947
|
const logger = getLogger();
|
|
66948
|
+
const lockRecovery = {
|
|
66949
|
+
profile: options.profile,
|
|
66950
|
+
stateBucket: stateConfig.bucket,
|
|
66951
|
+
statePrefix: stateConfig.prefix
|
|
66952
|
+
};
|
|
66764
66953
|
printRevertPlan(reports);
|
|
66765
66954
|
if (options.dryRun) {
|
|
66766
66955
|
logger.info("--dry-run: AWS will NOT be modified. Re-run without --dry-run to apply.");
|
|
@@ -66788,11 +66977,16 @@ async function runRevert(reports, providerRegistry, stateBackend, stateConfig, a
|
|
|
66788
66977
|
skipped: () => []
|
|
66789
66978
|
}));
|
|
66790
66979
|
if (driftedOutcomes.length === 0) continue;
|
|
66791
|
-
if (!await lockManager.acquireLock(report.stackName, report.region, owner, "drift-revert")) throw new Error(
|
|
66980
|
+
if (!await lockManager.acquireLock(report.stackName, report.region, owner, "drift-revert")) throw new Error(await buildLockContentionMessage({
|
|
66981
|
+
lockManager,
|
|
66982
|
+
stackName: report.stackName,
|
|
66983
|
+
region: report.region,
|
|
66984
|
+
recovery: lockRecovery
|
|
66985
|
+
}));
|
|
66792
66986
|
const narrowedByLogicalId = /* @__PURE__ */ new Map();
|
|
66793
|
-
const revertSecretResolvers = new DriftSecretResolvers(report.region);
|
|
66794
|
-
const revertProducerRegions = producerRegionsFromState(report.state);
|
|
66795
66987
|
try {
|
|
66988
|
+
const revertSecretResolvers = new DriftSecretResolvers(report.region);
|
|
66989
|
+
const revertProducerRegions = producerRegionsFromState(report.state);
|
|
66796
66990
|
await runWithConcurrency(driftedOutcomes.map((outcome) => async () => {
|
|
66797
66991
|
const stateResource = report.state.resources[outcome.logicalId];
|
|
66798
66992
|
if (!stateResource) {
|
|
@@ -67415,6 +67609,7 @@ async function destroyCommand(stackArgs, options) {
|
|
|
67415
67609
|
exportIndexStore,
|
|
67416
67610
|
destroyOptions: {
|
|
67417
67611
|
...options.profile && { profile: options.profile },
|
|
67612
|
+
statePrefix: options.statePrefix,
|
|
67418
67613
|
...options.removeProtection === true && { removeProtection: true },
|
|
67419
67614
|
...options.skipFinalSnapshot === true && { skipFinalSnapshot: true },
|
|
67420
67615
|
...options.resourceWarnAfter?.globalMs !== void 0 && { resourceWarnAfterMs: options.resourceWarnAfter.globalMs },
|
|
@@ -67430,6 +67625,7 @@ async function destroyCommand(stackArgs, options) {
|
|
|
67430
67625
|
baseRegion: region,
|
|
67431
67626
|
...options.profile && { profile: options.profile },
|
|
67432
67627
|
stateBucket,
|
|
67628
|
+
statePrefix: options.statePrefix,
|
|
67433
67629
|
skipConfirmation: options.yes || options.force,
|
|
67434
67630
|
removeProtection: options.removeProtection === true,
|
|
67435
67631
|
skipFinalSnapshot: options.skipFinalSnapshot === true,
|
|
@@ -69003,6 +69199,11 @@ async function exportCommand(stackArg, options) {
|
|
|
69003
69199
|
bucket: stateBucket,
|
|
69004
69200
|
prefix: options.statePrefix
|
|
69005
69201
|
};
|
|
69202
|
+
const lockRecovery = {
|
|
69203
|
+
profile: options.profile,
|
|
69204
|
+
stateBucket,
|
|
69205
|
+
statePrefix: options.statePrefix
|
|
69206
|
+
};
|
|
69006
69207
|
const stateBackend = new S3StateBackend(awsClients.s3, stateConfig, {
|
|
69007
69208
|
...options.region && { region: options.region },
|
|
69008
69209
|
...options.profile && { profile: options.profile }
|
|
@@ -69078,7 +69279,12 @@ async function exportCommand(stackArg, options) {
|
|
|
69078
69279
|
}
|
|
69079
69280
|
const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
|
|
69080
69281
|
if (!options.dryRun) {
|
|
69081
|
-
if (!await lockManager.acquireLock(resolvedStackName, targetRegion, owner, "export")) throw new Error(
|
|
69282
|
+
if (!await lockManager.acquireLock(resolvedStackName, targetRegion, owner, "export")) throw new Error(await buildLockContentionMessage({
|
|
69283
|
+
lockManager,
|
|
69284
|
+
stackName: resolvedStackName,
|
|
69285
|
+
region: targetRegion,
|
|
69286
|
+
recovery: lockRecovery
|
|
69287
|
+
}));
|
|
69082
69288
|
}
|
|
69083
69289
|
try {
|
|
69084
69290
|
if (nestedStackRows.length > 0) {
|
|
@@ -69098,6 +69304,7 @@ async function exportCommand(stackArg, options) {
|
|
|
69098
69304
|
if (missingNested.length > 0) throw new Error(`Template requires parameter(s) without defaults: ${missingNested.join(", ")}. Pass each one as --parameter Key=Value (or set a Default in the CDK code).`);
|
|
69099
69305
|
const childOverrides = parseCfnChildStackNameOverrides(options.cfnChildStackName);
|
|
69100
69306
|
if ((await runPerStackImportLoop({
|
|
69307
|
+
lockRecovery,
|
|
69101
69308
|
rootStackName: resolvedStackName,
|
|
69102
69309
|
rootRegion: targetRegion,
|
|
69103
69310
|
rootStackInfoNestedTemplates: rootNestedTemplatePaths,
|
|
@@ -70994,7 +71201,15 @@ async function runPerStackImportLoop(args) {
|
|
|
70994
71201
|
try {
|
|
70995
71202
|
await deps.lockManager.acquireLockWithRetry(node.stackName, node.region, deps.lockOwner, "export", CHILD_LOCK_RETRY_MAX_ATTEMPTS, CHILD_LOCK_RETRY_DELAY_MS);
|
|
70996
71203
|
} catch (err) {
|
|
70997
|
-
throw new Error(
|
|
71204
|
+
throw new Error(await buildLockContentionMessage({
|
|
71205
|
+
lockManager: deps.lockManager,
|
|
71206
|
+
stackName: node.stackName,
|
|
71207
|
+
region: node.region,
|
|
71208
|
+
subject: "nested-stack child",
|
|
71209
|
+
heldClause: "another cdkd process held it through the retry window",
|
|
71210
|
+
recovery: args.lockRecovery,
|
|
71211
|
+
suffix: "No CloudFormation changeset has been submitted; cdkd state is unchanged."
|
|
71212
|
+
}), { cause: err instanceof Error ? err : void 0 });
|
|
70998
71213
|
}
|
|
70999
71214
|
acquiredChildLocks.push({
|
|
71000
71215
|
stackName: node.stackName,
|
|
@@ -71930,8 +72145,12 @@ async function stateOrphanCommand(stackArgs, options) {
|
|
|
71930
72145
|
}
|
|
71931
72146
|
if (!options.force) {
|
|
71932
72147
|
for (const target of targets) if (await setup.lockManager.isLocked(stackName, target.region)) {
|
|
71933
|
-
const where = target.region
|
|
71934
|
-
throw new Error(`Stack '${stackName}' (${where}) is locked. Run
|
|
72148
|
+
const where = target.region ? displaySafe(target.region, { asciiOnly: true }) || "<unrenderable>" : "(legacy)";
|
|
72149
|
+
throw new Error(`Stack '${displaySafe(stackName, { asciiOnly: true })}' (${where}) is locked. Run: ${buildForceUnlockCommand(stackName, target.region, {
|
|
72150
|
+
profile: options.profile,
|
|
72151
|
+
stateBucket: setup.bucket,
|
|
72152
|
+
statePrefix: options.statePrefix
|
|
72153
|
+
}) || "a command cdkd cannot show safely: the recorded name or region would not survive a command line intact, so inspect the lock object directly"} first, or pass --force to remove anyway.`);
|
|
71935
72154
|
}
|
|
71936
72155
|
}
|
|
71937
72156
|
if (!options.yes && !options.force) {
|
|
@@ -71951,9 +72170,13 @@ async function stateOrphanCommand(stackArgs, options) {
|
|
|
71951
72170
|
}
|
|
71952
72171
|
for (const target of targets) {
|
|
71953
72172
|
if (target.region) {
|
|
72173
|
+
await warnOnLiveForeignLock(setup.lockManager, stackName, target.region, logger);
|
|
71954
72174
|
await setup.stateBackend.deleteState(stackName, target.region);
|
|
71955
72175
|
await setup.lockManager.forceReleaseLock(stackName, target.region);
|
|
71956
|
-
} else
|
|
72176
|
+
} else {
|
|
72177
|
+
await warnOnLiveForeignLock(setup.lockManager, stackName, void 0, logger);
|
|
72178
|
+
await setup.lockManager.forceReleaseLock(stackName, void 0);
|
|
72179
|
+
}
|
|
71957
72180
|
logger.info(`✓ Removed state for stack: ${formatStackRef(target)}`);
|
|
71958
72181
|
}
|
|
71959
72182
|
}
|
|
@@ -72085,6 +72308,7 @@ async function stateDestroyCommand(stackArgs, options) {
|
|
|
72085
72308
|
exportIndexStore: setup.exportIndexStore,
|
|
72086
72309
|
destroyOptions: {
|
|
72087
72310
|
...options.profile && { profile: options.profile },
|
|
72311
|
+
statePrefix: options.statePrefix,
|
|
72088
72312
|
...options.removeProtection === true && { removeProtection: true },
|
|
72089
72313
|
...options.skipFinalSnapshot === true && { skipFinalSnapshot: true },
|
|
72090
72314
|
...options.resourceWarnAfter?.globalMs !== void 0 && { resourceWarnAfterMs: options.resourceWarnAfter.globalMs },
|
|
@@ -72100,6 +72324,7 @@ async function stateDestroyCommand(stackArgs, options) {
|
|
|
72100
72324
|
baseRegion: setup.region,
|
|
72101
72325
|
...options.profile && { profile: options.profile },
|
|
72102
72326
|
stateBucket: setup.bucket,
|
|
72327
|
+
statePrefix: options.statePrefix,
|
|
72103
72328
|
skipConfirmation: options.yes || options.all === true,
|
|
72104
72329
|
removeProtection: options.removeProtection === true,
|
|
72105
72330
|
skipFinalSnapshot: options.skipFinalSnapshot === true,
|
|
@@ -72461,7 +72686,12 @@ async function stateRefreshObservedCommand(stackArgs, options) {
|
|
|
72461
72686
|
if (!target.region) throw new Error(`Stack '${target.stackName}' has only a legacy state record without a region. Run 'cdkd deploy ${target.stackName}' (or any cdkd write) first to migrate it to the region-scoped layout, then re-run refresh-observed.`);
|
|
72462
72687
|
const counts = await refreshObservedForStack(target.stackName, target.region, setup.stateBackend, setup.lockManager, providerRegistry, {
|
|
72463
72688
|
dryRun: options.dryRun ?? false,
|
|
72464
|
-
logger
|
|
72689
|
+
logger,
|
|
72690
|
+
lockRecovery: {
|
|
72691
|
+
profile: options.profile,
|
|
72692
|
+
stateBucket: setup.bucket,
|
|
72693
|
+
statePrefix: options.statePrefix
|
|
72694
|
+
}
|
|
72465
72695
|
});
|
|
72466
72696
|
totalRefreshed += counts.refreshed;
|
|
72467
72697
|
totalUnsupported += counts.unsupported;
|
|
@@ -72488,6 +72718,34 @@ async function stateRefreshObservedCommand(stackArgs, options) {
|
|
|
72488
72718
|
*/
|
|
72489
72719
|
const NO_RECORDED_SECRETS = /* @__PURE__ */ new Map();
|
|
72490
72720
|
/**
|
|
72721
|
+
* Warn before `cdkd state orphan` force-releases a lock that is still LIVE.
|
|
72722
|
+
*
|
|
72723
|
+
* `forceReleaseLock` is unconditional by design — a stuck lock must never make
|
|
72724
|
+
* a state record unremovable — but it deletes an in-flight `cdkd deploy`'s lock
|
|
72725
|
+
* just as readily as a stale one, and it did so silently (issue #2171). The
|
|
72726
|
+
* write it enables has already happened by the time anyone notices, so the
|
|
72727
|
+
* only useful thing is to name the owner at the moment of the release.
|
|
72728
|
+
*
|
|
72729
|
+
* Best-effort in both directions: an expired lock is not worth a line, and a
|
|
72730
|
+
* failed read must not block the removal the user asked for.
|
|
72731
|
+
*
|
|
72732
|
+
* (Issue #2171's own text called this command `cdkd state rm`; no such command
|
|
72733
|
+
* exists -- this file registers it as `orphan`.)
|
|
72734
|
+
*/
|
|
72735
|
+
async function warnOnLiveForeignLock(lockManager, stackName, region, logger) {
|
|
72736
|
+
try {
|
|
72737
|
+
const info = await lockManager.getLockInfo(stackName, region);
|
|
72738
|
+
if (!info) return;
|
|
72739
|
+
const expiryKnown = Number.isFinite(info.expiresAt);
|
|
72740
|
+
if (expiryKnown && info.expiresAt <= Date.now()) return;
|
|
72741
|
+
const safeStack = displaySafe(stackName, { asciiOnly: true }) || "<unrenderable>";
|
|
72742
|
+
const where = region ? `${safeStack} (${displaySafe(region, { asciiOnly: true }) || "<unrenderable>"})` : `${safeStack} (legacy lock key)`;
|
|
72743
|
+
const owner = info.owner;
|
|
72744
|
+
const operation = info.operation ? `, operation: ${info.operation}` : "";
|
|
72745
|
+
logger.warn(`Force-releasing a LIVE lock on ${where} ${owner ? `held by ${owner}${operation}` : "held by an unnamed holder"}. ` + (owner && expiryKnown ? `That process is still running and will keep writing; its next state write ` : expiryKnown ? `The lock has not expired, so a process may still be writing; its next state write ` : `The lock records no readable expiry, so a process may still be writing; its next state write `) + `may recreate the record being removed here.`);
|
|
72746
|
+
} catch {}
|
|
72747
|
+
}
|
|
72748
|
+
/**
|
|
72491
72749
|
* Refresh the `observedProperties` of every resource in one stack
|
|
72492
72750
|
* record. Returns counts so the caller can aggregate across `--all`.
|
|
72493
72751
|
*
|
|
@@ -72497,7 +72755,7 @@ const NO_RECORDED_SECRETS = /* @__PURE__ */ new Map();
|
|
|
72497
72755
|
* for the underlying SDK reads.
|
|
72498
72756
|
*/
|
|
72499
72757
|
async function refreshObservedForStack(stackName, region, stateBackend, lockManager, providerRegistry, opts) {
|
|
72500
|
-
const { logger } = opts;
|
|
72758
|
+
const { logger, lockRecovery } = opts;
|
|
72501
72759
|
const result = await stateBackend.getState(stackName, region);
|
|
72502
72760
|
if (!result) throw new Error(`No state found for stack '${stackName}' (${region}). Run 'cdkd state list' to see available stacks.`);
|
|
72503
72761
|
const { state, etag, migrationPending } = result;
|
|
@@ -72535,7 +72793,12 @@ async function refreshObservedForStack(stackName, region, stateBackend, lockMana
|
|
|
72535
72793
|
};
|
|
72536
72794
|
}
|
|
72537
72795
|
const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
|
|
72538
|
-
if (!await lockManager.acquireLock(stackName, region, owner, "state-refresh-observed")) throw new Error(
|
|
72796
|
+
if (!await lockManager.acquireLock(stackName, region, owner, "state-refresh-observed")) throw new Error(await buildLockContentionMessage({
|
|
72797
|
+
lockManager,
|
|
72798
|
+
stackName,
|
|
72799
|
+
region,
|
|
72800
|
+
recovery: lockRecovery
|
|
72801
|
+
}));
|
|
72539
72802
|
try {
|
|
72540
72803
|
let refreshed = 0;
|
|
72541
72804
|
let unsupported = 0;
|
|
@@ -72878,7 +73141,10 @@ async function rollbackCommand(stackArg, options) {
|
|
|
72878
73141
|
awsClients: setup.awsClients,
|
|
72879
73142
|
stateBucket: setup.bucket,
|
|
72880
73143
|
exportIndexStore: setup.exportIndexStore,
|
|
72881
|
-
destroyOptions: {
|
|
73144
|
+
destroyOptions: {
|
|
73145
|
+
...options.profile && { profile: options.profile },
|
|
73146
|
+
statePrefix: options.statePrefix
|
|
73147
|
+
}
|
|
72882
73148
|
}, () => withStackName(stackName, async () => {
|
|
72883
73149
|
let failedOpFailures = 0;
|
|
72884
73150
|
let failedOpWarnings = 0;
|
|
@@ -74915,7 +75181,16 @@ async function orphanCommand(pathArgs, options) {
|
|
|
74915
75181
|
logger.info(`Target: ${stackInfo.stackName} (${targetRegion}); orphaning ${orphanLogicalIds.length} resource(s): ${orphanLogicalIds.join(", ")}`);
|
|
74916
75182
|
const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
|
|
74917
75183
|
if (!options.dryRun) {
|
|
74918
|
-
if (!await lockManager.acquireLock(stackInfo.stackName, targetRegion, owner, "orphan")) throw new Error(
|
|
75184
|
+
if (!await lockManager.acquireLock(stackInfo.stackName, targetRegion, owner, "orphan")) throw new Error(await buildLockContentionMessage({
|
|
75185
|
+
lockManager,
|
|
75186
|
+
stackName: stackInfo.stackName,
|
|
75187
|
+
region: targetRegion,
|
|
75188
|
+
recovery: {
|
|
75189
|
+
profile: options.profile,
|
|
75190
|
+
stateBucket,
|
|
75191
|
+
statePrefix: options.statePrefix
|
|
75192
|
+
}
|
|
75193
|
+
}));
|
|
74919
75194
|
}
|
|
74920
75195
|
try {
|
|
74921
75196
|
const stateData = await stateBackend.getState(stackInfo.stackName, targetRegion);
|
|
@@ -75401,6 +75676,11 @@ async function importCommand(stackArg, options) {
|
|
|
75401
75676
|
bucket: stateBucket,
|
|
75402
75677
|
prefix: options.statePrefix
|
|
75403
75678
|
};
|
|
75679
|
+
const lockRecovery = {
|
|
75680
|
+
profile: options.profile,
|
|
75681
|
+
stateBucket,
|
|
75682
|
+
statePrefix: options.statePrefix
|
|
75683
|
+
};
|
|
75404
75684
|
const stateBackend = new S3StateBackend(awsClients.s3, stateConfig, {
|
|
75405
75685
|
...options.region && { region: options.region },
|
|
75406
75686
|
...options.profile && { profile: options.profile }
|
|
@@ -75501,7 +75781,16 @@ async function importCommand(stackArg, options) {
|
|
|
75501
75781
|
}
|
|
75502
75782
|
for (const overrideId of overrides.keys()) if (!templateLogicalIds.has(overrideId)) throw new Error(`--resource / --resource-mapping references logical ID '${overrideId}' which is not in the synthesized template for stack '${stackInfo.stackName}'. Available IDs: ${[...templateLogicalIds].join(", ")}`);
|
|
75503
75783
|
const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
|
|
75504
|
-
if (!await lockManager.acquireLock(stackInfo.stackName, targetRegion, owner, "import")) throw new Error(
|
|
75784
|
+
if (!await lockManager.acquireLock(stackInfo.stackName, targetRegion, owner, "import")) throw new Error(await buildLockContentionMessage({
|
|
75785
|
+
lockManager,
|
|
75786
|
+
stackName: stackInfo.stackName,
|
|
75787
|
+
region: targetRegion,
|
|
75788
|
+
recovery: {
|
|
75789
|
+
profile: options.profile,
|
|
75790
|
+
stateBucket,
|
|
75791
|
+
statePrefix: options.statePrefix
|
|
75792
|
+
}
|
|
75793
|
+
}));
|
|
75505
75794
|
try {
|
|
75506
75795
|
const rows = [];
|
|
75507
75796
|
for (const { logicalId, resource } of resources) {
|
|
@@ -75565,6 +75854,7 @@ async function importCommand(stackArg, options) {
|
|
|
75565
75854
|
logger.info(`✓ State written: ${stackInfo.stackName} (${targetRegion})`);
|
|
75566
75855
|
logger.info(` ${importedRows.length} resource(s) imported. Run 'cdkd diff' to see how the imported state lines up with the template.`);
|
|
75567
75856
|
if (migrationCfnStackName && migrationTree && accountIdForNestedSynth) await importNestedStackChildrenRecursive({
|
|
75857
|
+
lockRecovery,
|
|
75568
75858
|
parentStackName: stackInfo.stackName,
|
|
75569
75859
|
parentRegion: targetRegion,
|
|
75570
75860
|
parentNestedTemplates: stackInfo.nestedTemplates ?? {},
|
|
@@ -76230,7 +76520,13 @@ async function importNestedStackChildrenRecursive(args) {
|
|
|
76230
76520
|
const childRewritten = rewriteTemplateAssetReferences(childTemplate, assetRedirect);
|
|
76231
76521
|
if (childRewritten > 0) logger.info(`Note: ${childRewritten} asset reference(s) in nested stack ${childStackName} are recorded in state at their pre-rewrite (CDK bootstrap) values, so the next 'cdkd deploy' repoints any resource that still holds them to cdkd asset storage.`);
|
|
76232
76522
|
}
|
|
76233
|
-
if (!await lockManager.acquireLock(childStackName, childRegion, lockOwner, "import")) throw new Error(
|
|
76523
|
+
if (!await lockManager.acquireLock(childStackName, childRegion, lockOwner, "import")) throw new Error(await buildLockContentionMessage({
|
|
76524
|
+
lockManager,
|
|
76525
|
+
stackName: childStackName,
|
|
76526
|
+
region: childRegion,
|
|
76527
|
+
subject: "nested stack",
|
|
76528
|
+
recovery: args.lockRecovery
|
|
76529
|
+
}));
|
|
76234
76530
|
try {
|
|
76235
76531
|
const childResources = collectImportableResources(childTemplate);
|
|
76236
76532
|
const childTemplateLogicalIds = new Set(childResources.map((r) => r.logicalId));
|
|
@@ -76272,6 +76568,7 @@ async function importNestedStackChildrenRecursive(args) {
|
|
|
76272
76568
|
await stateBackend.saveState(childStackName, childRegion, childStackState);
|
|
76273
76569
|
logger.info(`✓ Nested stack state written: ${childStackName} (${childRegion}) — ${rows.filter((r) => r.outcome === "imported").length} resource(s) imported.`);
|
|
76274
76570
|
if (childTreeNode.nested.size > 0) await importNestedStackChildrenRecursive({
|
|
76571
|
+
lockRecovery: args.lockRecovery,
|
|
76275
76572
|
parentStackName: childStackName,
|
|
76276
76573
|
parentRegion: childRegion,
|
|
76277
76574
|
parentNestedTemplates: indexGrandchildTemplatePaths(childTemplate, childTemplatePath),
|
|
@@ -86145,7 +86442,7 @@ function createMigrateCommand() {
|
|
|
86145
86442
|
*/
|
|
86146
86443
|
function buildProgram() {
|
|
86147
86444
|
const program = new Command();
|
|
86148
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.
|
|
86445
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.39");
|
|
86149
86446
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
86150
86447
|
const { profile } = actionCommand.optsWithGlobals();
|
|
86151
86448
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|