@go-to-k/cdkd 0.284.23 → 0.284.25
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-Cucl2K22.js → asg-provider-B2lPfJBN.js} +2 -2
- package/dist/{asg-provider-Cucl2K22.js.map → asg-provider-B2lPfJBN.js.map} +1 -1
- package/dist/cli.js +353 -169
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-HfFU96oJ.js → deploy-engine-BpZWPiaL.js} +445 -57
- package/dist/deploy-engine-BpZWPiaL.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-HfFU96oJ.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as isInterruptedWaitError, $n as LocalMigrateError, $t as escapeRegExp, A as isStatefulRecreateTargetSync, An as CFN_TEMPLATE_BODY_LIMIT, At as s3BucketArn, B as collectPublishedOutputNames, Bn as processStackMessages, Bt as DagBuilder, C as createPreDeleteFinalSnapshot, Cn as resolveCaptureObservedState, Ct as TEMPLATE_SOURCED_RULES, D as makeCanonicalizePropertiesFn, Dn as resolveUseCdkBootstrapAssets, Dt as maskSecretsInText, E as unsupportedFinalSnapshotError, En as resolveStateBucketWithDefaultAndSource, Et as isSingleDynamicReferenceToken, F as gray, Fn as expectedOwnerParam, Ft as applyRoleArnIfSet, G as IAMRoleProvider, Gn as resetAwsClients, Gt as shouldRetainResource, H as isExportAliasCollision, Hn as resolveBucketRegion, Ht as LockManager, I as green, In as PARTITION_TABLE, It as DiffCalculator, J as ProviderRegistry, Jn as CdkdError, Jt as WorkGraph, K as collectInlinePolicyNamesManagedBySiblings, Kn as setAwsClients, Kt as AssetPublisher, L as red, Ln as canonicalizeRegion, Lt as INTRINSIC_KEYS, M as formatResourceLine, Mn as MIGRATE_TMP_PREFIX, Mt as s3BucketDualStackDomainName, N as bold, Nn as findLargeInlineResources, Nt as s3BucketRegionalDomainName, O as extractDeploymentEventError, On as stateBucketExistenceConfirmed, Ot as redactSecretsForState, P as cyan, Pn as uploadCfnTemplate, Pt as s3BucketWebsiteUrl, Q as endCommandInterruptScope, Qn as LocalInvokeBuildError$1, Qt as rewriteTemplateAssetReferences, R as yellow, Rn as derivePartitionAndUrlSuffix, Rt as describeTypeWithThrottleRetry, S as ccRoutedFinalSnapshotError, Sn as resolveAutoAssetStorage, St as STATE_SOURCED_READBACK_RULES, T as refusesFinalSnapshot, Tn as resolveStateBucketWithDefault, Tt as dynamicReferenceTokens, U as secretBearingStateKeyWarning, Un as AwsClients, Ut as S3StateBackend, V as exportAliasCollisionScrubWarning, Vt as TemplateParser, W as stateKeySecretExposure, Wn as getAwsClients, Wt as rebuildClientForBucketRegion, X as findSilentDropProperties, Xt as createAssetRedirectResolver, Y as findActionableSilentDrops, Yt as buildAssetRedirectMap, Z as beginCommandInterruptScope, Zn as DeployCancelledError, Zt as loadPublishableAssetManifest, _ as IMPLICIT_DELETE_DEPENDENCIES, _n as Synthesizer, _r as isRetryableTransientError, _t as replayWarn, a as DeploymentEventsStore, an as parseBootstrapMarker, ar as ProvisioningError, at as IntrinsicFunctionResolver, b as PRE_DELETE_SNAPSHOT_TYPES, bn as getLegacyStateBucketName, bt as requireConfigString, c as producerRegionsFromState, cn as validateContainerRepoName, cr as StackHasActiveImportsError, ct as refStateLookupFromResource, d as updatePartialMessage, dn as formatDockerLoginError, dt as resolveExplicitPhysicalId, en as stripControlChars, er as LocalStartServiceError, et as startInterruptWatch, f as updatePartialReason, fn as getDockerCmd, ft as assertRegionMatch, g as maskingRetryLogger, gn as getDockerImageBySourceHash, gr as isMarkedNonRetryable, gt as readConfigString, h as withResourceDeadline, hn as AssetManifestLoader, hr as withErrorHandling, ht as configStringRefusal, i as DeploymentEventsReader, in as getBootstrapMarkerKey, ir as PartialFailureError, it as isTerminationProtectionPropagationError, j as renderStatefulReason, jn as CFN_TEMPLATE_URL_LIMIT, jt as s3BucketDomainName, k as MULTI_REGION_RECREATE_BLOCKED_TYPES, kn as warnDeprecatedNoPrefixCliFlag, kt as scrubResourceRecord, l as replayFailedOperations, ln as buildDenyExternalAccessPolicy, lr as StackTerminationProtectionError, lt as WAFv2WebACLProvider, m as deleteSkipReason, mn as runDockerStreaming, mr as normalizeAwsError, mt as configBooleanRefusal, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as BOOTSTRAP_MARKER_PREFIX, nr as MissingCdkCliError, nt as slowCcOperationTimeoutMs, o as planFailedOps, on as readBootstrapMarkerBody, or as ResourceTimeoutError, ot as cfnRefValueFromPhysicalId, p as UNSPECIFIED_SKIP_REASON, pn as runDockerForeground, pt as coerceCfnBoolean, q as clearOnUpdateRemoval, qt as stringifyValue, r as DeployEngine, rn as ensureAssetStorage, rr as NestedStackChildDirectDestroyError, rt as disableInstanceApiTermination, s as planRollback, sn as validateAssetBucketName, sr as ResourceUpdateNotSupportedError, st as getAccountInfo, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as AssetModeResolver, tt as CloudControlProvider, u as replayRollback, un as buildDockerImage, ut as normalizeAwsTagsToCfn, v as computeImplicitDeleteEdges, vn as synthesisStatusMessage, vr as isThrottlingError, vt as requireConfigArray, w as isFinalSnapshotError, wn as resolveSkipPrefix, wt as createSecretMasker, x as buildFinalSnapshotIdentifier, xn as resolveApp, xt as STATE_SOURCED_CROSS_GENERATION_RULES, y as ATOMIC_FINAL_SNAPSHOT_TYPES, yn as getDefaultStateBucketName, yr as markNonRetryable, yt as requireConfigObject, z as collectDeclaredOutputNames, zn as AssemblyReader, zt as withRetry } from "./deploy-engine-BpZWPiaL.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-B2lPfJBN.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";
|
|
@@ -17,7 +17,7 @@ import { APIGatewayClient, CreateAuthorizerCommand, CreateDeploymentCommand, Cre
|
|
|
17
17
|
import { CreateEventBusCommand, DeleteEventBusCommand, DeleteRuleCommand, DescribeEventBusCommand, DescribeRuleCommand, EventBridgeClient, ListRulesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$1, ListTargetsByRuleCommand, PutRuleCommand, PutTargetsCommand, RemoveTargetsCommand, ResourceNotFoundException as ResourceNotFoundException$2, TagResourceCommand as TagResourceCommand$4, UntagResourceCommand as UntagResourceCommand$4, UpdateEventBusCommand } from "@aws-sdk/client-eventbridge";
|
|
18
18
|
import { CreateSecretCommand, DeleteSecretCommand, DescribeSecretCommand, GetSecretValueCommand, RemoveRegionsFromReplicationCommand, ReplicateSecretToRegionsCommand, ResourceNotFoundException as ResourceNotFoundException$3, SecretsManagerClient, TagResourceCommand as TagResourceCommand$5, UntagResourceCommand as UntagResourceCommand$5, UpdateSecretCommand } from "@aws-sdk/client-secrets-manager";
|
|
19
19
|
import { AddTagsToResourceCommand, DeleteParameterCommand, DescribeParametersCommand, GetParameterCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$2, ParameterNotFound, PutParameterCommand, RemoveTagsFromResourceCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
20
|
-
import { CloudFrontClient, CreateCloudFrontOriginAccessIdentityCommand, CreateDistributionCommand, CreateDistributionWithTagsCommand, CreateOriginAccessControlCommand, DeleteCloudFrontOriginAccessIdentityCommand, DeleteDistributionCommand, DeleteOriginAccessControlCommand, GetCloudFrontOriginAccessIdentityCommand, GetDistributionCommand, GetDistributionConfigCommand, GetOriginAccessControlCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$3, NoSuchCloudFrontOriginAccessIdentity, NoSuchDistribution, NoSuchOriginAccessControl, TagResourceCommand as TagResourceCommand$6, UntagResourceCommand as UntagResourceCommand$6, UpdateCloudFrontOriginAccessIdentityCommand, UpdateDistributionCommand, UpdateOriginAccessControlCommand } from "@aws-sdk/client-cloudfront";
|
|
20
|
+
import { CloudFrontClient, CreateCloudFrontOriginAccessIdentityCommand, CreateDistributionCommand, CreateDistributionWithTagsCommand, CreateOriginAccessControlCommand, DeleteCloudFrontOriginAccessIdentityCommand, DeleteDistributionCommand, DeleteOriginAccessControlCommand, DistributionAlreadyExists, GetCloudFrontOriginAccessIdentityCommand, GetDistributionCommand, GetDistributionConfigCommand, GetOriginAccessControlCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$3, NoSuchCloudFrontOriginAccessIdentity, NoSuchDistribution, NoSuchOriginAccessControl, TagResourceCommand as TagResourceCommand$6, UntagResourceCommand as UntagResourceCommand$6, UpdateCloudFrontOriginAccessIdentityCommand, UpdateDistributionCommand, UpdateOriginAccessControlCommand } from "@aws-sdk/client-cloudfront";
|
|
21
21
|
import { CloudWatchClient, DeleteAlarmsCommand, DeleteAnomalyDetectorCommand, DescribeAlarmsCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$4, PutAnomalyDetectorCommand, PutMetricAlarmCommand, ResourceNotFoundException as ResourceNotFoundException$4, TagResourceCommand as TagResourceCommand$7, UntagResourceCommand as UntagResourceCommand$7 } from "@aws-sdk/client-cloudwatch";
|
|
22
22
|
import { AssociateKmsKeyCommand, CloudWatchLogsClient, CreateLogGroupCommand, DeleteDataProtectionPolicyCommand, DeleteIndexPolicyCommand, DeleteLogGroupCommand, DeleteRetentionPolicyCommand, DescribeIndexPoliciesCommand, DescribeLogGroupsCommand, DisassociateKmsKeyCommand, GetDataProtectionPolicyCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$5, PutBearerTokenAuthenticationCommand, PutDataProtectionPolicyCommand, PutIndexPolicyCommand, PutLogGroupDeletionProtectionCommand, PutRetentionPolicyCommand, ResourceAlreadyExistsException, ResourceNotFoundException as ResourceNotFoundException$5, TagResourceCommand as TagResourceCommand$8, UntagResourceCommand as UntagResourceCommand$8 } from "@aws-sdk/client-cloudwatch-logs";
|
|
23
23
|
import { BedrockAgentCoreControlClient, CreateAgentRuntimeCommand, CreateEvaluatorCommand, DeleteAgentRuntimeCommand, DeleteEvaluatorCommand, GetAgentRuntimeCommand, GetBrowserCommand, GetCodeInterpreterCommand, GetEvaluatorCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$6, ResourceNotFoundException as ResourceNotFoundException$6, TagResourceCommand as TagResourceCommand$9, UntagResourceCommand as UntagResourceCommand$9, UpdateAgentRuntimeCommand, UpdateEvaluatorCommand } from "@aws-sdk/client-bedrock-agentcore-control";
|
|
@@ -1774,6 +1774,7 @@ function createListCommand() {
|
|
|
1774
1774
|
* handler of its own).
|
|
1775
1775
|
*/
|
|
1776
1776
|
function forwardSigtermToSigint() {
|
|
1777
|
+
beginCommandInterruptScope();
|
|
1777
1778
|
const handler = () => {
|
|
1778
1779
|
if (process.listenerCount("SIGINT") === 0) process.exit(143);
|
|
1779
1780
|
process.emit("SIGINT", "SIGINT");
|
|
@@ -1781,6 +1782,7 @@ function forwardSigtermToSigint() {
|
|
|
1781
1782
|
process.on("SIGTERM", handler);
|
|
1782
1783
|
return () => {
|
|
1783
1784
|
process.removeListener("SIGTERM", handler);
|
|
1785
|
+
endCommandInterruptScope();
|
|
1784
1786
|
};
|
|
1785
1787
|
}
|
|
1786
1788
|
|
|
@@ -10863,6 +10865,23 @@ function mapDeliveryStatusLogging(attrs, stateCaseMap = /* @__PURE__ */ new Map(
|
|
|
10863
10865
|
//#endregion
|
|
10864
10866
|
//#region src/provisioning/providers/sns-subscription-provider.ts
|
|
10865
10867
|
/**
|
|
10868
|
+
* The "old subscription was not deleted" reason the THROWN-delete arm of
|
|
10869
|
+
* `update()` reports (issue
|
|
10870
|
+
* [#1967](https://github.com/go-to-k/cdkd/issues/1967)).
|
|
10871
|
+
*
|
|
10872
|
+
* A constant, and FIXED WORDING with no interpolation, for the reason the
|
|
10873
|
+
* abort block spells out at length: this string is rendered onto the warn line
|
|
10874
|
+
* beside a message that must stay clear of the substrings
|
|
10875
|
+
* `retryable-errors.ts` classifies on, and the underlying AWS error text — an
|
|
10876
|
+
* `Unsubscribe` throttle, a `does not exist` — is user-uncontrolled and
|
|
10877
|
+
* carries several of them. The AWS message goes out on its own warn line in
|
|
10878
|
+
* the `catch`, where nothing classifies it.
|
|
10879
|
+
*
|
|
10880
|
+
* Its skip-arm twin is the provider-supplied `ResourceDeleteResult.reason`,
|
|
10881
|
+
* which is subject to the same rule at its own producer.
|
|
10882
|
+
*/
|
|
10883
|
+
const SNS_SUBSCRIPTION_DELETE_THREW_REASON = "the Unsubscribe call did not complete, so the old subscription is unproven";
|
|
10884
|
+
/**
|
|
10866
10885
|
* AWS SNS Subscription Provider
|
|
10867
10886
|
*
|
|
10868
10887
|
* Implements resource provisioning for AWS::SNS::Subscription using the SNS SDK.
|
|
@@ -10941,14 +10960,17 @@ var SNSSubscriptionProvider = class {
|
|
|
10941
10960
|
async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
|
|
10942
10961
|
this.logger.debug(`Updating SNS subscription ${logicalId}: ${physicalId}`);
|
|
10943
10962
|
let deleteResult = void 0;
|
|
10963
|
+
let deleteThrew = false;
|
|
10944
10964
|
try {
|
|
10945
10965
|
deleteResult = await this.delete(logicalId, physicalId, resourceType);
|
|
10946
10966
|
} catch (error) {
|
|
10967
|
+
deleteThrew = true;
|
|
10947
10968
|
this.logger.warn(`Failed to delete old subscription ${physicalId} during update: ${String(error)}`);
|
|
10948
10969
|
}
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
10970
|
+
const notDeletedReason = deleteThrew ? SNS_SUBSCRIPTION_DELETE_THREW_REASON : deleteResult?.outcome === "skipped" ? deleteResult.reason : void 0;
|
|
10971
|
+
if (notDeletedReason !== void 0) {
|
|
10972
|
+
this.logger.warn(`Cannot replace SNS subscription ${logicalId}: the old subscription ${physicalId} was not deleted — ${notDeletedReason}`);
|
|
10973
|
+
throw markNonRetryable(new ProvisioningError(`Cannot replace SNS subscription ${logicalId}: cdkd could not delete the old subscription, and creating the replacement would leave both subscribed to the topic and deliver every message twice. See the warning naming ${logicalId} for the recorded physical id and the cause. Usually the Unsubscribe itself failed (a throttle, a denied sns:Unsubscribe) and the state record is FINE — clear that cause and re-run, or remove the old subscription in AWS by hand. Repair the state record only when the warning says the recorded physical id is malformed, which is the latent skip arm rather than this one.`, resourceType, logicalId, physicalId));
|
|
10952
10974
|
}
|
|
10953
10975
|
const createResult = await this.create(logicalId, resourceType, properties);
|
|
10954
10976
|
return {
|
|
@@ -14819,28 +14841,37 @@ const DELETE_INDEX_WAIT_PROCEED_NOTE = `the DeleteTable goes ahead anyway and AW
|
|
|
14819
14841
|
async function waitForIndexesSettled(opts) {
|
|
14820
14842
|
const { tableName, logicalId, logger, describeTable, maxAttempts, proceedNote } = opts;
|
|
14821
14843
|
const budgetWait = opts.budgetWait;
|
|
14844
|
+
const watch = startInterruptWatch(`index settle wait on ${tableName}`);
|
|
14822
14845
|
let attempt = 0;
|
|
14823
|
-
|
|
14824
|
-
attempt
|
|
14825
|
-
|
|
14826
|
-
if (
|
|
14827
|
-
|
|
14828
|
-
|
|
14829
|
-
if (isThrottlingError(err)) {
|
|
14830
|
-
logger.debug(`DescribeTable throttled while waiting for indexes on ${tableName} (attempt ${attempt}/${maxAttempts}); still waiting: ${message}`);
|
|
14831
|
-
await new Promise((resolve) => setTimeout(resolve, INDEX_SETTLE_POLL_INTERVAL_MS));
|
|
14832
|
-
continue;
|
|
14846
|
+
try {
|
|
14847
|
+
while (budgetWait ? budgetWait.nextPoll() : attempt < maxAttempts) {
|
|
14848
|
+
attempt += 1;
|
|
14849
|
+
if (watch.isInterrupted()) {
|
|
14850
|
+
logger.debug(`Interrupted while waiting for indexes on ${tableName} (${logicalId}) after ${attempt - 1} DescribeTable polls; ${proceedNote}`);
|
|
14851
|
+
return;
|
|
14833
14852
|
}
|
|
14834
|
-
|
|
14835
|
-
|
|
14853
|
+
try {
|
|
14854
|
+
if (!hasTransitionalIndex((await describeTable()).Table?.GlobalSecondaryIndexes ?? [])) return;
|
|
14855
|
+
} catch (err) {
|
|
14856
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
14857
|
+
if (isThrottlingError(err)) {
|
|
14858
|
+
logger.debug(`DescribeTable throttled while waiting for indexes on ${tableName} (attempt ${attempt}/${maxAttempts}); still waiting: ${message}`);
|
|
14859
|
+
await new Promise((resolve) => setTimeout(resolve, INDEX_SETTLE_POLL_INTERVAL_MS));
|
|
14860
|
+
continue;
|
|
14861
|
+
}
|
|
14862
|
+
if (err instanceof ResourceNotFoundException$1) {
|
|
14863
|
+
logger.debug(`Table ${tableName} (${logicalId}) no longer exists while waiting for indexes`);
|
|
14864
|
+
return;
|
|
14865
|
+
}
|
|
14866
|
+
const errorName = err instanceof Error ? err.name : typeof err;
|
|
14867
|
+
logger.debug(`DescribeTable failed while waiting for indexes on ${tableName} (${logicalId}): ${message}`);
|
|
14868
|
+
logger.warn(`DescribeTable failed (${errorName}) while waiting for indexes on ${tableName} (${logicalId}), so cdkd stopped waiting; ${proceedNote} Re-run with --verbose for AWS's own message.`);
|
|
14836
14869
|
return;
|
|
14837
14870
|
}
|
|
14838
|
-
|
|
14839
|
-
logger.debug(`DescribeTable failed while waiting for indexes on ${tableName} (${logicalId}): ${message}`);
|
|
14840
|
-
logger.warn(`DescribeTable failed (${errorName}) while waiting for indexes on ${tableName} (${logicalId}), so cdkd stopped waiting; ${proceedNote} Re-run with --verbose for AWS's own message.`);
|
|
14841
|
-
return;
|
|
14871
|
+
await new Promise((resolve) => setTimeout(resolve, INDEX_SETTLE_POLL_INTERVAL_MS));
|
|
14842
14872
|
}
|
|
14843
|
-
|
|
14873
|
+
} finally {
|
|
14874
|
+
watch.dispose();
|
|
14844
14875
|
}
|
|
14845
14876
|
const pollSeconds = INDEX_SETTLE_POLL_INTERVAL_MS / 1e3;
|
|
14846
14877
|
const pollsRun = budgetWait ? budgetWait.pollsRun : maxAttempts;
|
|
@@ -14945,24 +14976,31 @@ function indexBusyRetryWarning(opts) {
|
|
|
14945
14976
|
*/
|
|
14946
14977
|
async function deleteTableWithIndexBusyRetry(opts) {
|
|
14947
14978
|
let deleteAttempts = 0;
|
|
14948
|
-
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
14962
|
-
|
|
14963
|
-
|
|
14964
|
-
|
|
14965
|
-
|
|
14979
|
+
const watch = startInterruptWatch(`DynamoDB ${opts.typeLabel} ${opts.logicalId} delete`);
|
|
14980
|
+
try {
|
|
14981
|
+
await withRetry(async () => {
|
|
14982
|
+
if (deleteAttempts++ > 0) {
|
|
14983
|
+
if (deleteAttempts === 2) opts.logger.warn(indexBusyRetryWarning({
|
|
14984
|
+
typeLabel: opts.typeLabel,
|
|
14985
|
+
logicalId: opts.logicalId,
|
|
14986
|
+
physicalId: opts.physicalId,
|
|
14987
|
+
attemptNumber: deleteAttempts,
|
|
14988
|
+
maxRetries: opts.maxRetries
|
|
14989
|
+
}));
|
|
14990
|
+
await opts.reArm();
|
|
14991
|
+
}
|
|
14992
|
+
await opts.deleteTable();
|
|
14993
|
+
}, opts.logicalId, {
|
|
14994
|
+
maxRetries: opts.maxRetries,
|
|
14995
|
+
isRetryable: (message) => isIndexBusyDeleteError(message) && (opts.shouldKeepRetrying?.() ?? true),
|
|
14996
|
+
logger: opts.logger,
|
|
14997
|
+
isInterrupted: watch.isInterrupted,
|
|
14998
|
+
onInterrupted: watch.onInterrupted,
|
|
14999
|
+
sleep: (ms) => opts.sleepSeam.sleep ? opts.sleepSeam.sleep(ms) : new Promise((resolve) => setTimeout(resolve, ms))
|
|
15000
|
+
});
|
|
15001
|
+
} finally {
|
|
15002
|
+
watch.dispose();
|
|
15003
|
+
}
|
|
14966
15004
|
}
|
|
14967
15005
|
|
|
14968
15006
|
//#endregion
|
|
@@ -18638,94 +18676,111 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
18638
18676
|
const oldEnabled = oldSettings !== void 0 && oldSettings !== null;
|
|
18639
18677
|
const newEnabled = newSettings !== void 0 && newSettings !== null;
|
|
18640
18678
|
if (!oldEnabled && !newEnabled) return;
|
|
18641
|
-
|
|
18642
|
-
|
|
18643
|
-
|
|
18644
|
-
|
|
18645
|
-
|
|
18679
|
+
const watch = startInterruptWatch(`DynamoDB auto-scaling for ${tableName}`);
|
|
18680
|
+
try {
|
|
18681
|
+
if (newEnabled) {
|
|
18682
|
+
const minCapacity = Number(newSettings["MinCapacity"] ?? 0);
|
|
18683
|
+
const maxCapacity = Number(newSettings["MaxCapacity"] ?? 0);
|
|
18684
|
+
if (!Number.isFinite(minCapacity) || !Number.isFinite(maxCapacity)) {
|
|
18685
|
+
warn(`Cannot apply auto-scaling diff on ${tableName} (${dimension}): MinCapacity / MaxCapacity must be numbers, got ${maskSecrets(String(newSettings["MinCapacity"]))} / ${maskSecrets(String(newSettings["MaxCapacity"]))}`);
|
|
18686
|
+
return;
|
|
18687
|
+
}
|
|
18688
|
+
try {
|
|
18689
|
+
await withRetry(() => asClient.send(new RegisterScalableTargetCommand({
|
|
18690
|
+
ServiceNamespace: "dynamodb",
|
|
18691
|
+
ResourceId: resourceId,
|
|
18692
|
+
ScalableDimension: dimension,
|
|
18693
|
+
MinCapacity: minCapacity,
|
|
18694
|
+
MaxCapacity: maxCapacity
|
|
18695
|
+
})), `${resourceId} (${dimension})`, {
|
|
18696
|
+
isRetryable: (_message, error) => isThrottlingError(error),
|
|
18697
|
+
maxRetries: asMaxRetries,
|
|
18698
|
+
isInterrupted: watch.isInterrupted,
|
|
18699
|
+
onInterrupted: watch.onInterrupted,
|
|
18700
|
+
...autoScalingRetryDelays.sleep ? { sleep: autoScalingRetryDelays.sleep } : {}
|
|
18701
|
+
});
|
|
18702
|
+
} catch (err) {
|
|
18703
|
+
if (isInterruptedWaitError(err)) throw err;
|
|
18704
|
+
warn(`Could not register auto-scaling target on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling register-scalable-target --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension} --min-capacity ${minCapacity} --max-capacity ${maxCapacity}`);
|
|
18705
|
+
return;
|
|
18706
|
+
}
|
|
18707
|
+
const tttCfg = newSettings["TargetTrackingScalingPolicyConfiguration"] ?? {};
|
|
18708
|
+
const targetValue = Number(tttCfg["TargetValue"]);
|
|
18709
|
+
if (!Number.isFinite(targetValue)) {
|
|
18710
|
+
warn(`Auto-scaling target registered on ${tableName} (${dimension}) but TargetValue is missing or non-numeric — skipping PutScalingPolicy. Provide TargetTrackingScalingPolicyConfiguration.TargetValue in the template.`);
|
|
18711
|
+
return;
|
|
18712
|
+
}
|
|
18713
|
+
const targetTrackingConfig = {
|
|
18714
|
+
PredefinedMetricSpecification: { PredefinedMetricType: metricType },
|
|
18715
|
+
TargetValue: targetValue
|
|
18716
|
+
};
|
|
18717
|
+
if (tttCfg["ScaleInCooldown"] !== void 0) targetTrackingConfig["ScaleInCooldown"] = Number(tttCfg["ScaleInCooldown"]);
|
|
18718
|
+
if (tttCfg["ScaleOutCooldown"] !== void 0) targetTrackingConfig["ScaleOutCooldown"] = Number(tttCfg["ScaleOutCooldown"]);
|
|
18719
|
+
if (tttCfg["DisableScaleIn"] !== void 0) targetTrackingConfig["DisableScaleIn"] = Boolean(tttCfg["DisableScaleIn"]);
|
|
18720
|
+
try {
|
|
18721
|
+
await withRetry(() => asClient.send(new PutScalingPolicyCommand({
|
|
18722
|
+
PolicyName: policyName,
|
|
18723
|
+
ServiceNamespace: "dynamodb",
|
|
18724
|
+
ResourceId: resourceId,
|
|
18725
|
+
ScalableDimension: dimension,
|
|
18726
|
+
PolicyType: "TargetTrackingScaling",
|
|
18727
|
+
TargetTrackingScalingPolicyConfiguration: targetTrackingConfig
|
|
18728
|
+
})), `${policyName}`, {
|
|
18729
|
+
isRetryable: (_message, error) => isThrottlingError(error),
|
|
18730
|
+
maxRetries: asMaxRetries,
|
|
18731
|
+
isInterrupted: watch.isInterrupted,
|
|
18732
|
+
onInterrupted: watch.onInterrupted,
|
|
18733
|
+
...autoScalingRetryDelays.sleep ? { sleep: autoScalingRetryDelays.sleep } : {}
|
|
18734
|
+
});
|
|
18735
|
+
this.logger.debug(`Upserted auto-scaling policy ${policyName} on ${tableName} (${dimension})`);
|
|
18736
|
+
} catch (err) {
|
|
18737
|
+
if (isInterruptedWaitError(err)) throw err;
|
|
18738
|
+
warn(`Could not put auto-scaling policy on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling put-scaling-policy --policy-name ${policyName} --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension} --policy-type TargetTrackingScaling`);
|
|
18739
|
+
}
|
|
18646
18740
|
return;
|
|
18647
18741
|
}
|
|
18742
|
+
const isObjectNotFound = (err) => {
|
|
18743
|
+
if (!(err instanceof Error)) return false;
|
|
18744
|
+
const name = err.name ?? "";
|
|
18745
|
+
const msg = err.message ?? "";
|
|
18746
|
+
return name === "ObjectNotFoundException" || msg.includes("No scaling policy found") || msg.includes("No scalable target found");
|
|
18747
|
+
};
|
|
18648
18748
|
try {
|
|
18649
|
-
await withRetry(() => asClient.send(new
|
|
18749
|
+
await withRetry(() => asClient.send(new DeleteScalingPolicyCommand({
|
|
18750
|
+
PolicyName: policyName,
|
|
18650
18751
|
ServiceNamespace: "dynamodb",
|
|
18651
18752
|
ResourceId: resourceId,
|
|
18652
|
-
ScalableDimension: dimension
|
|
18653
|
-
MinCapacity: minCapacity,
|
|
18654
|
-
MaxCapacity: maxCapacity
|
|
18753
|
+
ScalableDimension: dimension
|
|
18655
18754
|
})), `${resourceId} (${dimension})`, {
|
|
18656
18755
|
isRetryable: (_message, error) => isThrottlingError(error),
|
|
18657
18756
|
maxRetries: asMaxRetries,
|
|
18757
|
+
isInterrupted: watch.isInterrupted,
|
|
18758
|
+
onInterrupted: watch.onInterrupted,
|
|
18658
18759
|
...autoScalingRetryDelays.sleep ? { sleep: autoScalingRetryDelays.sleep } : {}
|
|
18659
18760
|
});
|
|
18660
18761
|
} catch (err) {
|
|
18661
|
-
|
|
18662
|
-
|
|
18762
|
+
if (isInterruptedWaitError(err)) throw err;
|
|
18763
|
+
if (!isObjectNotFound(err)) warn(`Could not delete auto-scaling policy on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling delete-scaling-policy --policy-name ${policyName} --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension}`);
|
|
18663
18764
|
}
|
|
18664
|
-
const tttCfg = newSettings["TargetTrackingScalingPolicyConfiguration"] ?? {};
|
|
18665
|
-
const targetValue = Number(tttCfg["TargetValue"]);
|
|
18666
|
-
if (!Number.isFinite(targetValue)) {
|
|
18667
|
-
warn(`Auto-scaling target registered on ${tableName} (${dimension}) but TargetValue is missing or non-numeric — skipping PutScalingPolicy. Provide TargetTrackingScalingPolicyConfiguration.TargetValue in the template.`);
|
|
18668
|
-
return;
|
|
18669
|
-
}
|
|
18670
|
-
const targetTrackingConfig = {
|
|
18671
|
-
PredefinedMetricSpecification: { PredefinedMetricType: metricType },
|
|
18672
|
-
TargetValue: targetValue
|
|
18673
|
-
};
|
|
18674
|
-
if (tttCfg["ScaleInCooldown"] !== void 0) targetTrackingConfig["ScaleInCooldown"] = Number(tttCfg["ScaleInCooldown"]);
|
|
18675
|
-
if (tttCfg["ScaleOutCooldown"] !== void 0) targetTrackingConfig["ScaleOutCooldown"] = Number(tttCfg["ScaleOutCooldown"]);
|
|
18676
|
-
if (tttCfg["DisableScaleIn"] !== void 0) targetTrackingConfig["DisableScaleIn"] = Boolean(tttCfg["DisableScaleIn"]);
|
|
18677
18765
|
try {
|
|
18678
|
-
await withRetry(() => asClient.send(new
|
|
18679
|
-
PolicyName: policyName,
|
|
18766
|
+
await withRetry(() => asClient.send(new DeregisterScalableTargetCommand({
|
|
18680
18767
|
ServiceNamespace: "dynamodb",
|
|
18681
18768
|
ResourceId: resourceId,
|
|
18682
|
-
ScalableDimension: dimension
|
|
18683
|
-
|
|
18684
|
-
TargetTrackingScalingPolicyConfiguration: targetTrackingConfig
|
|
18685
|
-
})), `${policyName}`, {
|
|
18769
|
+
ScalableDimension: dimension
|
|
18770
|
+
})), `${resourceId} (${dimension})`, {
|
|
18686
18771
|
isRetryable: (_message, error) => isThrottlingError(error),
|
|
18687
18772
|
maxRetries: asMaxRetries,
|
|
18773
|
+
isInterrupted: watch.isInterrupted,
|
|
18774
|
+
onInterrupted: watch.onInterrupted,
|
|
18688
18775
|
...autoScalingRetryDelays.sleep ? { sleep: autoScalingRetryDelays.sleep } : {}
|
|
18689
18776
|
});
|
|
18690
|
-
this.logger.debug(`
|
|
18777
|
+
this.logger.debug(`Deregistered auto-scaling target ${resourceId} (${dimension})`);
|
|
18691
18778
|
} catch (err) {
|
|
18692
|
-
|
|
18779
|
+
if (isInterruptedWaitError(err)) throw err;
|
|
18780
|
+
if (!isObjectNotFound(err)) warn(`Could not deregister auto-scaling target on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling deregister-scalable-target --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension}`);
|
|
18693
18781
|
}
|
|
18694
|
-
|
|
18695
|
-
|
|
18696
|
-
const isObjectNotFound = (err) => {
|
|
18697
|
-
if (!(err instanceof Error)) return false;
|
|
18698
|
-
const name = err.name ?? "";
|
|
18699
|
-
const msg = err.message ?? "";
|
|
18700
|
-
return name === "ObjectNotFoundException" || msg.includes("No scaling policy found") || msg.includes("No scalable target found");
|
|
18701
|
-
};
|
|
18702
|
-
try {
|
|
18703
|
-
await withRetry(() => asClient.send(new DeleteScalingPolicyCommand({
|
|
18704
|
-
PolicyName: policyName,
|
|
18705
|
-
ServiceNamespace: "dynamodb",
|
|
18706
|
-
ResourceId: resourceId,
|
|
18707
|
-
ScalableDimension: dimension
|
|
18708
|
-
})), `${resourceId} (${dimension})`, {
|
|
18709
|
-
isRetryable: (_message, error) => isThrottlingError(error),
|
|
18710
|
-
maxRetries: asMaxRetries,
|
|
18711
|
-
...autoScalingRetryDelays.sleep ? { sleep: autoScalingRetryDelays.sleep } : {}
|
|
18712
|
-
});
|
|
18713
|
-
} catch (err) {
|
|
18714
|
-
if (!isObjectNotFound(err)) warn(`Could not delete auto-scaling policy on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling delete-scaling-policy --policy-name ${policyName} --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension}`);
|
|
18715
|
-
}
|
|
18716
|
-
try {
|
|
18717
|
-
await withRetry(() => asClient.send(new DeregisterScalableTargetCommand({
|
|
18718
|
-
ServiceNamespace: "dynamodb",
|
|
18719
|
-
ResourceId: resourceId,
|
|
18720
|
-
ScalableDimension: dimension
|
|
18721
|
-
})), `${resourceId} (${dimension})`, {
|
|
18722
|
-
isRetryable: (_message, error) => isThrottlingError(error),
|
|
18723
|
-
maxRetries: asMaxRetries,
|
|
18724
|
-
...autoScalingRetryDelays.sleep ? { sleep: autoScalingRetryDelays.sleep } : {}
|
|
18725
|
-
});
|
|
18726
|
-
this.logger.debug(`Deregistered auto-scaling target ${resourceId} (${dimension})`);
|
|
18727
|
-
} catch (err) {
|
|
18728
|
-
if (!isObjectNotFound(err)) warn(`Could not deregister auto-scaling target on ${tableName} (${dimension}): ${err instanceof Error ? err.message : String(err)}. Run: aws application-autoscaling deregister-scalable-target --service-namespace dynamodb --resource-id ${resourceId} --scalable-dimension ${dimension}`);
|
|
18782
|
+
} finally {
|
|
18783
|
+
watch.dispose();
|
|
18729
18784
|
}
|
|
18730
18785
|
}
|
|
18731
18786
|
/**
|
|
@@ -18923,6 +18978,7 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
18923
18978
|
}
|
|
18924
18979
|
} catch (describeErr) {
|
|
18925
18980
|
if (describeErr instanceof ProvisioningError) throw describeErr;
|
|
18981
|
+
if (isInterruptedWaitError(describeErr)) throw describeErr;
|
|
18926
18982
|
if (!(describeErr instanceof ResourceNotFoundException$1)) {
|
|
18927
18983
|
const cause = describeErr instanceof Error ? describeErr : void 0;
|
|
18928
18984
|
throw new ProvisioningError(`Failed to describe DynamoDB GlobalTable ${logicalId} before delete: ${describeErr instanceof Error ? describeErr.message : String(describeErr)}`, resourceType, logicalId, physicalId, cause);
|
|
@@ -19634,12 +19690,20 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
19634
19690
|
*/
|
|
19635
19691
|
async waitForReplicaGone(tableName, region, logicalId, maxAttempts = REPLICA_GONE_WAIT_ATTEMPTS, budget) {
|
|
19636
19692
|
const wait = beginDeleteWait(maxAttempts, budget);
|
|
19637
|
-
|
|
19638
|
-
|
|
19639
|
-
|
|
19640
|
-
|
|
19641
|
-
|
|
19642
|
-
|
|
19693
|
+
const watch = startInterruptWatch(`DynamoDB replica ${region} teardown on ${tableName}`);
|
|
19694
|
+
try {
|
|
19695
|
+
while (wait.nextPoll()) {
|
|
19696
|
+
if (watch.isInterrupted()) throw watch.onInterrupted();
|
|
19697
|
+
try {
|
|
19698
|
+
if (!(await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: tableName }))).Table?.Replicas?.find((r) => r.RegionName === region)) return;
|
|
19699
|
+
await new Promise((resolve) => setTimeout(resolve, INDEX_SETTLE_POLL_INTERVAL_MS));
|
|
19700
|
+
} catch (err) {
|
|
19701
|
+
if (err instanceof ResourceNotFoundException$1) return;
|
|
19702
|
+
throw err;
|
|
19703
|
+
}
|
|
19704
|
+
}
|
|
19705
|
+
} finally {
|
|
19706
|
+
watch.dispose();
|
|
19643
19707
|
}
|
|
19644
19708
|
throw new ProvisioningError(`Replica ${region} for table ${tableName} did not disappear within ${wait.pollsRun}s${wait.note()}`, "AWS::DynamoDB::GlobalTable", logicalId, tableName);
|
|
19645
19709
|
}
|
|
@@ -19659,12 +19723,23 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
19659
19723
|
*/
|
|
19660
19724
|
async waitForTableGone(tableName, logicalId, maxAttempts = 600, budget) {
|
|
19661
19725
|
const wait = beginDeleteWait(maxAttempts, budget);
|
|
19662
|
-
|
|
19663
|
-
|
|
19664
|
-
|
|
19665
|
-
|
|
19666
|
-
|
|
19667
|
-
|
|
19726
|
+
const watch = startInterruptWatch(`DynamoDB table ${tableName} deletion wait`);
|
|
19727
|
+
try {
|
|
19728
|
+
while (wait.nextPoll()) {
|
|
19729
|
+
if (watch.isInterrupted()) {
|
|
19730
|
+
this.logger.warn(`DynamoDB GlobalTable ${logicalId}: interrupted while waiting for ${tableName} to disappear. AWS ACCEPTED the DeleteTable and will finish it; cdkd stopped watching.`);
|
|
19731
|
+
return;
|
|
19732
|
+
}
|
|
19733
|
+
try {
|
|
19734
|
+
await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: tableName }));
|
|
19735
|
+
await new Promise((resolve) => setTimeout(resolve, INDEX_SETTLE_POLL_INTERVAL_MS));
|
|
19736
|
+
} catch (err) {
|
|
19737
|
+
if (err instanceof ResourceNotFoundException$1) return;
|
|
19738
|
+
throw err;
|
|
19739
|
+
}
|
|
19740
|
+
}
|
|
19741
|
+
} finally {
|
|
19742
|
+
watch.dispose();
|
|
19668
19743
|
}
|
|
19669
19744
|
if (wait.cutShort) {
|
|
19670
19745
|
this.logger.warn(`DynamoDB GlobalTable ${logicalId}: DeleteTable on ${tableName} was ACCEPTED by AWS but cdkd stopped waiting for the table to disappear${wait.note()} The delete completes on AWS's side; a later describe (or a re-run of this destroy) sees it gone.`);
|
|
@@ -30751,13 +30826,19 @@ var CloudFrontDistributionProvider = class {
|
|
|
30751
30826
|
/**
|
|
30752
30827
|
* Create a CloudFront Distribution
|
|
30753
30828
|
*/
|
|
30754
|
-
async create(logicalId, resourceType, properties) {
|
|
30829
|
+
async create(logicalId, resourceType, properties, context) {
|
|
30755
30830
|
this.logger.debug(`Creating CloudFront Distribution ${logicalId}`);
|
|
30831
|
+
const maskSecrets = context?.maskSecrets ?? ((text) => text);
|
|
30832
|
+
const callerReferenceToken = acquireIdempotencyToken({
|
|
30833
|
+
scope: "CreateDistribution",
|
|
30834
|
+
logicalId,
|
|
30835
|
+
maxLength: 128
|
|
30836
|
+
});
|
|
30756
30837
|
try {
|
|
30757
30838
|
const distributionConfig = properties["DistributionConfig"] ?? {};
|
|
30758
30839
|
const sdkConfig = this.convertToSdkFormat({
|
|
30759
30840
|
...distributionConfig,
|
|
30760
|
-
CallerReference:
|
|
30841
|
+
CallerReference: callerReferenceToken.value
|
|
30761
30842
|
});
|
|
30762
30843
|
const sdkTags = this.toSdkTags(properties["Tags"]);
|
|
30763
30844
|
const distribution = (sdkTags ? await this.cloudFrontClient.send(new CreateDistributionWithTagsCommand({ DistributionConfigWithTags: {
|
|
@@ -30768,6 +30849,7 @@ var CloudFrontDistributionProvider = class {
|
|
|
30768
30849
|
const domainName = distribution.DomainName;
|
|
30769
30850
|
this.logger.debug(`Created CloudFront Distribution: ${distributionId} (${domainName})`);
|
|
30770
30851
|
await this.settleDistribution(logicalId, distributionId);
|
|
30852
|
+
callerReferenceToken.release();
|
|
30771
30853
|
return {
|
|
30772
30854
|
physicalId: distributionId,
|
|
30773
30855
|
attributes: {
|
|
@@ -30777,11 +30859,51 @@ var CloudFrontDistributionProvider = class {
|
|
|
30777
30859
|
}
|
|
30778
30860
|
};
|
|
30779
30861
|
} catch (error) {
|
|
30862
|
+
if (error instanceof DistributionAlreadyExists || error?.name === "DistributionAlreadyExists") {
|
|
30863
|
+
const cause = error instanceof Error ? error : void 0;
|
|
30864
|
+
throw markNonRetryable(new ProvisioningError(maskSecrets(`Failed to create CloudFront Distribution ${logicalId}: CloudFront refused the create because this deploy's CallerReference had been used before, which means an EARLIER attempt of this same create succeeded and cdkd never received its response. That distribution is LIVE, is not in cdkd state, and 'cdkd destroy' will not remove it — it bills until you delete it by hand. CloudFront does not return CallerReference from ListDistributions, so find it with 'aws cloudfront list-distributions' and match on ${this.orphanSearchHint(properties, maskSecrets)}; then disable and delete it (or import it with 'cdkd import') before re-running. The AWS error is on this error's cause.`), resourceType, logicalId, void 0, cause));
|
|
30865
|
+
}
|
|
30780
30866
|
const cause = error instanceof Error ? error : void 0;
|
|
30781
30867
|
throw new ProvisioningError(`Failed to create CloudFront Distribution ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
30782
30868
|
}
|
|
30783
30869
|
}
|
|
30784
30870
|
/**
|
|
30871
|
+
* The identifying fields of the distribution that WOULD have been created,
|
|
30872
|
+
* for the `DistributionAlreadyExists` orphan message (issue #2079).
|
|
30873
|
+
*
|
|
30874
|
+
* Only fields `ListDistributions` actually returns are worth naming — the
|
|
30875
|
+
* user has to match the orphan in that output by eye. `Origins[].DomainName`
|
|
30876
|
+
* and `Comment` are both on `DistributionSummary`; `CallerReference` is not,
|
|
30877
|
+
* which is the whole reason this message exists.
|
|
30878
|
+
*
|
|
30879
|
+
* Read from the RAW template properties rather than the converted SDK config
|
|
30880
|
+
* so the helper stays usable from the catch, which is outside the scope
|
|
30881
|
+
* where `sdkConfig` exists. Both the bare-array (CFn) and `{ Quantity,
|
|
30882
|
+
* Items }` (SDK) spellings of `Origins` are accepted because a template may
|
|
30883
|
+
* carry either.
|
|
30884
|
+
*
|
|
30885
|
+
* **Every value it returns is a RESOLVED template value, so each is masked
|
|
30886
|
+
* HERE, at the leaf** (issue #1932 item 3, the shape
|
|
30887
|
+
* `apigatewayv2-provider.ts`'s `toSdkResponseParameters` established). Two
|
|
30888
|
+
* reasons the caller's outer mask cannot stand alone, both from
|
|
30889
|
+
* `.claude/rules/providers.md`: `maskSecretsInText`'s SUBSTRING arm ignores a
|
|
30890
|
+
* needle shorter than `MIN_NEEDLE_LENGTH` (4), and `JSON.stringify` escapes
|
|
30891
|
+
* quotes — so a Secrets Manager JSON document no longer OCCURS literally in
|
|
30892
|
+
* the finished sentence. Masking the raw string first reaches the
|
|
30893
|
+
* WHOLE-VALUE arm at any length, and the mask is idempotent, so both layers
|
|
30894
|
+
* are free.
|
|
30895
|
+
*/
|
|
30896
|
+
orphanSearchHint(properties, maskSecrets) {
|
|
30897
|
+
const config = properties["DistributionConfig"] ?? {};
|
|
30898
|
+
const origins = config["Origins"];
|
|
30899
|
+
const domains = (Array.isArray(origins) ? origins : Array.isArray(origins?.Items) ? origins.Items ?? [] : []).map((origin) => origin?.DomainName).filter((domain) => typeof domain === "string" && domain !== "").map((domain) => maskSecrets(domain));
|
|
30900
|
+
const comment = typeof config["Comment"] === "string" ? maskSecrets(config["Comment"]) : "";
|
|
30901
|
+
const parts = [];
|
|
30902
|
+
if (domains.length > 0) parts.push(`origin domain ${domains.join(" / ")}`);
|
|
30903
|
+
if (comment !== "") parts.push(`comment ${JSON.stringify(comment)}`);
|
|
30904
|
+
return parts.length > 0 ? parts.join(" and ") : "its creation time (the orphan is the newest distribution in this account)";
|
|
30905
|
+
}
|
|
30906
|
+
/**
|
|
30785
30907
|
* Update a CloudFront Distribution
|
|
30786
30908
|
*
|
|
30787
30909
|
* `UpdateDistribution` is a read-modify-write API that expects the COMPLETE
|
|
@@ -30938,11 +31060,14 @@ var CloudFrontDistributionProvider = class {
|
|
|
30938
31060
|
* false positive every run (mirrors the Lambda `Code.S3*` precedent).
|
|
30939
31061
|
*
|
|
30940
31062
|
* - `DistributionConfig.CallerReference`: a create-time idempotency
|
|
30941
|
-
* token. cdkd generates it internally (
|
|
30942
|
-
*
|
|
30943
|
-
* it
|
|
30944
|
-
*
|
|
30945
|
-
*
|
|
31063
|
+
* token. cdkd generates it internally (`acquireIdempotencyToken`, issue
|
|
31064
|
+
* #2079 — a per-process digest, `cdkd-<sha256 prefix>`); AWS echoes it
|
|
31065
|
+
* back, but it is never templated by CDK, so comparing it would diff
|
|
31066
|
+
* cdkd's generated value on every run. It is not even stable across
|
|
31067
|
+
* cdkd RUNS by design (a process nonce is mixed in), so suppression is
|
|
31068
|
+
* required rather than merely convenient. `convertToCfnFormat` already
|
|
31069
|
+
* drops it from the AWS side; declaring it here also excludes it from
|
|
31070
|
+
* the observed-baseline side.
|
|
30946
31071
|
* - `DistributionConfig.Logging.Bucket`: CloudFront normalizes the S3
|
|
30947
31072
|
* logging bucket to its `<bucket>.s3.amazonaws.com` regional domain on
|
|
30948
31073
|
* read, which never matches the bare bucket domain a template may
|
|
@@ -35329,13 +35454,23 @@ var ELBv2Provider = class {
|
|
|
35329
35454
|
try {
|
|
35330
35455
|
const listenerAttributes = this.normalizeAttributes(properties["ListenerAttributes"]);
|
|
35331
35456
|
if (listenerAttributes.length > 0) {
|
|
35332
|
-
|
|
35333
|
-
|
|
35334
|
-
|
|
35335
|
-
|
|
35457
|
+
const watch = startInterruptWatch(`ELBv2 Listener ${logicalId} attributes`);
|
|
35458
|
+
try {
|
|
35459
|
+
await withRetry(() => this.getClient().send(new ModifyListenerAttributesCommand({
|
|
35460
|
+
ListenerArn: listenerArn,
|
|
35461
|
+
Attributes: listenerAttributes
|
|
35462
|
+
})), logicalId, {
|
|
35463
|
+
logger: this.maskedRetryLogger(maskSecrets),
|
|
35464
|
+
isInterrupted: watch.isInterrupted,
|
|
35465
|
+
onInterrupted: watch.onInterrupted
|
|
35466
|
+
});
|
|
35467
|
+
} finally {
|
|
35468
|
+
watch.dispose();
|
|
35469
|
+
}
|
|
35336
35470
|
this.logger.debug(`Applied ${listenerAttributes.length} ListenerAttribute(s) for ${logicalId}`);
|
|
35337
35471
|
}
|
|
35338
35472
|
} catch (innerError) {
|
|
35473
|
+
if (isInterruptedWaitError(innerError)) this.logger.warn(maskerOrIdentity(maskSecrets)(`Interrupted after creating Listener ${logicalId} (${listenerArn}) but before its attributes were applied. Nothing in cdkd state refers to it, so cdkd is deleting it now — left behind it would fail the next deploy with DuplicateListener and neither rollback nor destroy could reach it. If that delete does not complete, remove it manually: aws elbv2 delete-listener --listener-arn ${listenerArn}`));
|
|
35339
35474
|
try {
|
|
35340
35475
|
await this.getClient().send(new DeleteListenerCommand({ ListenerArn: listenerArn }));
|
|
35341
35476
|
this.logger.debug(`Cleaned up partially-created Listener ${logicalId} (${listenerArn}) after attributes-wiring failure`);
|
|
@@ -35372,10 +35507,19 @@ var ELBv2Provider = class {
|
|
|
35372
35507
|
}));
|
|
35373
35508
|
const submittedAttrs = this.diffAttributes(this.normalizeAttributes(properties["ListenerAttributes"]), this.normalizeAttributes(previousProperties["ListenerAttributes"]), this.attributeRemovalResolver(LISTENER_ATTRIBUTE_DEFAULTS));
|
|
35374
35509
|
if (submittedAttrs.length > 0) {
|
|
35375
|
-
|
|
35376
|
-
|
|
35377
|
-
|
|
35378
|
-
|
|
35510
|
+
const watch = startInterruptWatch(`ELBv2 Listener ${logicalId} attributes`);
|
|
35511
|
+
try {
|
|
35512
|
+
await withRetry(() => this.getClient().send(new ModifyListenerAttributesCommand({
|
|
35513
|
+
ListenerArn: physicalId,
|
|
35514
|
+
Attributes: submittedAttrs
|
|
35515
|
+
})), logicalId, {
|
|
35516
|
+
logger: this.maskedRetryLogger(maskSecrets),
|
|
35517
|
+
isInterrupted: watch.isInterrupted,
|
|
35518
|
+
onInterrupted: watch.onInterrupted
|
|
35519
|
+
});
|
|
35520
|
+
} finally {
|
|
35521
|
+
watch.dispose();
|
|
35522
|
+
}
|
|
35379
35523
|
this.logger.debug(`Applied ${submittedAttrs.length} ListenerAttributes change(s) for ${logicalId}`);
|
|
35380
35524
|
}
|
|
35381
35525
|
await this.applyTagDiff(physicalId, previousProperties["Tags"], properties["Tags"]);
|
|
@@ -42469,16 +42613,23 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
42469
42613
|
this.logger.debug(`Deleting Cloud Map namespace ${logicalId}: ${physicalId}`);
|
|
42470
42614
|
const client = this.getClient();
|
|
42471
42615
|
try {
|
|
42472
|
-
|
|
42473
|
-
|
|
42474
|
-
|
|
42475
|
-
|
|
42476
|
-
|
|
42477
|
-
|
|
42478
|
-
|
|
42479
|
-
|
|
42480
|
-
|
|
42481
|
-
|
|
42616
|
+
const watch = startInterruptWatch(`Cloud Map namespace ${logicalId}`);
|
|
42617
|
+
try {
|
|
42618
|
+
await withRetry(async () => {
|
|
42619
|
+
const operationId = (await client.send(new DeleteNamespaceCommand({ Id: physicalId }))).OperationId;
|
|
42620
|
+
if (operationId) await this.pollOperation(operationId, logicalId, resourceType);
|
|
42621
|
+
}, logicalId, {
|
|
42622
|
+
maxRetries: 24,
|
|
42623
|
+
initialDelayMs: 3e3,
|
|
42624
|
+
maxDelayMs: 15e3,
|
|
42625
|
+
isRetryable: (message, error) => error instanceof ResourceInUse || /has associated services/i.test(message),
|
|
42626
|
+
logger: this.logger,
|
|
42627
|
+
isInterrupted: watch.isInterrupted,
|
|
42628
|
+
onInterrupted: watch.onInterrupted
|
|
42629
|
+
});
|
|
42630
|
+
} finally {
|
|
42631
|
+
watch.dispose();
|
|
42632
|
+
}
|
|
42482
42633
|
this.logger.debug(`Successfully deleted Cloud Map namespace ${logicalId}`);
|
|
42483
42634
|
} catch (error) {
|
|
42484
42635
|
if (error instanceof NamespaceNotFound) {
|
|
@@ -42678,13 +42829,23 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
42678
42829
|
try {
|
|
42679
42830
|
const attrs = this.normalizeServiceAttributes(properties["ServiceAttributes"]);
|
|
42680
42831
|
if (Object.keys(attrs).length > 0) {
|
|
42681
|
-
|
|
42682
|
-
|
|
42683
|
-
|
|
42684
|
-
|
|
42832
|
+
const watch = startInterruptWatch(`Cloud Map service ${logicalId} attributes`);
|
|
42833
|
+
try {
|
|
42834
|
+
await withRetry(() => client.send(new UpdateServiceAttributesCommand({
|
|
42835
|
+
ServiceId: serviceId,
|
|
42836
|
+
Attributes: attrs
|
|
42837
|
+
})), logicalId, {
|
|
42838
|
+
logger: this.maskedRetryLogger(maskSecrets),
|
|
42839
|
+
isInterrupted: watch.isInterrupted,
|
|
42840
|
+
onInterrupted: watch.onInterrupted
|
|
42841
|
+
});
|
|
42842
|
+
} finally {
|
|
42843
|
+
watch.dispose();
|
|
42844
|
+
}
|
|
42685
42845
|
this.logger.debug(`Applied ${Object.keys(attrs).length} ServiceAttribute(s) for ${logicalId}`);
|
|
42686
42846
|
}
|
|
42687
42847
|
} catch (innerError) {
|
|
42848
|
+
if (isInterruptedWaitError(innerError)) this.logger.warn(maskerOrIdentity(maskSecrets)(`Interrupted after creating ServiceDiscovery Service ${logicalId} (${serviceId}) but before its ServiceAttributes were applied. Nothing in cdkd state refers to it, so cdkd is deleting it now — left behind it would fail the next deploy on a name collision AND block deletion of its namespace with ResourceInUse. If that delete does not complete, remove it manually: aws servicediscovery delete-service --id ${serviceId}`));
|
|
42688
42849
|
try {
|
|
42689
42850
|
await client.send(new DeleteServiceCommand$1({ Id: serviceId }));
|
|
42690
42851
|
this.logger.debug(`Cleaned up partially-created ServiceDiscovery Service ${logicalId} (${serviceId}) after ServiceAttributes wiring failure`);
|
|
@@ -42754,19 +42915,34 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
42754
42915
|
}))).OperationId;
|
|
42755
42916
|
if (operationId) await this.pollOperation(operationId, logicalId, resourceType, maskSecrets);
|
|
42756
42917
|
}
|
|
42757
|
-
if (hasAttrUpsert) {
|
|
42758
|
-
|
|
42759
|
-
|
|
42760
|
-
|
|
42761
|
-
|
|
42762
|
-
|
|
42763
|
-
|
|
42764
|
-
|
|
42765
|
-
|
|
42766
|
-
|
|
42767
|
-
|
|
42768
|
-
|
|
42769
|
-
|
|
42918
|
+
if (hasAttrUpsert || hasAttrRemove) {
|
|
42919
|
+
const attrWatch = startInterruptWatch(`Cloud Map service ${logicalId} attributes`);
|
|
42920
|
+
try {
|
|
42921
|
+
if (hasAttrUpsert) {
|
|
42922
|
+
await withRetry(() => client.send(new UpdateServiceAttributesCommand({
|
|
42923
|
+
ServiceId: physicalId,
|
|
42924
|
+
Attributes: upsertAttrs
|
|
42925
|
+
})), logicalId, {
|
|
42926
|
+
logger: this.maskedRetryLogger(maskSecrets),
|
|
42927
|
+
isInterrupted: attrWatch.isInterrupted,
|
|
42928
|
+
onInterrupted: attrWatch.onInterrupted
|
|
42929
|
+
});
|
|
42930
|
+
this.logger.debug(`Applied ${Object.keys(upsertAttrs).length} ServiceAttribute change(s) for ${logicalId}`);
|
|
42931
|
+
}
|
|
42932
|
+
if (hasAttrRemove) {
|
|
42933
|
+
await withRetry(() => client.send(new DeleteServiceAttributesCommand({
|
|
42934
|
+
ServiceId: physicalId,
|
|
42935
|
+
Attributes: removedAttrKeys
|
|
42936
|
+
})), logicalId, {
|
|
42937
|
+
logger: this.maskedRetryLogger(maskSecrets),
|
|
42938
|
+
isInterrupted: attrWatch.isInterrupted,
|
|
42939
|
+
onInterrupted: attrWatch.onInterrupted
|
|
42940
|
+
});
|
|
42941
|
+
this.logger.debug(`Removed ${removedAttrKeys.length} ServiceAttribute(s) for ${logicalId}`);
|
|
42942
|
+
}
|
|
42943
|
+
} finally {
|
|
42944
|
+
attrWatch.dispose();
|
|
42945
|
+
}
|
|
42770
42946
|
}
|
|
42771
42947
|
this.logger.debug(`Successfully updated service discovery service ${logicalId}`);
|
|
42772
42948
|
return {
|
|
@@ -58128,7 +58304,7 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58128
58304
|
} catch (error) {
|
|
58129
58305
|
renderer.removeTask(logicalId);
|
|
58130
58306
|
const msg = error instanceof Error ? error.message : String(error);
|
|
58131
|
-
if (!isFinalSnapshotError(error) && (msg.includes("does not exist") || msg.includes("not found") || msg.includes("No policy found") || msg.includes("NoSuchEntity") || msg.includes("NotFoundException"))) {
|
|
58307
|
+
if (!isInterruptedWaitError(error) && !isFinalSnapshotError(error) && (msg.includes("does not exist") || msg.includes("not found") || msg.includes("No policy found") || msg.includes("NoSuchEntity") || msg.includes("NotFoundException"))) {
|
|
58132
58308
|
logger.debug(` ${logicalId} already deleted, removing from state`);
|
|
58133
58309
|
result.deletedCount++;
|
|
58134
58310
|
ctx.eventRecorder?.record({
|
|
@@ -58212,11 +58388,19 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58212
58388
|
logger.warn(`\n${yellow("⚠")} ${bold(`Stack ${stackName} partially destroyed`)} (${green(result.deletedCount)} deleted${retainedSuffix}${skippedSuffix}, ${red(result.errorCount)} errors). State preserved — re-run 'cdkd destroy' / 'cdkd state destroy' to clean up. If the same resource keeps failing, ${orphanHint} is the last resort: it removes the state record without deleting AWS resources.` + skippedClause);
|
|
58213
58389
|
}
|
|
58214
58390
|
} finally {
|
|
58215
|
-
|
|
58216
|
-
|
|
58217
|
-
|
|
58218
|
-
|
|
58219
|
-
|
|
58391
|
+
try {
|
|
58392
|
+
try {
|
|
58393
|
+
renderer.stop();
|
|
58394
|
+
} catch (rendererError) {
|
|
58395
|
+
logger.debug(`Live renderer teardown failed (continuing to release the lock): ${rendererError instanceof Error ? rendererError.message : String(rendererError)}`);
|
|
58396
|
+
}
|
|
58397
|
+
await saveChain;
|
|
58398
|
+
logger.debug("Releasing lock...");
|
|
58399
|
+
await ctx.lockManager.releaseLock(stackName, regionForState);
|
|
58400
|
+
} finally {
|
|
58401
|
+
process.removeListener("SIGINT", sigintHandler);
|
|
58402
|
+
}
|
|
58403
|
+
result.interrupted ||= draining;
|
|
58220
58404
|
if (destroyAwsClients) {
|
|
58221
58405
|
destroyAwsClients.destroy();
|
|
58222
58406
|
process.env["AWS_REGION"] = ctx.baseRegion;
|
|
@@ -83844,7 +84028,7 @@ function createMigrateCommand() {
|
|
|
83844
84028
|
*/
|
|
83845
84029
|
function buildProgram() {
|
|
83846
84030
|
const program = new Command();
|
|
83847
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.
|
|
84031
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.25");
|
|
83848
84032
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
83849
84033
|
const { profile } = actionCommand.optsWithGlobals();
|
|
83850
84034
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|