@go-to-k/cdkd 0.171.0 → 0.173.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { _ as withSkipPrefix, a as runDockerStreaming, c as getLogger, d as getLiveRenderer, f as PATTERN_B_NAME_PROPERTIES, g as generateResourceNameWithFallback, h as generateResourceName, i as runDockerForeground, n as formatDockerLoginError, p as PATTERN_B_RESOURCE_TYPES, r as getDockerCmd, u as runStackBuffered, v as withStackName } from "./docker-cmd-iDMcWcre.js";
|
|
3
|
-
import { A as S3StateBackend, B as resolveCaptureObservedState, C as assertRegionMatch, D as DagBuilder, E as DiffCalculator, F as buildDockerImage, G as CFN_TEMPLATE_BODY_LIMIT, H as resolveStateBucketWithDefault, I as Synthesizer, J as findLargeInlineResources, K as CFN_TEMPLATE_URL_LIMIT, L as getDefaultStateBucketName, M as AssetPublisher, N as stringifyValue, O as TemplateParser, P as WorkGraph, Q as resolveBucketRegion, R as getLegacyStateBucketName, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveStateBucketWithDefaultAndSource, V as resolveSkipPrefix, W as warnDeprecatedNoPrefixCliFlag, X as AssemblyReader, Y as uploadCfnTemplate, _ as matchesCdkPath, a as withRetry, at as LocalStartServiceError, b as ProviderRegistry, bt as withErrorHandling, c as bold, ct as NestedStackChildDirectDestroyError, d as green, dt as ResourceTimeoutError, et as CdkdError, f as red, ft as ResourceUpdateNotSupportedError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, i as withResourceDeadline, it as LocalMigrateError, j as shouldRetainResource, k as LockManager, l as cyan, lt as PartialFailureError, m as IAMRoleProvider, mt as StackTerminationProtectionError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as StackHasActiveImportsError, q as MIGRATE_TMP_PREFIX, r as DeployEngine, rt as LocalInvokeBuildError$1, s as formatResourceLine, st as MissingCdkCliError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ProvisioningError, v as normalizeAwsTagsToCfn, w as IntrinsicFunctionResolver, x as findActionableSilentDrops, y as resolveExplicitPhysicalId, yt as normalizeAwsError, z as resolveApp } from "./deploy-engine-
|
|
3
|
+
import { A as S3StateBackend, B as resolveCaptureObservedState, C as assertRegionMatch, D as DagBuilder, E as DiffCalculator, F as buildDockerImage, G as CFN_TEMPLATE_BODY_LIMIT, H as resolveStateBucketWithDefault, I as Synthesizer, J as findLargeInlineResources, K as CFN_TEMPLATE_URL_LIMIT, L as getDefaultStateBucketName, M as AssetPublisher, N as stringifyValue, O as TemplateParser, P as WorkGraph, Q as resolveBucketRegion, R as getLegacyStateBucketName, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveStateBucketWithDefaultAndSource, V as resolveSkipPrefix, W as warnDeprecatedNoPrefixCliFlag, X as AssemblyReader, Y as uploadCfnTemplate, _ as matchesCdkPath, a as withRetry, at as LocalStartServiceError, b as ProviderRegistry, bt as withErrorHandling, c as bold, ct as NestedStackChildDirectDestroyError, d as green, dt as ResourceTimeoutError, et as CdkdError, f as red, ft as ResourceUpdateNotSupportedError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, i as withResourceDeadline, it as LocalMigrateError, j as shouldRetainResource, k as LockManager, l as cyan, lt as PartialFailureError, m as IAMRoleProvider, mt as StackTerminationProtectionError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as StackHasActiveImportsError, q as MIGRATE_TMP_PREFIX, r as DeployEngine, rt as LocalInvokeBuildError$1, s as formatResourceLine, st as MissingCdkCliError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ProvisioningError, v as normalizeAwsTagsToCfn, w as IntrinsicFunctionResolver, x as findActionableSilentDrops, y as resolveExplicitPhysicalId, yt as normalizeAwsError, z as resolveApp } from "./deploy-engine-BfRlYX17.js";
|
|
4
4
|
import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-B15NAPbL.js";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
@@ -11,7 +11,7 @@ import { CreateTopicCommand, DeleteTopicCommand, GetSubscriptionAttributesComman
|
|
|
11
11
|
import { AddPermissionCommand, CreateEventSourceMappingCommand, CreateFunctionCommand, CreateFunctionUrlConfigCommand, DeleteEventSourceMappingCommand, DeleteFunctionCommand, DeleteFunctionUrlConfigCommand, DeleteLayerVersionCommand, GetEventSourceMappingCommand, GetFunctionCommand, GetFunctionUrlConfigCommand, GetLayerVersionByArnCommand, GetPolicyCommand as GetPolicyCommand$1, LambdaClient, ListFunctionsCommand, ListLayersCommand, ListTagsCommand, PublishLayerVersionCommand, RemovePermissionCommand, ResourceNotFoundException, TagResourceCommand as TagResourceCommand$1, UntagResourceCommand as UntagResourceCommand$1, UpdateEventSourceMappingCommand, UpdateFunctionCodeCommand, UpdateFunctionConfigurationCommand, UpdateFunctionUrlConfigCommand, waitUntilFunctionUpdatedV2 } from "@aws-sdk/client-lambda";
|
|
12
12
|
import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
|
|
13
13
|
import { AssociateRouteTableCommand, AttachInternetGatewayCommand, AuthorizeSecurityGroupEgressCommand, AuthorizeSecurityGroupIngressCommand, CreateInternetGatewayCommand, CreateNatGatewayCommand, CreateNetworkAclCommand, CreateNetworkAclEntryCommand, CreateRouteCommand, CreateRouteTableCommand, CreateSecurityGroupCommand, CreateSubnetCommand, CreateTagsCommand, CreateVpcCommand, DeleteInternetGatewayCommand, DeleteNatGatewayCommand, DeleteNetworkAclCommand, DeleteNetworkAclEntryCommand, DeleteNetworkInterfaceCommand, DeleteRouteCommand, DeleteRouteTableCommand, DeleteSecurityGroupCommand, DeleteSubnetCommand, DeleteTagsCommand, DeleteVpcCommand, DescribeAvailabilityZonesCommand, DescribeInstanceAttributeCommand, DescribeInstancesCommand, DescribeInternetGatewaysCommand, DescribeNatGatewaysCommand, DescribeNetworkAclsCommand, DescribeNetworkInterfacesCommand, DescribeRouteTablesCommand, DescribeSecurityGroupsCommand, DescribeSubnetsCommand, DescribeVolumesCommand, DescribeVpcAttributeCommand, DescribeVpcsCommand, DetachInternetGatewayCommand, DisassociateRouteTableCommand, EC2Client, ModifyInstanceAttributeCommand, ModifySubnetAttributeCommand, ModifyVpcAttributeCommand, ReplaceNetworkAclAssociationCommand, RevokeSecurityGroupEgressCommand, RevokeSecurityGroupIngressCommand, RunInstancesCommand, TerminateInstancesCommand, waitUntilInstanceRunning, waitUntilInstanceTerminated, waitUntilNatGatewayAvailable, waitUntilNatGatewayDeleted } from "@aws-sdk/client-ec2";
|
|
14
|
-
import { CreateTableCommand, DeleteTableCommand, DescribeContinuousBackupsCommand, DescribeContributorInsightsCommand, DescribeKinesisStreamingDestinationCommand, DescribeTableCommand, DescribeTimeToLiveCommand, DynamoDBClient, ListTablesCommand, ListTagsOfResourceCommand, ResourceNotFoundException as ResourceNotFoundException$1, TagResourceCommand as TagResourceCommand$2, UntagResourceCommand as UntagResourceCommand$2, UpdateTableCommand, UpdateTimeToLiveCommand } from "@aws-sdk/client-dynamodb";
|
|
14
|
+
import { CreateTableCommand, DeleteTableCommand, DescribeContinuousBackupsCommand, DescribeContributorInsightsCommand, DescribeKinesisStreamingDestinationCommand, DescribeTableCommand, DescribeTimeToLiveCommand, DynamoDBClient, ListTablesCommand, ListTagsOfResourceCommand, ResourceNotFoundException as ResourceNotFoundException$1, TagResourceCommand as TagResourceCommand$2, UntagResourceCommand as UntagResourceCommand$2, UpdateContinuousBackupsCommand, UpdateTableCommand, UpdateTimeToLiveCommand } from "@aws-sdk/client-dynamodb";
|
|
15
15
|
import { CloudFormationClient, CreateChangeSetCommand, DeleteChangeSetCommand, DeleteStackCommand, DescribeChangeSetCommand, DescribeStackEventsCommand, DescribeStackResourcesCommand, DescribeStacksCommand, DescribeTypeCommand, ExecuteChangeSetCommand, GetTemplateCommand, UpdateStackCommand, waitUntilChangeSetCreateComplete, waitUntilStackDeleteComplete, waitUntilStackImportComplete, waitUntilStackUpdateComplete } from "@aws-sdk/client-cloudformation";
|
|
16
16
|
import { APIGatewayClient, CreateAuthorizerCommand, CreateDeploymentCommand, CreateResourceCommand, CreateStageCommand, DeleteAuthorizerCommand, DeleteDeploymentCommand, DeleteMethodCommand, DeleteResourceCommand, DeleteStageCommand, GetAccountCommand, GetAuthorizerCommand, GetDeploymentCommand, GetMethodCommand, GetResourceCommand, GetStageCommand, NotFoundException as NotFoundException$1, PutIntegrationCommand, PutIntegrationResponseCommand, PutMethodCommand, PutMethodResponseCommand, TagResourceCommand as TagResourceCommand$3, UntagResourceCommand as UntagResourceCommand$3, UpdateAccountCommand, UpdateAuthorizerCommand, UpdateMethodCommand, UpdateStageCommand } from "@aws-sdk/client-api-gateway";
|
|
17
17
|
import { CreateEventBusCommand, DeleteEventBusCommand, DeleteRuleCommand, DescribeEventBusCommand, DescribeRuleCommand, EventBridgeClient, ListEventBusesCommand, 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";
|
|
@@ -414,12 +414,12 @@ const RESOURCE_PROPERTY_FORMAT = /^[A-Z][A-Za-z0-9]+(::[A-Z][A-Za-z0-9]+)+:[A-Z]
|
|
|
414
414
|
function parseAllowUnsupportedPropertiesToken(value, previous) {
|
|
415
415
|
const parsed = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
416
416
|
for (const token of parsed) {
|
|
417
|
-
if (!RESOURCE_PROPERTY_FORMAT.test(token)) throw new Error(`Invalid --allow-unsupported-properties value "${token}": expected <ResourceType>:<PropertyName> with PascalCase on both halves (e.g. AWS::Lambda::Function:
|
|
417
|
+
if (!RESOURCE_PROPERTY_FORMAT.test(token)) throw new Error(`Invalid --allow-unsupported-properties value "${token}": expected <ResourceType>:<PropertyName> with PascalCase on both halves (e.g. AWS::Lambda::Function:RecursiveLoop).`);
|
|
418
418
|
if (token.startsWith("Custom::")) throw new Error(`Invalid --allow-unsupported-properties value "${token}": Custom:: resources are routed through cfn-response and have no write-side silent drop at cdkd, so the flag would have no effect. Use --allow-unsupported-types for type-level escape hatches instead.`);
|
|
419
419
|
}
|
|
420
420
|
return [...previous ?? [], ...parsed];
|
|
421
421
|
}
|
|
422
|
-
const allowUnsupportedPropertiesOption = new Option("--allow-unsupported-properties <entries>", "Comma-separated <ResourceType>:<PropertyName> tokens to accept as silently dropped at deploy time. Escape hatch — the property will NOT be written to AWS, the deployed resource will be missing the field. Example: --allow-unsupported-properties AWS::Lambda::Function:
|
|
422
|
+
const allowUnsupportedPropertiesOption = new Option("--allow-unsupported-properties <entries>", "Comma-separated <ResourceType>:<PropertyName> tokens to accept as silently dropped at deploy time. Escape hatch — the property will NOT be written to AWS, the deployed resource will be missing the field. Example: --allow-unsupported-properties AWS::Lambda::Function:RecursiveLoop,AWS::RDS::DBInstance:CACertificateIdentifier").argParser(parseAllowUnsupportedPropertiesToken);
|
|
423
423
|
/**
|
|
424
424
|
* Issue [#615] — `--recreate-via-cc-api <LogicalId>` (repeatable). Each
|
|
425
425
|
* named resource is destroyed + recreated this deploy via Cloud Control
|
|
@@ -1088,8 +1088,8 @@ function renderStatefulReason(reason) {
|
|
|
1088
1088
|
* this is a structural limitation, not a data-loss footgun.
|
|
1089
1089
|
*
|
|
1090
1090
|
* Plus one cross-flag invariant: `--recreate-via-cc-api MyLambda`
|
|
1091
|
-
* combined with `--allow-unsupported-properties AWS::Lambda::Function:
|
|
1092
|
-
* on a resource whose template carries `
|
|
1091
|
+
* combined with `--allow-unsupported-properties AWS::Lambda::Function:RecursiveLoop`
|
|
1092
|
+
* on a resource whose template carries `RecursiveLoop` is **ambiguous
|
|
1093
1093
|
* intent** — does the user want SDK + silent drop, or CC migration?
|
|
1094
1094
|
* Fail fast and let the user pick one strategy per resource.
|
|
1095
1095
|
*/
|
|
@@ -6992,7 +6992,8 @@ var LambdaFunctionProvider = class {
|
|
|
6992
6992
|
"KmsKeyArn",
|
|
6993
6993
|
"FileSystemConfigs",
|
|
6994
6994
|
"ImageConfig",
|
|
6995
|
-
"SnapStart"
|
|
6995
|
+
"SnapStart",
|
|
6996
|
+
"LoggingConfig"
|
|
6996
6997
|
])]]);
|
|
6997
6998
|
eniWaitTimeoutMs = 600 * 1e3;
|
|
6998
6999
|
eniWaitInitialDelayMs = 1e4;
|
|
@@ -7044,6 +7045,7 @@ var LambdaFunctionProvider = class {
|
|
|
7044
7045
|
FileSystemConfigs: properties["FileSystemConfigs"],
|
|
7045
7046
|
ImageConfig: properties["ImageConfig"],
|
|
7046
7047
|
SnapStart: properties["SnapStart"],
|
|
7048
|
+
LoggingConfig: properties["LoggingConfig"],
|
|
7047
7049
|
Tags: tags
|
|
7048
7050
|
};
|
|
7049
7051
|
const response = await this.lambdaClient.send(new CreateFunctionCommand(createParams));
|
|
@@ -7082,7 +7084,8 @@ var LambdaFunctionProvider = class {
|
|
|
7082
7084
|
"KmsKeyArn",
|
|
7083
7085
|
"FileSystemConfigs",
|
|
7084
7086
|
"ImageConfig",
|
|
7085
|
-
"SnapStart"
|
|
7087
|
+
"SnapStart",
|
|
7088
|
+
"LoggingConfig"
|
|
7086
7089
|
];
|
|
7087
7090
|
let hasConfigChanges = false;
|
|
7088
7091
|
for (const field of configFields) if (JSON.stringify(properties[field]) !== JSON.stringify(previousProperties[field])) {
|
|
@@ -7107,7 +7110,8 @@ var LambdaFunctionProvider = class {
|
|
|
7107
7110
|
KMSKeyArn: this.clearOnUpdateRemoval(properties["KmsKeyArn"], previousProperties["KmsKeyArn"], ""),
|
|
7108
7111
|
FileSystemConfigs: this.clearOnUpdateRemoval(properties["FileSystemConfigs"], previousProperties["FileSystemConfigs"], []),
|
|
7109
7112
|
ImageConfig: this.clearOnUpdateRemoval(properties["ImageConfig"], previousProperties["ImageConfig"], {}),
|
|
7110
|
-
SnapStart: this.clearOnUpdateRemoval(properties["SnapStart"], previousProperties["SnapStart"], { ApplyOn: "None" })
|
|
7113
|
+
SnapStart: this.clearOnUpdateRemoval(properties["SnapStart"], previousProperties["SnapStart"], { ApplyOn: "None" }),
|
|
7114
|
+
LoggingConfig: this.clearOnUpdateRemoval(properties["LoggingConfig"], previousProperties["LoggingConfig"], { LogFormat: "Text" })
|
|
7111
7115
|
};
|
|
7112
7116
|
await this.lambdaClient.send(new UpdateFunctionConfigurationCommand(configParams));
|
|
7113
7117
|
this.logger.debug(`Updated configuration for Lambda function ${physicalId}`);
|
|
@@ -7573,8 +7577,9 @@ var LambdaFunctionProvider = class {
|
|
|
7573
7577
|
* `create()` accepts (`Runtime`, `Handler`, `Role`, `Timeout`, `MemorySize`,
|
|
7574
7578
|
* `Description`, `Environment`, `Layers`, `Architectures`, `PackageType`,
|
|
7575
7579
|
* `TracingConfig`, `EphemeralStorage`, `VpcConfig`, `DeadLetterConfig`,
|
|
7576
|
-
* `KmsKeyArn`, `FileSystemConfigs`, `ImageConfig`, `SnapStart`,
|
|
7577
|
-
* physical `FunctionName`). The drift comparator
|
|
7580
|
+
* `KmsKeyArn`, `FileSystemConfigs`, `ImageConfig`, `SnapStart`,
|
|
7581
|
+
* `LoggingConfig`, plus the physical `FunctionName`). The drift comparator
|
|
7582
|
+
* only descends into keys
|
|
7578
7583
|
* present in
|
|
7579
7584
|
* cdkd state, so AWS-managed fields (timestamps, FunctionArn, RevisionId,
|
|
7580
7585
|
* etc.) are filtered at compare time — we still avoid serializing them on
|
|
@@ -7639,6 +7644,13 @@ var LambdaFunctionProvider = class {
|
|
|
7639
7644
|
if (Object.keys(ic).length > 0) result["ImageConfig"] = ic;
|
|
7640
7645
|
}
|
|
7641
7646
|
if (cfg.SnapStart?.ApplyOn !== void 0) result["SnapStart"] = { ApplyOn: cfg.SnapStart.ApplyOn };
|
|
7647
|
+
if (cfg.LoggingConfig?.LogFormat !== void 0) {
|
|
7648
|
+
const lc = { LogFormat: cfg.LoggingConfig.LogFormat };
|
|
7649
|
+
if (cfg.LoggingConfig.ApplicationLogLevel !== void 0) lc["ApplicationLogLevel"] = cfg.LoggingConfig.ApplicationLogLevel;
|
|
7650
|
+
if (cfg.LoggingConfig.SystemLogLevel !== void 0) lc["SystemLogLevel"] = cfg.LoggingConfig.SystemLogLevel;
|
|
7651
|
+
if (cfg.LoggingConfig.LogGroup !== void 0) lc["LogGroup"] = cfg.LoggingConfig.LogGroup;
|
|
7652
|
+
result["LoggingConfig"] = lc;
|
|
7653
|
+
}
|
|
7642
7654
|
result["Tags"] = normalizeAwsTagsToCfn(resp.Tags);
|
|
7643
7655
|
return result;
|
|
7644
7656
|
} catch (err) {
|
|
@@ -8697,7 +8709,9 @@ var DynamoDBTableProvider = class {
|
|
|
8697
8709
|
"SSESpecification",
|
|
8698
8710
|
"Tags",
|
|
8699
8711
|
"DeletionProtectionEnabled",
|
|
8700
|
-
"TableClass"
|
|
8712
|
+
"TableClass",
|
|
8713
|
+
"PointInTimeRecoverySpecification",
|
|
8714
|
+
"TimeToLiveSpecification"
|
|
8701
8715
|
])]]);
|
|
8702
8716
|
constructor() {
|
|
8703
8717
|
const awsClients = getAwsClients();
|
|
@@ -8713,6 +8727,7 @@ var DynamoDBTableProvider = class {
|
|
|
8713
8727
|
const attributeDefinitions = properties["AttributeDefinitions"];
|
|
8714
8728
|
if (!keySchema) throw new ProvisioningError(`KeySchema is required for DynamoDB table ${logicalId}`, resourceType, logicalId);
|
|
8715
8729
|
if (!attributeDefinitions) throw new ProvisioningError(`AttributeDefinitions is required for DynamoDB table ${logicalId}`, resourceType, logicalId);
|
|
8730
|
+
let tableCreated = false;
|
|
8716
8731
|
try {
|
|
8717
8732
|
const billingMode = properties["BillingMode"] || "PROVISIONED";
|
|
8718
8733
|
const createParams = {
|
|
@@ -8739,8 +8754,11 @@ var DynamoDBTableProvider = class {
|
|
|
8739
8754
|
if (properties["DeletionProtectionEnabled"] !== void 0) createParams.DeletionProtectionEnabled = properties["DeletionProtectionEnabled"];
|
|
8740
8755
|
if (properties["TableClass"]) createParams.TableClass = properties["TableClass"];
|
|
8741
8756
|
await this.dynamoDBClient.send(new CreateTableCommand(createParams));
|
|
8757
|
+
tableCreated = true;
|
|
8742
8758
|
this.logger.debug(`CreateTable initiated for ${tableName}, waiting for ACTIVE status`);
|
|
8743
8759
|
const tableInfo = await this.waitForTableActive(tableName);
|
|
8760
|
+
await this.applyPointInTimeRecovery(tableName, properties["PointInTimeRecoverySpecification"]);
|
|
8761
|
+
await this.applyTimeToLive(tableName, properties["TimeToLiveSpecification"]);
|
|
8744
8762
|
this.logger.debug(`Successfully created DynamoDB table ${logicalId}: ${tableName}`);
|
|
8745
8763
|
return {
|
|
8746
8764
|
physicalId: tableName,
|
|
@@ -8752,6 +8770,12 @@ var DynamoDBTableProvider = class {
|
|
|
8752
8770
|
}
|
|
8753
8771
|
};
|
|
8754
8772
|
} catch (error) {
|
|
8773
|
+
if (tableCreated) try {
|
|
8774
|
+
await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: tableName }));
|
|
8775
|
+
this.logger.debug(`Rolled back partially-created DynamoDB table ${tableName}`);
|
|
8776
|
+
} catch (cleanupError) {
|
|
8777
|
+
this.logger.warn(`Failed to roll back partially-created DynamoDB table ${tableName}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
8778
|
+
}
|
|
8755
8779
|
if (error instanceof ProvisioningError) throw error;
|
|
8756
8780
|
const cause = error instanceof Error ? error : void 0;
|
|
8757
8781
|
throw new ProvisioningError(`Failed to create DynamoDB table ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, tableName, cause);
|
|
@@ -8769,6 +8793,8 @@ var DynamoDBTableProvider = class {
|
|
|
8769
8793
|
try {
|
|
8770
8794
|
const table = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table;
|
|
8771
8795
|
if (table?.TableArn) await this.applyTagDiff(table.TableArn, previousProperties["Tags"], properties["Tags"]);
|
|
8796
|
+
if (JSON.stringify(properties["PointInTimeRecoverySpecification"]) !== JSON.stringify(previousProperties["PointInTimeRecoverySpecification"])) await this.applyPointInTimeRecovery(physicalId, properties["PointInTimeRecoverySpecification"], previousProperties["PointInTimeRecoverySpecification"]);
|
|
8797
|
+
if (JSON.stringify(properties["TimeToLiveSpecification"]) !== JSON.stringify(previousProperties["TimeToLiveSpecification"])) await this.applyTimeToLive(physicalId, properties["TimeToLiveSpecification"], previousProperties["TimeToLiveSpecification"]);
|
|
8772
8798
|
return {
|
|
8773
8799
|
physicalId,
|
|
8774
8800
|
wasReplaced: false,
|
|
@@ -8852,6 +8878,97 @@ var DynamoDBTableProvider = class {
|
|
|
8852
8878
|
}
|
|
8853
8879
|
}
|
|
8854
8880
|
/**
|
|
8881
|
+
* Apply the table's `PointInTimeRecoverySpecification` via the separate
|
|
8882
|
+
* `UpdateContinuousBackups` API (PITR does NOT ride on CreateTable).
|
|
8883
|
+
*
|
|
8884
|
+
* CFn shape is `{ PointInTimeRecoveryEnabled: boolean, RecoveryPeriodInDays?: number }`.
|
|
8885
|
+
* Called from both `create()` (after the table is ACTIVE) and `update()`
|
|
8886
|
+
* (only when the value changed). On `update()`-side removal — when the
|
|
8887
|
+
* template drops the block but it was present before — we explicitly
|
|
8888
|
+
* disable PITR (`UpdateContinuousBackups` treats an absent spec as "no
|
|
8889
|
+
* change", so a dropped block must be turned into an explicit
|
|
8890
|
+
* `PointInTimeRecoveryEnabled: false`).
|
|
8891
|
+
*/
|
|
8892
|
+
async applyPointInTimeRecovery(tableName, spec, previousSpec) {
|
|
8893
|
+
let enabled;
|
|
8894
|
+
let recoveryPeriodInDays;
|
|
8895
|
+
if (spec !== void 0 && spec !== null) {
|
|
8896
|
+
const s = spec;
|
|
8897
|
+
enabled = Boolean(s["PointInTimeRecoveryEnabled"]);
|
|
8898
|
+
if (enabled && s["RecoveryPeriodInDays"] !== void 0) recoveryPeriodInDays = Number(s["RecoveryPeriodInDays"]);
|
|
8899
|
+
} else if (previousSpec !== void 0 && previousSpec !== null) enabled = false;
|
|
8900
|
+
if (enabled === void 0) return;
|
|
8901
|
+
const pitrSpec = { PointInTimeRecoveryEnabled: enabled };
|
|
8902
|
+
if (recoveryPeriodInDays !== void 0) pitrSpec.RecoveryPeriodInDays = recoveryPeriodInDays;
|
|
8903
|
+
await this.retryOnTransientControlPlane(() => this.dynamoDBClient.send(new UpdateContinuousBackupsCommand({
|
|
8904
|
+
TableName: tableName,
|
|
8905
|
+
PointInTimeRecoverySpecification: pitrSpec
|
|
8906
|
+
})), `enable PITR on ${tableName}`);
|
|
8907
|
+
this.logger.debug(`Set PointInTimeRecoveryEnabled=${enabled}${recoveryPeriodInDays !== void 0 ? ` RecoveryPeriodInDays=${recoveryPeriodInDays}` : ""} on DynamoDB table ${tableName}`);
|
|
8908
|
+
}
|
|
8909
|
+
/**
|
|
8910
|
+
* Retry a DynamoDB control-plane call on the transient "settling" errors AWS
|
|
8911
|
+
* returns when two table-modifying operations land back-to-back. Enabling
|
|
8912
|
+
* PITR (`UpdateContinuousBackups`) puts the table in a transient state, and a
|
|
8913
|
+
* subsequent `UpdateTimeToLive` is then rejected with "Backups are being
|
|
8914
|
+
* enabled for the table ... Please retry later". `ResourceInUseException`
|
|
8915
|
+
* ("table is being updated") and `LimitExceededException` are the same class.
|
|
8916
|
+
* Backoff: ~2s,4s,8s,16s,30s,30s... bounded to ~2min total, which comfortably
|
|
8917
|
+
* covers the few-second PITR-enable window.
|
|
8918
|
+
*/
|
|
8919
|
+
async retryOnTransientControlPlane(op, label, maxAttempts = 8) {
|
|
8920
|
+
let delayMs = 2e3;
|
|
8921
|
+
for (let attempt = 1;; attempt++) try {
|
|
8922
|
+
return await op();
|
|
8923
|
+
} catch (error) {
|
|
8924
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
8925
|
+
const name = error instanceof Error ? error.name : "";
|
|
8926
|
+
if (!(/being enabled|being updated|please retry later|backups are being/i.test(msg) || name === "ResourceInUseException" || name === "LimitExceededException") || attempt >= maxAttempts) throw error;
|
|
8927
|
+
this.logger.debug(`Transient error on "${label}" (attempt ${attempt}/${maxAttempts}): ${msg} — retrying in ${delayMs}ms`);
|
|
8928
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
8929
|
+
delayMs = Math.min(delayMs * 2, 3e4);
|
|
8930
|
+
}
|
|
8931
|
+
}
|
|
8932
|
+
/**
|
|
8933
|
+
* Apply the table's `TimeToLiveSpecification` via the separate
|
|
8934
|
+
* `UpdateTimeToLive` API (TTL does NOT ride on CreateTable).
|
|
8935
|
+
*
|
|
8936
|
+
* CFn shape is `{ AttributeName: string, Enabled: boolean }`. Called from
|
|
8937
|
+
* both `create()` (after the table is ACTIVE) and `update()` (only when the
|
|
8938
|
+
* value changed). On `update()`-side removal — when the template drops the
|
|
8939
|
+
* block but it was present before — we disable TTL using the PREVIOUS
|
|
8940
|
+
* `AttributeName` (AWS requires the attribute name even to disable TTL).
|
|
8941
|
+
*/
|
|
8942
|
+
async applyTimeToLive(tableName, spec, previousSpec) {
|
|
8943
|
+
if (spec !== void 0 && spec !== null) {
|
|
8944
|
+
const s = spec;
|
|
8945
|
+
const attributeName = s["AttributeName"];
|
|
8946
|
+
if (!attributeName) return;
|
|
8947
|
+
const enabled = s["Enabled"] !== void 0 ? Boolean(s["Enabled"]) : true;
|
|
8948
|
+
await this.retryOnTransientControlPlane(() => this.dynamoDBClient.send(new UpdateTimeToLiveCommand({
|
|
8949
|
+
TableName: tableName,
|
|
8950
|
+
TimeToLiveSpecification: {
|
|
8951
|
+
Enabled: enabled,
|
|
8952
|
+
AttributeName: attributeName
|
|
8953
|
+
}
|
|
8954
|
+
})), `set TTL on ${tableName}`);
|
|
8955
|
+
this.logger.debug(`Set TimeToLive Enabled=${enabled} AttributeName=${attributeName} on DynamoDB table ${tableName}`);
|
|
8956
|
+
return;
|
|
8957
|
+
}
|
|
8958
|
+
if (previousSpec !== void 0 && previousSpec !== null) {
|
|
8959
|
+
const prevAttributeName = previousSpec["AttributeName"];
|
|
8960
|
+
if (!prevAttributeName) return;
|
|
8961
|
+
await this.retryOnTransientControlPlane(() => this.dynamoDBClient.send(new UpdateTimeToLiveCommand({
|
|
8962
|
+
TableName: tableName,
|
|
8963
|
+
TimeToLiveSpecification: {
|
|
8964
|
+
Enabled: false,
|
|
8965
|
+
AttributeName: prevAttributeName
|
|
8966
|
+
}
|
|
8967
|
+
})), `disable TTL on ${tableName}`);
|
|
8968
|
+
this.logger.debug(`Disabled TimeToLive (AttributeName=${prevAttributeName}) on DynamoDB table ${tableName}`);
|
|
8969
|
+
}
|
|
8970
|
+
}
|
|
8971
|
+
/**
|
|
8855
8972
|
* Poll DescribeTable until the table reaches ACTIVE status
|
|
8856
8973
|
*
|
|
8857
8974
|
* Uses a tight polling loop (1s intervals) instead of CC API's exponential
|
|
@@ -8970,6 +9087,26 @@ var DynamoDBTableProvider = class {
|
|
|
8970
9087
|
if (err instanceof ResourceNotFoundException$1) return void 0;
|
|
8971
9088
|
throw err;
|
|
8972
9089
|
}
|
|
9090
|
+
try {
|
|
9091
|
+
const pitrDesc = (await this.dynamoDBClient.send(new DescribeContinuousBackupsCommand({ TableName: physicalId }))).ContinuousBackupsDescription?.PointInTimeRecoveryDescription;
|
|
9092
|
+
const pitrStatus = pitrDesc?.PointInTimeRecoveryStatus;
|
|
9093
|
+
if (pitrStatus) {
|
|
9094
|
+
const pitr = { PointInTimeRecoveryEnabled: pitrStatus === "ENABLED" };
|
|
9095
|
+
if (pitrStatus === "ENABLED" && pitrDesc?.RecoveryPeriodInDays !== void 0) pitr["RecoveryPeriodInDays"] = pitrDesc.RecoveryPeriodInDays;
|
|
9096
|
+
result["PointInTimeRecoverySpecification"] = pitr;
|
|
9097
|
+
}
|
|
9098
|
+
} catch (err) {
|
|
9099
|
+
this.logger.debug(`Could not read PointInTimeRecovery for ${physicalId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
9100
|
+
}
|
|
9101
|
+
try {
|
|
9102
|
+
const ttlDesc = (await this.dynamoDBClient.send(new DescribeTimeToLiveCommand({ TableName: physicalId }))).TimeToLiveDescription;
|
|
9103
|
+
if (ttlDesc?.TimeToLiveStatus === "ENABLED" && ttlDesc.AttributeName) result["TimeToLiveSpecification"] = {
|
|
9104
|
+
AttributeName: ttlDesc.AttributeName,
|
|
9105
|
+
Enabled: true
|
|
9106
|
+
};
|
|
9107
|
+
} catch (err) {
|
|
9108
|
+
this.logger.debug(`Could not read TimeToLive for ${physicalId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
9109
|
+
}
|
|
8973
9110
|
return result;
|
|
8974
9111
|
} catch (err) {
|
|
8975
9112
|
if (err instanceof ResourceNotFoundException$1) return void 0;
|
|
@@ -35145,7 +35282,7 @@ const EMPTY_ALLOW_SET = /* @__PURE__ */ new Set();
|
|
|
35145
35282
|
*
|
|
35146
35283
|
* - **Fresh hits**: a resource whose template uses one or more
|
|
35147
35284
|
* silent-drop top-level CFn properties. Annotation value is the list
|
|
35148
|
-
* of property names (e.g. `
|
|
35285
|
+
* of property names (e.g. `RecursiveLoop`).
|
|
35149
35286
|
* - **Sticky hits**: a resource whose deployed state records
|
|
35150
35287
|
* `provisionedBy: 'cc-api'` (from a prior deploy) even when the
|
|
35151
35288
|
* current template's silent-drop set is empty. Annotation value is
|
|
@@ -51125,7 +51262,7 @@ function reorderArgs(argv) {
|
|
|
51125
51262
|
*/
|
|
51126
51263
|
async function main() {
|
|
51127
51264
|
const program = new Command();
|
|
51128
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
51265
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.173.0");
|
|
51129
51266
|
program.addCommand(createBootstrapCommand());
|
|
51130
51267
|
program.addCommand(createSynthCommand());
|
|
51131
51268
|
program.addCommand(createListCommand());
|