@go-to-k/cdkd 0.229.8 → 0.230.1
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/cli.js +46 -126
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-rMH9694Q.js → deploy-engine-_N5kVjZN.js} +144 -4
- package/dist/deploy-engine-_N5kVjZN.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-rMH9694Q.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as SynthesisError, F as getLiveRenderer, M as getLogger, T as StateError, U as withStackName, V as generateResourceNameWithFallback, a as assertRegionMatch, b as ProvisioningError, c as AssetError, d as DependencyError, g as MacroExpansionError, h as LockError, i as resolveExplicitPhysicalId, k as normalizeAwsError, n as matchesCdkPath, o as disableInstanceApiTermination, r as normalizeAwsTagsToCfn, s as isTerminationProtectionPropagationError, x as ResourceTimeoutError, z as applyDefaultNameForFallback } from "./import-helpers-DayvBD4T.js";
|
|
1
|
+
import { E as SynthesisError, F as getLiveRenderer, M as getLogger, S as ResourceUpdateNotSupportedError, T as StateError, U as withStackName, V as generateResourceNameWithFallback, a as assertRegionMatch, b as ProvisioningError, c as AssetError, d as DependencyError, g as MacroExpansionError, h as LockError, i as resolveExplicitPhysicalId, k as normalizeAwsError, l as CdkdError, n as matchesCdkPath, o as disableInstanceApiTermination, r as normalizeAwsTagsToCfn, s as isTerminationProtectionPropagationError, x as ResourceTimeoutError, z as applyDefaultNameForFallback } from "./import-helpers-DayvBD4T.js";
|
|
2
2
|
import { r as getAwsClients } from "./aws-clients-pjPwZz1r.js";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -11669,6 +11669,140 @@ function formatResourceLine(op, logicalId, resourceType, verbOverride) {
|
|
|
11669
11669
|
}
|
|
11670
11670
|
}
|
|
11671
11671
|
|
|
11672
|
+
//#endregion
|
|
11673
|
+
//#region src/provisioning/stateful-types.ts
|
|
11674
|
+
/**
|
|
11675
|
+
* Stateful-resource guard list (issue [#615]).
|
|
11676
|
+
*
|
|
11677
|
+
* `--recreate-via-cc-api <LogicalId>` destroys + recreates the named
|
|
11678
|
+
* resource in one deploy so a previously-silent-dropped top-level CFn
|
|
11679
|
+
* property reaches AWS via Cloud Control API. For most types this is
|
|
11680
|
+
* safe — destroying + recreating an IAM Role or a Lambda Function
|
|
11681
|
+
* loses no user data — but for **data-bearing** types the destroy
|
|
11682
|
+
* cycle loses everything in the resource: rows in a DynamoDB table,
|
|
11683
|
+
* objects in an S3 bucket, log lines in a LogGroup, images in an ECR
|
|
11684
|
+
* repository, etc.
|
|
11685
|
+
*
|
|
11686
|
+
* To avoid an accidental data-loss footgun, cdkd refuses to recreate
|
|
11687
|
+
* any resource whose type is in {@link STATEFUL_TYPES} unless the user
|
|
11688
|
+
* ALSO passes `--force-stateful-recreation`. The two-flag protection
|
|
11689
|
+
* mirrors `--remove-protection`'s pattern (see
|
|
11690
|
+
* `src/cli/commands/destroy-runner.ts`).
|
|
11691
|
+
*
|
|
11692
|
+
* The list is hand-curated and intentionally **conservative**: every
|
|
11693
|
+
* type here carries user data that the AWS service does NOT
|
|
11694
|
+
* automatically migrate to the replacement resource. Types that the
|
|
11695
|
+
* AWS service treats as ephemeral (e.g. Lambda Function, IAM Role)
|
|
11696
|
+
* are NOT in this list — recreate is cheap.
|
|
11697
|
+
*
|
|
11698
|
+
* Two entries are **conditionally stateful** — they only count when
|
|
11699
|
+
* the resource actually contains data:
|
|
11700
|
+
*
|
|
11701
|
+
* - `AWS::S3::Bucket`: empty buckets are safe to recreate. The
|
|
11702
|
+
* deploy engine probes `s3:ListObjectsV2` at plan time and only
|
|
11703
|
+
* refuses when the bucket has at least one object.
|
|
11704
|
+
* - `AWS::Logs::LogGroup`: a log group with `RetentionInDays`
|
|
11705
|
+
* undefined or zero is functionally ephemeral. The deploy engine
|
|
11706
|
+
* refuses only when `RetentionInDays > 0`.
|
|
11707
|
+
*
|
|
11708
|
+
* Both conditional checks live in {@link isStatefulRecreateTarget};
|
|
11709
|
+
* the bare {@link STATEFUL_TYPES} set is the type-only first-cut.
|
|
11710
|
+
*/
|
|
11711
|
+
const STATEFUL_TYPES = new Set([
|
|
11712
|
+
"AWS::RDS::DBInstance",
|
|
11713
|
+
"AWS::RDS::DBCluster",
|
|
11714
|
+
"AWS::DocDB::DBInstance",
|
|
11715
|
+
"AWS::DocDB::DBCluster",
|
|
11716
|
+
"AWS::Neptune::DBInstance",
|
|
11717
|
+
"AWS::Neptune::DBCluster",
|
|
11718
|
+
"AWS::DynamoDB::Table",
|
|
11719
|
+
"AWS::DynamoDB::GlobalTable",
|
|
11720
|
+
"AWS::EFS::FileSystem",
|
|
11721
|
+
"AWS::S3::Bucket",
|
|
11722
|
+
"AWS::ECR::Repository",
|
|
11723
|
+
"AWS::Kinesis::Stream",
|
|
11724
|
+
"AWS::Elasticsearch::Domain",
|
|
11725
|
+
"AWS::OpenSearchService::Domain",
|
|
11726
|
+
"AWS::Cognito::UserPool",
|
|
11727
|
+
"AWS::SecretsManager::Secret",
|
|
11728
|
+
"AWS::SSM::Parameter",
|
|
11729
|
+
"AWS::Glue::Database",
|
|
11730
|
+
"AWS::Glue::Table",
|
|
11731
|
+
"AWS::Logs::LogGroup",
|
|
11732
|
+
"AWS::CloudFront::Distribution"
|
|
11733
|
+
]);
|
|
11734
|
+
/**
|
|
11735
|
+
* Multi-region resource types — `--recreate-via-cc-api` refuses these
|
|
11736
|
+
* outright in v1 regardless of `--force-stateful-recreation`. Design
|
|
11737
|
+
* doc §8 calls these "out of scope": the destroy + recreate cycle
|
|
11738
|
+
* across replica regions is more involved than a single-region
|
|
11739
|
+
* destroy-and-create (replica regions, automated backups, eventual
|
|
11740
|
+
* consistency across the replication mesh, etc.).
|
|
11741
|
+
*
|
|
11742
|
+
* Distinct from {@link STATEFUL_TYPES} — STATEFUL_TYPES gates on data
|
|
11743
|
+
* loss (bypassable with `--force-stateful-recreation`); this set is
|
|
11744
|
+
* an out-of-scope refusal (no bypass).
|
|
11745
|
+
*/
|
|
11746
|
+
const MULTI_REGION_RECREATE_BLOCKED_TYPES = new Set(["AWS::DynamoDB::GlobalTable"]);
|
|
11747
|
+
/**
|
|
11748
|
+
* Cheap, synchronous read of the resource's recorded properties only.
|
|
11749
|
+
* For `AWS::S3::Bucket` this returns `null` — the live `ListObjectsV2`
|
|
11750
|
+
* probe to distinguish empty buckets (safe to recreate) from
|
|
11751
|
+
* non-empty (data loss) lives in
|
|
11752
|
+
* `src/deployment/recreate-targets.ts#probeStatefulRecreateTargetsAsync`
|
|
11753
|
+
* (issue [#648]) and runs after this sync first-cut. Sync callers can
|
|
11754
|
+
* still treat `null` as "not stateful" — the deploy command does both
|
|
11755
|
+
* passes back-to-back; only callers that explicitly opt out of the
|
|
11756
|
+
* async probe need to assume conservative "stateful" semantics.
|
|
11757
|
+
*
|
|
11758
|
+
* Returns the {@link StatefulReason} when the type is stateful (or
|
|
11759
|
+
* `null` for non-stateful types).
|
|
11760
|
+
*/
|
|
11761
|
+
function isStatefulRecreateTargetSync(resourceType, recordedProperties) {
|
|
11762
|
+
if (!STATEFUL_TYPES.has(resourceType)) return null;
|
|
11763
|
+
if (resourceType === "AWS::Logs::LogGroup") {
|
|
11764
|
+
const retention = recordedProperties?.["RetentionInDays"];
|
|
11765
|
+
if (typeof retention === "number" && retention > 0) return "has-retention";
|
|
11766
|
+
return null;
|
|
11767
|
+
}
|
|
11768
|
+
if (resourceType === "AWS::S3::Bucket") return null;
|
|
11769
|
+
return "always";
|
|
11770
|
+
}
|
|
11771
|
+
/**
|
|
11772
|
+
* Conservative variant for the `cdkd deploy --replace` mid-deploy guard.
|
|
11773
|
+
*
|
|
11774
|
+
* `--replace` catches a provider's immutable-update rejection while the deploy
|
|
11775
|
+
* is already in flight, so — unlike the `--recreate-via-*` pre-flight, which
|
|
11776
|
+
* runs {@link probeStatefulRecreateTargetsAsync} (`s3:ListObjectVersions`) —
|
|
11777
|
+
* there is no opportunity to probe an `AWS::S3::Bucket`'s object count. The
|
|
11778
|
+
* sync check returns `null` for S3 (it defers to that async probe), which would
|
|
11779
|
+
* let a NON-EMPTY bucket be DELETE + CREATEd (data loss) without
|
|
11780
|
+
* `--force-stateful-recreation`. To stay fail-safe, treat a deferred S3 bucket
|
|
11781
|
+
* as stateful here: the user must pass `--force-stateful-recreation` to replace
|
|
11782
|
+
* ANY S3 bucket via `--replace`, empty or not. Every other type matches
|
|
11783
|
+
* {@link isStatefulRecreateTargetSync} exactly (the LogGroup retention check is
|
|
11784
|
+
* fully resolvable from recorded properties, so no conservatism is needed there).
|
|
11785
|
+
*/
|
|
11786
|
+
function isStatefulRecreateTargetForReplace(resourceType, recordedProperties) {
|
|
11787
|
+
const sync = isStatefulRecreateTargetSync(resourceType, recordedProperties);
|
|
11788
|
+
if (sync) return sync;
|
|
11789
|
+
if (resourceType === "AWS::S3::Bucket") return "has-objects";
|
|
11790
|
+
return null;
|
|
11791
|
+
}
|
|
11792
|
+
/**
|
|
11793
|
+
* Human-readable rendering of {@link StatefulReason} for error
|
|
11794
|
+
* messages. Used by the pre-flight guard's "X resources require
|
|
11795
|
+
* --force-stateful-recreation" listing.
|
|
11796
|
+
*/
|
|
11797
|
+
function renderStatefulReason(reason) {
|
|
11798
|
+
switch (reason) {
|
|
11799
|
+
case "always": return "destroy loses all data in the resource";
|
|
11800
|
+
case "has-objects": return "S3 bucket is non-empty";
|
|
11801
|
+
case "has-retention": return "log group retains data (RetentionInDays > 0)";
|
|
11802
|
+
case null: return "(not stateful)";
|
|
11803
|
+
}
|
|
11804
|
+
}
|
|
11805
|
+
|
|
11672
11806
|
//#endregion
|
|
11673
11807
|
//#region src/deployment/dag-executor.ts
|
|
11674
11808
|
/**
|
|
@@ -13248,7 +13382,13 @@ var DeployEngine = class {
|
|
|
13248
13382
|
result = await this.withRetry(() => updateProvider.update(logicalId, currentResource.physicalId, resourceType, updateProps, currentProps), logicalId, void 0, void 0, updateProvider);
|
|
13249
13383
|
} catch (updateError) {
|
|
13250
13384
|
const msg = updateError instanceof Error ? updateError.message : String(updateError);
|
|
13251
|
-
|
|
13385
|
+
const ccUnsupported = msg.includes("UnsupportedActionException") || msg.includes("does not support UPDATE");
|
|
13386
|
+
const replaceOptIn = updateError instanceof ResourceUpdateNotSupportedError && this.options.replace === true;
|
|
13387
|
+
if (ccUnsupported || replaceOptIn) {
|
|
13388
|
+
if (replaceOptIn) {
|
|
13389
|
+
const statefulReason = isStatefulRecreateTargetForReplace(resourceType, currentProps);
|
|
13390
|
+
if (statefulReason && this.options.forceStatefulRecreation !== true) throw new CdkdError(`--replace would DELETE + CREATE the stateful resource ${logicalId} (${resourceType}) — ${renderStatefulReason(statefulReason)}. Re-run with --force-stateful-recreation to confirm the data loss, or change the resource definition to avoid the immutable-property change.`, "STATEFUL_REPLACE_BLOCKED");
|
|
13391
|
+
}
|
|
13252
13392
|
this.logger.info(`UPDATE not supported for ${logicalId} (${resourceType}), replacing (DELETE → CREATE)`);
|
|
13253
13393
|
try {
|
|
13254
13394
|
await updateProvider.delete(logicalId, currentResource.physicalId, resourceType, currentProps, { expectedRegion: this.stackRegion });
|
|
@@ -13523,5 +13663,5 @@ var DeployEngine = class {
|
|
|
13523
13663
|
};
|
|
13524
13664
|
|
|
13525
13665
|
//#endregion
|
|
13526
|
-
export {
|
|
13527
|
-
//# sourceMappingURL=deploy-engine-
|
|
13666
|
+
export { CFN_TEMPLATE_BODY_LIMIT as $, LockManager as A, runDockerForeground as B, findActionableSilentDrops as C, DiffCalculator as D, applyRoleArnIfSet as E, stringifyValue as F, getDefaultStateBucketName as G, AssetManifestLoader as H, WorkGraph as I, resolveCaptureObservedState as J, getLegacyStateBucketName as K, buildDockerImage as L, rebuildClientForBucketRegion as M, shouldRetainResource as N, DagBuilder as O, AssetPublisher as P, warnDeprecatedNoPrefixCliFlag as Q, formatDockerLoginError as R, ProviderRegistry as S, IntrinsicFunctionResolver as T, getDockerImageBySourceHash as U, runDockerStreaming as V, Synthesizer as W, resolveStateBucketWithDefault as X, resolveSkipPrefix as Y, resolveStateBucketWithDefaultAndSource as Z, green as _, withRetry as a, clearBucketRegionCache as at, IAMRoleProvider as b, computeImplicitDeleteEdges as c, isStatefulRecreateTargetSync as d, CFN_TEMPLATE_URL_LIMIT as et, renderStatefulReason as f, gray as g, cyan as h, withResourceDeadline as i, AssemblyReader as it, S3StateBackend as j, TemplateParser as k, extractDeploymentEventError as l, bold as m, DEFAULT_RESOURCE_WARN_AFTER_MS as n, findLargeInlineResources as nt, isRetryableTransientError as o, resolveBucketRegion as ot, formatResourceLine as p, resolveApp as q, DeployEngine as r, uploadCfnTemplate as rt, IMPLICIT_DELETE_DEPENDENCIES as s, DEFAULT_RESOURCE_TIMEOUT_MS as t, MIGRATE_TMP_PREFIX as tt, MULTI_REGION_RECREATE_BLOCKED_TYPES as u, red as v, CloudControlProvider as w, collectInlinePolicyNamesManagedBySiblings as x, yellow as y, getDockerCmd as z };
|
|
13667
|
+
//# sourceMappingURL=deploy-engine-_N5kVjZN.js.map
|