@go-to-k/cdkd 0.284.49 → 0.284.50
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-BBqefiXQ.js → asg-provider-tVXU-L28.js} +2 -2
- package/dist/{asg-provider-BBqefiXQ.js.map → asg-provider-tVXU-L28.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-D-NZ_16N.js → deploy-engine-tBUjmzHn.js} +3 -3
- package/dist/{deploy-engine-D-NZ_16N.js.map → deploy-engine-tBUjmzHn.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-Bd0gnMR0.js → program-CMiO_i__.js} +255 -4
- package/dist/{program-Bd0gnMR0.js.map → program-CMiO_i__.js.map} +1 -1
- package/dist/{version-DZ6zMwCR.js → version-pYF8nPNw.js} +2 -2
- package/dist/{version-DZ6zMwCR.js.map → version-pYF8nPNw.js.map} +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $n as setAwsClients, Bt as DiffCalculator, Cr as normalizeAwsError, Gt as TemplateParser, Jn as clearBucketRegionCache, Jt as S3StateBackend, Kn as AssemblyReader, Kt as LockManager, Qn as resetAwsClients, Sr as isCdkdError, W as IAMRoleProvider, Wt as DagBuilder, Xn as AwsClients, Yn as resolveBucketRegion, Zn as getAwsClients, Zt as AssetPublisher, br as SynthesisError, er as AssetError, et as CloudControlProvider, ir as DependencyError, mr as ProvisioningError, nr as ConfigError, q as ProviderRegistry, r as DeployEngine, tr as CdkdError, ur as LockError, wn as Synthesizer, xr as formatError, yr as StateError } from "./deploy-engine-
|
|
1
|
+
import { $n as setAwsClients, Bt as DiffCalculator, Cr as normalizeAwsError, Gt as TemplateParser, Jn as clearBucketRegionCache, Jt as S3StateBackend, Kn as AssemblyReader, Kt as LockManager, Qn as resetAwsClients, Sr as isCdkdError, W as IAMRoleProvider, Wt as DagBuilder, Xn as AwsClients, Yn as resolveBucketRegion, Zn as getAwsClients, Zt as AssetPublisher, br as SynthesisError, er as AssetError, et as CloudControlProvider, ir as DependencyError, mr as ProvisioningError, nr as ConfigError, q as ProviderRegistry, r as DeployEngine, tr as CdkdError, ur as LockError, wn as Synthesizer, xr as formatError, yr as StateError } from "./deploy-engine-tBUjmzHn.js";
|
|
2
2
|
import { n as getLogger, r as setLogger, t as ConsoleLogger } from "./logger-zRrlbaQt.js";
|
|
3
3
|
|
|
4
4
|
export { AssemblyReader, AssetError, AssetPublisher, AwsClients, CdkdError, CloudControlProvider, ConfigError, ConsoleLogger, DagBuilder, DependencyError, DeployEngine, DiffCalculator, IAMRoleProvider, LockError, LockManager, ProviderRegistry, ProvisioningError, S3StateBackend, StateError, SynthesisError, Synthesizer, TemplateParser, clearBucketRegionCache, formatError, getAwsClients, getLogger, isCdkdError, normalizeAwsError, resetAwsClients, resolveBucketRegion, setAwsClients, setLogger };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { $ as startInterruptWatch, $n as setAwsClients, $t as WorkGraph, A as renderStatefulReason, An as resolveCaptureObservedState, At as redactSecretsForState, B as exportAliasCollisionScrubWarning, Bn as findLargeInlineResources, Bt as DiffCalculator, C as isFinalSnapshotError, Cn as getDockerImageBySourceHash, Cr as normalizeAwsError, Ct as TEMPLATE_SOURCED_RULES, D as extractDeploymentEventError, Dn as getLegacyStateBucketName, Dr as isThrottlingError, Dt as isSingleDynamicReferenceToken, E as makeCanonicalizePropertiesFn, En as getDefaultStateBucketName, Er as isRetryableTransientError, Et as errorCauseChain, F as green, Fn as stateBucketExistenceConfirmed, Ft as s3BucketDomainName, G as collectInlinePolicyNamesManagedBySiblings, Gn as derivePartitionAndUrlSuffix, Gt as TemplateParser, H as secretBearingStateKeyWarning, Hn as expectedOwnerParam, Ht as describeTypeWithThrottleRetry, I as red, In as warnDeprecatedNoPrefixCliFlag, It as s3BucketDualStackDomainName, J as findActionableSilentDrops, Jt as S3StateBackend, K as clearOnUpdateRemoval, Kn as AssemblyReader, Kt as LockManager, L as yellow, Ln as CFN_TEMPLATE_BODY_LIMIT, Lt as s3BucketRegionalDomainName, M as bold, Mn as resolveStateBucketWithDefault, Mt as classifyReplaySecretRegion, N as cyan, Nn as resolveStateBucketWithDefaultAndSource, Nt as producerRegionsFromState, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as resolveApp, Or as markNonRetryable, Ot as maskSecretsInError, P as gray, Pn as resolveUseCdkBootstrapAssets, Pt as s3BucketArn, Q as isInterruptedWaitError, Qn as resetAwsClients, Qt as stringifyValue, R as collectDeclaredOutputNames, Rn as CFN_TEMPLATE_URL_LIMIT, Rt as s3BucketWebsiteUrl, S as createPreDeleteFinalSnapshot, Sn as AssetManifestLoader, St as STATE_SOURCED_READBACK_RULES, T as unsupportedFinalSnapshotError, Tn as synthesisStatusMessage, Tr as isMarkedNonRetryable, Tt as dynamicReferenceTokens, U as stateKeySecretExposure, Un as PARTITION_TABLE, Ut as withRetry, V as isExportAliasCollision, Vn as uploadCfnTemplate, Vt as INTRINSIC_KEYS, W as IAMRoleProvider, Wn as canonicalizeRegion, Wt as DagBuilder, X as beginCommandInterruptScope, Xn as AwsClients, Xt as shouldRetainResource, Y as findSilentDropProperties, Yn as resolveBucketRegion, Yt as rebuildClientForBucketRegion, Z as endCommandInterruptScope, Zn as getAwsClients, Zt as AssetPublisher, _ as computeImplicitDeleteEdges, _n as formatDockerLoginError, _r as StackHasActiveImportsError, _t as replayWarn, a as DeploymentEventsStore, an as stripControlChars, ar as DeployCancelledError, at as carriesDynamicReference, b as buildFinalSnapshotIdentifier, bn as runDockerForeground, bt as requireConfigString, c as replayFailedOperations, cn as ensureAssetStorage, cr as LocalMigrateError, ct as refStateLookupFromResource, d as updatePartialReason, dn as readBootstrapMarkerBody, dr as MissingCdkCliError, dt as resolveExplicitPhysicalId, en as buildAssetRedirectMap, et as CloudControlProvider, f as UNSPECIFIED_SKIP_REASON, fn as validateAssetBucketName, fr as NestedStackChildDirectDestroyError, ft as assertRegionMatch, g as IMPLICIT_DELETE_DEPENDENCIES, gn as dockerSpawnEnvWithSensitive, gr as ResourceUpdateNotSupportedError, gt as readConfigString, h as maskingRetryLogger, hn as buildDockerImage, hr as ResourceTimeoutError, ht as configStringRefusal, i as DeploymentEventsReader, in as escapeRegExp, it as IntrinsicFunctionResolver, j as formatResourceLine, jn as resolveSkipPrefix, jt as scrubResourceRecord, k as isStatefulRecreateTargetSync, kn as resolveAutoAssetStorage, kt as maskSecretsInText, l as replayRollback, ln as getBootstrapMarkerKey, lr as LocalStartServiceError, lt as WAFv2WebACLProvider, m as withResourceDeadline, mn as buildDenyExternalAccessPolicy, mr as ProvisioningError, mt as configBooleanRefusal, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as loadPublishableAssetManifest, nt as disableInstanceApiTermination, o as planFailedOps, on as AssetModeResolver, or as DynamicReferenceRegionAmbiguousError, ot as cfnRefValueFromPhysicalId, p as deleteSkipReason, pn as validateContainerRepoName, pr as PartialFailureError, pt as coerceCfnBoolean, q as ProviderRegistry, qn as processStackMessages, qt as displaySafe, r as DeployEngine, rn as rewriteTemplateAssetReferences, rr as CrossAccountSecretRefusalError, rt as isTerminationProtectionPropagationError, s as planRollback, sn as BOOTSTRAP_MARKER_PREFIX, sr as LocalInvokeBuildError$1, st as getAccountInfo, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as createAssetRedirectResolver, tr as CdkdError, tt as slowCcOperationTimeoutMs, u as updatePartialMessage, un as parseBootstrapMarker, ut as normalizeAwsTagsToCfn, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as getDockerCmd, vr as StackTerminationProtectionError, vt as requireConfigArray, w as refusesFinalSnapshot, wn as Synthesizer, wr as withErrorHandling, wt as createSecretMasker, x as ccRoutedFinalSnapshotError, xn as runDockerStreaming, xt as STATE_SOURCED_CROSS_GENERATION_RULES, y as PRE_DELETE_SNAPSHOT_TYPES, yn as partitionSensitiveEnv, yt as requireConfigObject, z as collectPublishedOutputNames, zn as MIGRATE_TMP_PREFIX, zt as applyRoleArnIfSet } from "./deploy-engine-
|
|
1
|
+
import { $ as startInterruptWatch, $n as setAwsClients, $t as WorkGraph, A as renderStatefulReason, An as resolveCaptureObservedState, At as redactSecretsForState, B as exportAliasCollisionScrubWarning, Bn as findLargeInlineResources, Bt as DiffCalculator, C as isFinalSnapshotError, Cn as getDockerImageBySourceHash, Cr as normalizeAwsError, Ct as TEMPLATE_SOURCED_RULES, D as extractDeploymentEventError, Dn as getLegacyStateBucketName, Dr as isThrottlingError, Dt as isSingleDynamicReferenceToken, E as makeCanonicalizePropertiesFn, En as getDefaultStateBucketName, Er as isRetryableTransientError, Et as errorCauseChain, F as green, Fn as stateBucketExistenceConfirmed, Ft as s3BucketDomainName, G as collectInlinePolicyNamesManagedBySiblings, Gn as derivePartitionAndUrlSuffix, Gt as TemplateParser, H as secretBearingStateKeyWarning, Hn as expectedOwnerParam, Ht as describeTypeWithThrottleRetry, I as red, In as warnDeprecatedNoPrefixCliFlag, It as s3BucketDualStackDomainName, J as findActionableSilentDrops, Jt as S3StateBackend, K as clearOnUpdateRemoval, Kn as AssemblyReader, Kt as LockManager, L as yellow, Ln as CFN_TEMPLATE_BODY_LIMIT, Lt as s3BucketRegionalDomainName, M as bold, Mn as resolveStateBucketWithDefault, Mt as classifyReplaySecretRegion, N as cyan, Nn as resolveStateBucketWithDefaultAndSource, Nt as producerRegionsFromState, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as resolveApp, Or as markNonRetryable, Ot as maskSecretsInError, P as gray, Pn as resolveUseCdkBootstrapAssets, Pt as s3BucketArn, Q as isInterruptedWaitError, Qn as resetAwsClients, Qt as stringifyValue, R as collectDeclaredOutputNames, Rn as CFN_TEMPLATE_URL_LIMIT, Rt as s3BucketWebsiteUrl, S as createPreDeleteFinalSnapshot, Sn as AssetManifestLoader, St as STATE_SOURCED_READBACK_RULES, T as unsupportedFinalSnapshotError, Tn as synthesisStatusMessage, Tr as isMarkedNonRetryable, Tt as dynamicReferenceTokens, U as stateKeySecretExposure, Un as PARTITION_TABLE, Ut as withRetry, V as isExportAliasCollision, Vn as uploadCfnTemplate, Vt as INTRINSIC_KEYS, W as IAMRoleProvider, Wn as canonicalizeRegion, Wt as DagBuilder, X as beginCommandInterruptScope, Xn as AwsClients, Xt as shouldRetainResource, Y as findSilentDropProperties, Yn as resolveBucketRegion, Yt as rebuildClientForBucketRegion, Z as endCommandInterruptScope, Zn as getAwsClients, Zt as AssetPublisher, _ as computeImplicitDeleteEdges, _n as formatDockerLoginError, _r as StackHasActiveImportsError, _t as replayWarn, a as DeploymentEventsStore, an as stripControlChars, ar as DeployCancelledError, at as carriesDynamicReference, b as buildFinalSnapshotIdentifier, bn as runDockerForeground, bt as requireConfigString, c as replayFailedOperations, cn as ensureAssetStorage, cr as LocalMigrateError, ct as refStateLookupFromResource, d as updatePartialReason, dn as readBootstrapMarkerBody, dr as MissingCdkCliError, dt as resolveExplicitPhysicalId, en as buildAssetRedirectMap, et as CloudControlProvider, f as UNSPECIFIED_SKIP_REASON, fn as validateAssetBucketName, fr as NestedStackChildDirectDestroyError, ft as assertRegionMatch, g as IMPLICIT_DELETE_DEPENDENCIES, gn as dockerSpawnEnvWithSensitive, gr as ResourceUpdateNotSupportedError, gt as readConfigString, h as maskingRetryLogger, hn as buildDockerImage, hr as ResourceTimeoutError, ht as configStringRefusal, i as DeploymentEventsReader, in as escapeRegExp, it as IntrinsicFunctionResolver, j as formatResourceLine, jn as resolveSkipPrefix, jt as scrubResourceRecord, k as isStatefulRecreateTargetSync, kn as resolveAutoAssetStorage, kt as maskSecretsInText, l as replayRollback, ln as getBootstrapMarkerKey, lr as LocalStartServiceError, lt as WAFv2WebACLProvider, m as withResourceDeadline, mn as buildDenyExternalAccessPolicy, mr as ProvisioningError, mt as configBooleanRefusal, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as loadPublishableAssetManifest, nt as disableInstanceApiTermination, o as planFailedOps, on as AssetModeResolver, or as DynamicReferenceRegionAmbiguousError, ot as cfnRefValueFromPhysicalId, p as deleteSkipReason, pn as validateContainerRepoName, pr as PartialFailureError, pt as coerceCfnBoolean, q as ProviderRegistry, qn as processStackMessages, qt as displaySafe, r as DeployEngine, rn as rewriteTemplateAssetReferences, rr as CrossAccountSecretRefusalError, rt as isTerminationProtectionPropagationError, s as planRollback, sn as BOOTSTRAP_MARKER_PREFIX, sr as LocalInvokeBuildError$1, st as getAccountInfo, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as createAssetRedirectResolver, tr as CdkdError, tt as slowCcOperationTimeoutMs, u as updatePartialMessage, un as parseBootstrapMarker, ut as normalizeAwsTagsToCfn, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as getDockerCmd, vr as StackTerminationProtectionError, vt as requireConfigArray, w as refusesFinalSnapshot, wn as Synthesizer, wr as withErrorHandling, wt as createSecretMasker, x as ccRoutedFinalSnapshotError, xn as runDockerStreaming, xt as STATE_SOURCED_CROSS_GENERATION_RULES, y as PRE_DELETE_SNAPSHOT_TYPES, yn as partitionSensitiveEnv, yt as requireConfigObject, z as collectPublishedOutputNames, zn as MIGRATE_TMP_PREFIX, zt as applyRoleArnIfSet } from "./deploy-engine-tBUjmzHn.js";
|
|
2
2
|
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";
|
|
3
|
-
import { t as getCdkdVersion } from "./version-
|
|
4
|
-
import { t as ASGProvider } from "./asg-provider-
|
|
3
|
+
import { t as getCdkdVersion } from "./version-pYF8nPNw.js";
|
|
4
|
+
import { t as ASGProvider } from "./asg-provider-tVXU-L28.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";
|
|
@@ -15887,6 +15887,155 @@ function autoScalingRetriesWithinDeleteBudget(budget, defaultMaxRetries) {
|
|
|
15887
15887
|
const AUTO_SCALING_TEARDOWN_RESERVE_MS = 20 * 6e4;
|
|
15888
15888
|
/** `withRetry`'s capped backoff step (`maxDelayMs`), the cost of one retry. */
|
|
15889
15889
|
const AUTO_SCALING_RETRY_STEP_MS = 8e3;
|
|
15890
|
+
/**
|
|
15891
|
+
* {@link ProtectionFlipRecord}s keyed by the resource they describe, so a
|
|
15892
|
+
* `delete()` that is RE-ENTERED remembers what an earlier attempt did.
|
|
15893
|
+
*
|
|
15894
|
+
* Shaped after `ElapsedBudgetRegistry` in `../../utils/elapsed-budget.ts` and
|
|
15895
|
+
* keyed with the same {@link deleteBudgetKey}, because it is the same re-entry:
|
|
15896
|
+
* `destroy-runner.ts` wraps its outer retry loop — up to four `delete()` calls
|
|
15897
|
+
* — in ONE deadline, and re-invokes `delete()` for anything it classes as
|
|
15898
|
+
* retryable. A record created per call cannot see that. Attempt 1 observes the
|
|
15899
|
+
* guard ON, flips it off and fails on a throttle; attempt 2's pre-flip
|
|
15900
|
+
* `DescribeTable` now reports the guard OFF (attempt 1 is why), so a per-call
|
|
15901
|
+
* record starts and stays `false` and a TERMINAL failure on attempt 2
|
|
15902
|
+
* compensates nothing. That is precisely the issue's retry-then-fail case
|
|
15903
|
+
* (#1978).
|
|
15904
|
+
*
|
|
15905
|
+
* A provider INSTANCE FIELD would be wrong for the same reason the budget is
|
|
15906
|
+
* not one: providers are singletons serving concurrent resources, so one field
|
|
15907
|
+
* would carry another table's flip. The key qualifies the physical id by
|
|
15908
|
+
* region, exactly as the budget's does.
|
|
15909
|
+
*
|
|
15910
|
+
* Entries are RETAINED on a throw — that is the point — and released by the
|
|
15911
|
+
* caller on a terminal outcome (a completed delete, or a NotFound), so the map
|
|
15912
|
+
* holds at most one entry per in-flight resource.
|
|
15913
|
+
*/
|
|
15914
|
+
var ProtectionFlipRegistry = class {
|
|
15915
|
+
records = /* @__PURE__ */ new Map();
|
|
15916
|
+
/**
|
|
15917
|
+
* The record for `key`, creating it on first use and REUSING it on re-entry.
|
|
15918
|
+
*
|
|
15919
|
+
* `reuseWithinMs` bounds how long an entry may be reused for and is passed
|
|
15920
|
+
* the same `DELETE_BUDGET_REUSE_WINDOW_MS` the allowance uses: past the
|
|
15921
|
+
* deadline the whole path is sized against, that deadline has certainly
|
|
15922
|
+
* fired, so a caller arriving now belongs to a NEW operation and must not
|
|
15923
|
+
* inherit a previous one's flip. Without it a retained record would make a
|
|
15924
|
+
* much later destroy of the same table re-enable a guard it never touched.
|
|
15925
|
+
*/
|
|
15926
|
+
acquire(key, reuseWithinMs, clock = monotonicNowMs) {
|
|
15927
|
+
const existing = this.records.get(key);
|
|
15928
|
+
if (existing) {
|
|
15929
|
+
if (existing.age.elapsedMs() <= reuseWithinMs) return existing.record;
|
|
15930
|
+
this.records.delete(key);
|
|
15931
|
+
}
|
|
15932
|
+
const created = {
|
|
15933
|
+
record: {
|
|
15934
|
+
flippedOffByThisRun: false,
|
|
15935
|
+
deleteAccepted: false
|
|
15936
|
+
},
|
|
15937
|
+
age: new ElapsedBudget(reuseWithinMs, clock)
|
|
15938
|
+
};
|
|
15939
|
+
this.records.set(key, created);
|
|
15940
|
+
return created.record;
|
|
15941
|
+
}
|
|
15942
|
+
/** Drop `key`'s record — call on a TERMINAL outcome, never between retries. */
|
|
15943
|
+
release(key) {
|
|
15944
|
+
this.records.delete(key);
|
|
15945
|
+
}
|
|
15946
|
+
/** Live entries; exists so a test can prove release actually released. */
|
|
15947
|
+
get size() {
|
|
15948
|
+
return this.records.size;
|
|
15949
|
+
}
|
|
15950
|
+
clear() {
|
|
15951
|
+
this.records.clear();
|
|
15952
|
+
}
|
|
15953
|
+
};
|
|
15954
|
+
/**
|
|
15955
|
+
* Whether `error` ends the delete for good, i.e. whether `destroy-runner.ts`'s
|
|
15956
|
+
* outer loop will NOT re-enter `delete()` for it.
|
|
15957
|
+
*
|
|
15958
|
+
* This is the gate on the compensation, and it is the issue's own point:
|
|
15959
|
+
* re-enabling the guard after a RETRYABLE failure would flip the flag back and
|
|
15960
|
+
* forth across a retry sequence, since the next `delete()` immediately turns it
|
|
15961
|
+
* off again. Compensation belongs on the terminal failure only.
|
|
15962
|
+
*
|
|
15963
|
+
* The predicate MIRRORS `destroy-runner.ts`'s re-entry condition
|
|
15964
|
+
* (`!isMarkedNonRetryable && (isRetryableTransientError || 'Too Many
|
|
15965
|
+
* Requests')`) rather than inventing a second classification, and it is applied
|
|
15966
|
+
* to the error the provider is about to THROW — the same wrapped
|
|
15967
|
+
* `ProvisioningError` message the outer loop will classify — so the two cannot
|
|
15968
|
+
* disagree about who gets re-entered.
|
|
15969
|
+
*
|
|
15970
|
+
* A user abort is terminal here even though nothing classifies it: the run is
|
|
15971
|
+
* being torn down, so no re-entry is coming and the guard would otherwise stay
|
|
15972
|
+
* down. That is the Ctrl-C route recorded on the issue.
|
|
15973
|
+
*
|
|
15974
|
+
* KNOWN NARROWINGS, all deliberate. Each leaves the guard off in a case this
|
|
15975
|
+
* mechanism does not reach; none of them is silent about it here.
|
|
15976
|
+
*
|
|
15977
|
+
* 1. **Attempt-cap exhaustion.** A genuinely retryable failure that exhausts
|
|
15978
|
+
* the outer loop's attempt cap ends the run with the guard still off,
|
|
15979
|
+
* because the provider cannot see which attempt is the last one.
|
|
15980
|
+
* Compensating on every attempt instead would trade that residue for an
|
|
15981
|
+
* `UpdateTable` pair per retry against a table AWS is already throttling.
|
|
15982
|
+
* 2. **The per-resource DEADLINE route.** `src/deployment/resource-deadline.ts`
|
|
15983
|
+
* rejects the OUTER promise on its timer and does NOT cancel what it
|
|
15984
|
+
* wraps — the provider's own `await` never settles as a rejection, so no
|
|
15985
|
+
* `ResourceTimeoutError` ever enters `delete()`'s `catch` and nothing here
|
|
15986
|
+
* runs for it. The provider keeps polling behind a run that has already
|
|
15987
|
+
* reported failure (the same non-cancelling shape issue #1955 documents),
|
|
15988
|
+
* and if that poll eventually succeeds the table is gone anyway. Closing
|
|
15989
|
+
* this would mean making the deadline cancel — a change to a mechanism
|
|
15990
|
+
* every provider shares — so it is recorded, not fixed here.
|
|
15991
|
+
* 3. **The compensation itself is unbounded.** `reEnable` is one `UpdateTable`
|
|
15992
|
+
* with no timeout of its own, so on Ctrl-C it adds one SDK call per flipped
|
|
15993
|
+
* table to a teardown the user has already asked to end. Left unbounded on
|
|
15994
|
+
* purpose: an `UpdateTable` is a single control-plane round trip (no
|
|
15995
|
+
* polling, no wait for ACTIVE), the SDK's own retry/timeout config already
|
|
15996
|
+
* applies to it, and it is the ONLY thing standing between a Ctrl-C and a
|
|
15997
|
+
* live table with its guard stripped — a timeout short enough to be felt
|
|
15998
|
+
* during teardown would mostly convert successful restores into the "could
|
|
15999
|
+
* NOT re-enable" line. Revisit if the compensation ever grows a WAIT.
|
|
16000
|
+
*/
|
|
16001
|
+
function isTerminalDeleteFailure(error) {
|
|
16002
|
+
if (isInterruptedWaitError(error)) return true;
|
|
16003
|
+
if (isMarkedNonRetryable(error)) return true;
|
|
16004
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16005
|
+
return !(isRetryableTransientError(error, message) || message.includes("Too Many Requests"));
|
|
16006
|
+
}
|
|
16007
|
+
/**
|
|
16008
|
+
* Put `DeletionProtectionEnabled` back after a `--remove-protection` flip whose
|
|
16009
|
+
* delete then failed terminally (issue #1978).
|
|
16010
|
+
*
|
|
16011
|
+
* BEST-EFFORT, and it says so. Three properties, each of which the issue names:
|
|
16012
|
+
*
|
|
16013
|
+
* - **It never masks the original error.** This function does not throw —
|
|
16014
|
+
* including when the re-enable itself fails — because it runs inside the
|
|
16015
|
+
* `catch` that is about to re-throw the delete failure, and a secondary
|
|
16016
|
+
* write that throws would REPLACE the reported outcome with its own. The
|
|
16017
|
+
* delete failure stays the outcome; this is a secondary line.
|
|
16018
|
+
* - **It never edits the primary message either.** Splicing the re-enable's
|
|
16019
|
+
* text into the thrown error would change what `isRetryableTransientError`
|
|
16020
|
+
* substring-matches on, so a compensation failure carrying a throttle phrase
|
|
16021
|
+
* could flip a terminal delete failure into a retryable one and re-run the
|
|
16022
|
+
* whole path. The narration goes to the logger, not into the throw.
|
|
16023
|
+
* - **It names the table when it fails.** A silent failure here leaves a LIVE
|
|
16024
|
+
* table with its guard down, which is the exact residue this mechanism
|
|
16025
|
+
* exists to remove, so the message carries the physical id and the one
|
|
16026
|
+
* command that fixes it.
|
|
16027
|
+
*/
|
|
16028
|
+
async function compensateRemovedDeletionProtection(opts) {
|
|
16029
|
+
if (!opts.flip.flippedOffByThisRun) return;
|
|
16030
|
+
if (opts.flip.deleteAccepted) return;
|
|
16031
|
+
if (!isTerminalDeleteFailure(opts.error)) return;
|
|
16032
|
+
try {
|
|
16033
|
+
await opts.reEnable();
|
|
16034
|
+
opts.logger.warn(`DynamoDB ${opts.typeLabel} ${opts.logicalId}: the delete failed after --remove-protection had turned DeletionProtectionEnabled off, so it was re-enabled on ${opts.physicalId}. The delete failure below is the outcome.`);
|
|
16035
|
+
} catch (reEnableError) {
|
|
16036
|
+
opts.logger.error(`DynamoDB ${opts.typeLabel} ${opts.logicalId}: could NOT re-enable DeletionProtectionEnabled on ${opts.physicalId} after the delete failed — that table is LIVE with its deletion protection still off. Restore it with: aws dynamodb update-table --table-name ${opts.physicalId} --deletion-protection-enabled. (${reEnableError instanceof Error ? reEnableError.message : String(reEnableError)})`);
|
|
16037
|
+
}
|
|
16038
|
+
}
|
|
15890
16039
|
|
|
15891
16040
|
//#endregion
|
|
15892
16041
|
//#region src/provisioning/providers/dynamodb-table-provider.ts
|
|
@@ -16488,6 +16637,17 @@ var DynamoDBTableProvider = class {
|
|
|
16488
16637
|
* provider instance.
|
|
16489
16638
|
*/
|
|
16490
16639
|
deleteBudgets = new ElapsedBudgetRegistry();
|
|
16640
|
+
/**
|
|
16641
|
+
* What each in-flight delete did to `DeletionProtectionEnabled` (issue
|
|
16642
|
+
* #1978), keyed exactly as the allowance above and for exactly the same
|
|
16643
|
+
* reason: `destroy-runner.ts` re-enters `delete()` after a retryable failure,
|
|
16644
|
+
* and the second attempt's pre-flip `DescribeTable` sees the guard already
|
|
16645
|
+
* off BECAUSE the first attempt turned it off. A record created per call
|
|
16646
|
+
* would therefore read "nothing to undo" on precisely the retry-then-fail
|
|
16647
|
+
* case the issue names. Keyed rather than a plain field for the budget's
|
|
16648
|
+
* reason too — one provider instance serves a whole level's tables at once.
|
|
16649
|
+
*/
|
|
16650
|
+
protectionFlips = new ProtectionFlipRegistry();
|
|
16491
16651
|
constructor() {
|
|
16492
16652
|
const awsClients = getAwsClients();
|
|
16493
16653
|
this.dynamoDBClient = awsClients.dynamoDB;
|
|
@@ -16807,15 +16967,60 @@ var DynamoDBTableProvider = class {
|
|
|
16807
16967
|
}
|
|
16808
16968
|
/**
|
|
16809
16969
|
* Delete a DynamoDB table
|
|
16970
|
+
*
|
|
16971
|
+
* A thin wrapper around {@link deleteTableResource} whose only job is the
|
|
16972
|
+
* `--remove-protection` compensation (issue #1978): if this run turned
|
|
16973
|
+
* `DeletionProtectionEnabled` off and the delete then ended for good — a
|
|
16974
|
+
* terminal AWS refusal, or a Ctrl-C landing anywhere after the flip — the
|
|
16975
|
+
* guard goes back on before the failure is re-thrown. Without it the run ends
|
|
16976
|
+
* with a LIVE table whose protection cdkd silently stripped: the failure is
|
|
16977
|
+
* loud, the side effect is not.
|
|
16978
|
+
*
|
|
16979
|
+
* It is a WRAPPER rather than a `catch` inside the body because the window is
|
|
16980
|
+
* not one `try`. Between the flip and a successful delete this provider can
|
|
16981
|
+
* throw from the index-settled re-arm, from the retry loop, and from an
|
|
16982
|
+
* interrupted wait, and the same shape on the sibling `GlobalTable` provider
|
|
16983
|
+
* spans a replica teardown as well. Catching at the boundary covers every
|
|
16984
|
+
* exit; the {@link ProtectionFlipRecord} — not the position of the catch — is
|
|
16985
|
+
* what decides whether there is anything to undo.
|
|
16810
16986
|
*/
|
|
16811
16987
|
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
16988
|
+
const flip = this.protectionFlips.acquire(deleteBudgetKey(physicalId, context?.expectedRegion), DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS, resolveDynamoDbDeleteBudgetClock());
|
|
16989
|
+
try {
|
|
16990
|
+
await this.deleteTableResource(logicalId, physicalId, resourceType, context, flip);
|
|
16991
|
+
} catch (error) {
|
|
16992
|
+
await compensateRemovedDeletionProtection({
|
|
16993
|
+
flip,
|
|
16994
|
+
error,
|
|
16995
|
+
logicalId,
|
|
16996
|
+
physicalId,
|
|
16997
|
+
typeLabel: "table",
|
|
16998
|
+
logger: this.logger,
|
|
16999
|
+
reEnable: async () => {
|
|
17000
|
+
await this.dynamoDBClient.send(new UpdateTableCommand({
|
|
17001
|
+
TableName: physicalId,
|
|
17002
|
+
DeletionProtectionEnabled: true
|
|
17003
|
+
}));
|
|
17004
|
+
}
|
|
17005
|
+
});
|
|
17006
|
+
throw error;
|
|
17007
|
+
}
|
|
17008
|
+
}
|
|
17009
|
+
async deleteTableResource(logicalId, physicalId, resourceType, context, flip) {
|
|
16812
17010
|
this.logger.debug(`Deleting DynamoDB table ${logicalId}: ${physicalId}`);
|
|
16813
17011
|
const budget = this.deleteBudgets.acquire(deleteBudgetKey(physicalId, context?.expectedRegion), resolveDynamoDbDeleteBudgetMs(), resolveDynamoDbDeleteBudgetClock(), DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS);
|
|
16814
17012
|
if (context?.removeProtection === true) try {
|
|
17013
|
+
let observedProtectionOn = false;
|
|
17014
|
+
try {
|
|
17015
|
+
observedProtectionOn = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table?.DeletionProtectionEnabled === true;
|
|
17016
|
+
} catch (observeError) {
|
|
17017
|
+
this.logger.debug(`Could not read DeletionProtectionEnabled on ${physicalId} before disabling it: ${observeError instanceof Error ? observeError.message : String(observeError)}`);
|
|
17018
|
+
}
|
|
16815
17019
|
await this.dynamoDBClient.send(new UpdateTableCommand({
|
|
16816
17020
|
TableName: physicalId,
|
|
16817
17021
|
DeletionProtectionEnabled: false
|
|
16818
17022
|
}));
|
|
17023
|
+
if (observedProtectionOn) flip.flippedOffByThisRun = true;
|
|
16819
17024
|
this.logger.debug(`Disabled DeletionProtectionEnabled on DynamoDB table ${logicalId}, waiting for ACTIVE`);
|
|
16820
17025
|
try {
|
|
16821
17026
|
await this.waitForTableActiveAfterUpdate(physicalId, 60, budget);
|
|
@@ -16841,6 +17046,7 @@ var DynamoDBTableProvider = class {
|
|
|
16841
17046
|
logger: this.logger,
|
|
16842
17047
|
deleteTable: async () => {
|
|
16843
17048
|
await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: physicalId }));
|
|
17049
|
+
flip.deleteAccepted = true;
|
|
16844
17050
|
},
|
|
16845
17051
|
reArm: () => waitForIndexesSettled({
|
|
16846
17052
|
tableName: physicalId,
|
|
@@ -16859,11 +17065,13 @@ var DynamoDBTableProvider = class {
|
|
|
16859
17065
|
});
|
|
16860
17066
|
this.logger.debug(`Successfully deleted DynamoDB table ${logicalId}`);
|
|
16861
17067
|
this.deleteBudgets.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
17068
|
+
this.protectionFlips.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
16862
17069
|
} catch (error) {
|
|
16863
17070
|
if (error instanceof ResourceNotFoundException$1) {
|
|
16864
17071
|
assertRegionMatch(await this.dynamoDBClient.config.region(), context?.expectedRegion, resourceType, logicalId, physicalId);
|
|
16865
17072
|
this.logger.debug(`DynamoDB table ${physicalId} does not exist, skipping deletion`);
|
|
16866
17073
|
this.deleteBudgets.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
17074
|
+
this.protectionFlips.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
16867
17075
|
return;
|
|
16868
17076
|
}
|
|
16869
17077
|
const cause = error instanceof Error ? error : void 0;
|
|
@@ -18064,6 +18272,17 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
18064
18272
|
* terms it closes.
|
|
18065
18273
|
*/
|
|
18066
18274
|
deleteBudgets = new ElapsedBudgetRegistry();
|
|
18275
|
+
/**
|
|
18276
|
+
* What each in-flight delete did to `DeletionProtectionEnabled` (issue
|
|
18277
|
+
* #1978), keyed exactly as the allowance above and for exactly the same
|
|
18278
|
+
* reason: `destroy-runner.ts` re-enters `delete()` after a retryable failure,
|
|
18279
|
+
* and the second attempt's pre-flip `DescribeTable` sees the guard already
|
|
18280
|
+
* off BECAUSE the first attempt turned it off. A record created per call
|
|
18281
|
+
* would therefore read "nothing to undo" on precisely the retry-then-fail
|
|
18282
|
+
* case the issue names. Keyed rather than a plain field for the budget's
|
|
18283
|
+
* reason too — one provider instance serves a whole level's tables at once.
|
|
18284
|
+
*/
|
|
18285
|
+
protectionFlips = new ProtectionFlipRegistry();
|
|
18067
18286
|
handledProperties = /* @__PURE__ */ new Map([["AWS::DynamoDB::GlobalTable", /* @__PURE__ */ new Set([
|
|
18068
18287
|
"TableName",
|
|
18069
18288
|
"KeySchema",
|
|
@@ -19332,13 +19551,42 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
19332
19551
|
* strip a still-existing resource from state.
|
|
19333
19552
|
*/
|
|
19334
19553
|
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
19554
|
+
const flip = this.protectionFlips.acquire(deleteBudgetKey(physicalId, context?.expectedRegion), DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS, resolveDynamoDbDeleteBudgetClock());
|
|
19555
|
+
try {
|
|
19556
|
+
await this.deleteGlobalTableResource(logicalId, physicalId, resourceType, context, flip);
|
|
19557
|
+
} catch (error) {
|
|
19558
|
+
await compensateRemovedDeletionProtection({
|
|
19559
|
+
flip,
|
|
19560
|
+
error,
|
|
19561
|
+
logicalId,
|
|
19562
|
+
physicalId,
|
|
19563
|
+
typeLabel: "GlobalTable",
|
|
19564
|
+
logger: this.logger,
|
|
19565
|
+
reEnable: async () => {
|
|
19566
|
+
await this.dynamoDBClient.send(new UpdateTableCommand({
|
|
19567
|
+
TableName: physicalId,
|
|
19568
|
+
DeletionProtectionEnabled: true
|
|
19569
|
+
}));
|
|
19570
|
+
}
|
|
19571
|
+
});
|
|
19572
|
+
throw error;
|
|
19573
|
+
}
|
|
19574
|
+
}
|
|
19575
|
+
async deleteGlobalTableResource(logicalId, physicalId, resourceType, context, flip) {
|
|
19335
19576
|
this.logger.debug(`Deleting DynamoDB GlobalTable ${logicalId}: ${physicalId}`);
|
|
19336
19577
|
const budget = this.deleteBudgets.acquire(deleteBudgetKey(physicalId, context?.expectedRegion), resolveDynamoDbDeleteBudgetMs(), resolveDynamoDbDeleteBudgetClock(), DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS);
|
|
19337
19578
|
if (context?.removeProtection === true) try {
|
|
19579
|
+
let observedProtectionOn = false;
|
|
19580
|
+
try {
|
|
19581
|
+
observedProtectionOn = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table?.DeletionProtectionEnabled === true;
|
|
19582
|
+
} catch (observeError) {
|
|
19583
|
+
this.logger.debug(`Could not read DeletionProtectionEnabled on ${physicalId} before disabling it: ${observeError instanceof Error ? observeError.message : String(observeError)}`);
|
|
19584
|
+
}
|
|
19338
19585
|
await this.dynamoDBClient.send(new UpdateTableCommand({
|
|
19339
19586
|
TableName: physicalId,
|
|
19340
19587
|
DeletionProtectionEnabled: false
|
|
19341
19588
|
}));
|
|
19589
|
+
if (observedProtectionOn) flip.flippedOffByThisRun = true;
|
|
19342
19590
|
this.logger.debug(`Disabled DeletionProtectionEnabled on ${logicalId}, waiting for ACTIVE`);
|
|
19343
19591
|
try {
|
|
19344
19592
|
await this.waitForTableActiveAfterUpdate(physicalId, logicalId, 600, budget);
|
|
@@ -19407,6 +19655,7 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
19407
19655
|
logger: this.logger,
|
|
19408
19656
|
deleteTable: async () => {
|
|
19409
19657
|
await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: physicalId }));
|
|
19658
|
+
flip.deleteAccepted = true;
|
|
19410
19659
|
},
|
|
19411
19660
|
reArm: () => this.waitForIndexesActive(physicalId, logicalId, {
|
|
19412
19661
|
maxAttempts: 60,
|
|
@@ -19423,11 +19672,13 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
19423
19672
|
await this.waitForTableGone(physicalId, logicalId, 600, budget);
|
|
19424
19673
|
this.logger.debug(`Successfully deleted DynamoDB GlobalTable ${logicalId}`);
|
|
19425
19674
|
this.deleteBudgets.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
19675
|
+
this.protectionFlips.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
19426
19676
|
} catch (error) {
|
|
19427
19677
|
if (error instanceof ResourceNotFoundException$1) {
|
|
19428
19678
|
assertRegionMatch(await this.dynamoDBClient.config.region(), context?.expectedRegion, resourceType, logicalId, physicalId);
|
|
19429
19679
|
this.logger.debug(`DynamoDB GlobalTable ${physicalId} does not exist, skipping`);
|
|
19430
19680
|
this.deleteBudgets.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
19681
|
+
this.protectionFlips.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
19431
19682
|
return;
|
|
19432
19683
|
}
|
|
19433
19684
|
const cause = error instanceof Error ? error : void 0;
|
|
@@ -86808,4 +87059,4 @@ function buildProgram() {
|
|
|
86808
87059
|
|
|
86809
87060
|
//#endregion
|
|
86810
87061
|
export { buildProgram };
|
|
86811
|
-
//# sourceMappingURL=program-
|
|
87062
|
+
//# sourceMappingURL=program-CMiO_i__.js.map
|