@go-to-k/cdkd 0.107.0 → 0.109.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 { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-CuHRHcyW.js";
|
|
3
|
-
import { A as resolveApp, B as CdkdError, C as AssetPublisher, D as Synthesizer, E as buildDockerImage, F as warnDeprecatedNoPrefixCliFlag, G as PartialFailureError, I as AssemblyReader, J as ResourceUpdateNotSupportedError, K as ProvisioningError, M as resolveSkipPrefix, N as resolveStateBucketWithDefault, O as getDefaultStateBucketName, P as resolveStateBucketWithDefaultAndSource, R as resolveBucketRegion, S as shouldRetainResource, T as WorkGraph, U as LocalInvokeBuildError, X as StackHasActiveImportsError, Y as RouteDiscoveryError, Z as StackTerminationProtectionError, _ as DiffCalculator, a as withRetry, at as getLogger, b as LockManager, c as collectInlinePolicyNamesManagedBySiblings, ct as getLiveRenderer, d as normalizeAwsTagsToCfn, dt as generateResourceName, f as resolveExplicitPhysicalId, ft as generateResourceNameWithFallback, g as IntrinsicFunctionResolver, h as assertRegionMatch, i as withResourceDeadline, j as resolveCaptureObservedState, k as getLegacyStateBucketName, l as CDK_PATH_TAG, lt as PATTERN_B_NAME_PROPERTIES, m as CloudControlProvider, mt as withStackName, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as normalizeAwsError, o as IMPLICIT_DELETE_DEPENDENCIES, p as ProviderRegistry, pt as withSkipPrefix, q as ResourceTimeoutError, r as DeployEngine, rt as withErrorHandling, s as IAMRoleProvider, st as runStackBuffered, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as matchesCdkPath, ut as PATTERN_B_RESOURCE_TYPES, v as DagBuilder, w as stringifyValue, x as S3StateBackend, y as TemplateParser } from "./deploy-engine-
|
|
3
|
+
import { A as resolveApp, B as CdkdError, C as AssetPublisher, D as Synthesizer, E as buildDockerImage, F as warnDeprecatedNoPrefixCliFlag, G as PartialFailureError, I as AssemblyReader, J as ResourceUpdateNotSupportedError, K as ProvisioningError, M as resolveSkipPrefix, N as resolveStateBucketWithDefault, O as getDefaultStateBucketName, P as resolveStateBucketWithDefaultAndSource, R as resolveBucketRegion, S as shouldRetainResource, T as WorkGraph, U as LocalInvokeBuildError, X as StackHasActiveImportsError, Y as RouteDiscoveryError, Z as StackTerminationProtectionError, _ as DiffCalculator, a as withRetry, at as getLogger, b as LockManager, c as collectInlinePolicyNamesManagedBySiblings, ct as getLiveRenderer, d as normalizeAwsTagsToCfn, dt as generateResourceName, f as resolveExplicitPhysicalId, ft as generateResourceNameWithFallback, g as IntrinsicFunctionResolver, h as assertRegionMatch, i as withResourceDeadline, j as resolveCaptureObservedState, k as getLegacyStateBucketName, l as CDK_PATH_TAG, lt as PATTERN_B_NAME_PROPERTIES, m as CloudControlProvider, mt as withStackName, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as normalizeAwsError, o as IMPLICIT_DELETE_DEPENDENCIES, p as ProviderRegistry, pt as withSkipPrefix, q as ResourceTimeoutError, r as DeployEngine, rt as withErrorHandling, s as IAMRoleProvider, st as runStackBuffered, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as matchesCdkPath, ut as PATTERN_B_RESOURCE_TYPES, v as DagBuilder, w as stringifyValue, x as S3StateBackend, y as TemplateParser } from "./deploy-engine-Br8DvrvB.js";
|
|
4
4
|
import { createHash, createPublicKey, createVerify, randomBytes, randomUUID } from "node:crypto";
|
|
5
5
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListBucketsCommand, ListDirectoryBucketsCommand, 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";
|
|
6
6
|
import { AddRoleToInstanceProfileCommand, AddUserToGroupCommand, AttachGroupPolicyCommand, AttachUserPolicyCommand, CreateGroupCommand, CreateInstanceProfileCommand, CreateLoginProfileCommand, CreateUserCommand, DeleteAccessKeyCommand, DeleteGroupCommand, DeleteGroupPolicyCommand, DeleteInstanceProfileCommand, DeleteLoginProfileCommand, DeleteRolePolicyCommand, DeleteUserCommand, DeleteUserPermissionsBoundaryCommand, DeleteUserPolicyCommand, DetachGroupPolicyCommand, DetachUserPolicyCommand, GetGroupCommand, GetGroupPolicyCommand, GetInstanceProfileCommand, GetRolePolicyCommand, GetUserCommand, GetUserPolicyCommand, IAMClient, ListAccessKeysCommand, ListAttachedGroupPoliciesCommand, ListAttachedUserPoliciesCommand, ListGroupPoliciesCommand, ListGroupsForUserCommand, ListInstanceProfilesCommand, ListUserPoliciesCommand, ListUserTagsCommand, ListUsersCommand, NoSuchEntityException, PutGroupPolicyCommand, PutRolePolicyCommand, PutUserPermissionsBoundaryCommand, PutUserPolicyCommand, RemoveRoleFromInstanceProfileCommand, RemoveUserFromGroupCommand, TagUserCommand, UntagUserCommand, UpdateLoginProfileCommand } from "@aws-sdk/client-iam";
|
|
@@ -30,12 +30,12 @@ import { CreateAliasCommand, CreateKeyCommand, DeleteAliasCommand, DescribeKeyCo
|
|
|
30
30
|
import { promisify } from "node:util";
|
|
31
31
|
import { CreateRepositoryCommand, DeleteLifecyclePolicyCommand, DeleteRepositoryCommand, DeleteRepositoryPolicyCommand, DescribeRepositoriesCommand, ECRClient, GetAuthorizationTokenCommand, GetLifecyclePolicyCommand, LifecyclePolicyNotFoundException, ListTagsForResourceCommand as ListTagsForResourceCommand$7, PutImageScanningConfigurationCommand, PutImageTagMutabilityCommand, PutLifecyclePolicyCommand, RepositoryNotFoundException, SetRepositoryPolicyCommand, TagResourceCommand as TagResourceCommand$9 } from "@aws-sdk/client-ecr";
|
|
32
32
|
import graphlib from "graphlib";
|
|
33
|
-
import { AddTagsToResourceCommand as AddTagsToResourceCommand$1, CreateDBClusterCommand, CreateDBInstanceCommand, CreateDBProxyCommand, CreateDBSubnetGroupCommand, DBProxyNotFoundFault, DBProxyTargetGroupNotFoundFault, DBProxyTargetNotFoundFault, DeleteDBClusterCommand, DeleteDBInstanceCommand, DeleteDBProxyCommand, DeleteDBSubnetGroupCommand, DeregisterDBProxyTargetsCommand, DescribeDBClustersCommand, DescribeDBInstancesCommand, DescribeDBProxiesCommand, DescribeDBProxyTargetGroupsCommand, DescribeDBSubnetGroupsCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$8, ModifyDBClusterCommand, ModifyDBInstanceCommand, ModifyDBProxyCommand, ModifyDBProxyTargetGroupCommand, ModifyDBSubnetGroupCommand, RDSClient, RegisterDBProxyTargetsCommand, RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand$1 } from "@aws-sdk/client-rds";
|
|
33
|
+
import { AddTagsToResourceCommand as AddTagsToResourceCommand$1, CreateDBClusterCommand, CreateDBInstanceCommand, CreateDBProxyCommand, CreateDBProxyEndpointCommand, CreateDBSubnetGroupCommand, DBProxyEndpointNotFoundFault, DBProxyNotFoundFault, DBProxyTargetGroupNotFoundFault, DBProxyTargetNotFoundFault, DeleteDBClusterCommand, DeleteDBInstanceCommand, DeleteDBProxyCommand, DeleteDBProxyEndpointCommand, DeleteDBSubnetGroupCommand, DeregisterDBProxyTargetsCommand, DescribeDBClustersCommand, DescribeDBInstancesCommand, DescribeDBProxiesCommand, DescribeDBProxyEndpointsCommand, DescribeDBProxyTargetGroupsCommand, DescribeDBSubnetGroupsCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$8, ModifyDBClusterCommand, ModifyDBInstanceCommand, ModifyDBProxyCommand, ModifyDBProxyEndpointCommand, ModifyDBProxyTargetGroupCommand, ModifyDBSubnetGroupCommand, RDSClient, RegisterDBProxyTargetsCommand, RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand$1 } from "@aws-sdk/client-rds";
|
|
34
34
|
import { Command, Option } from "commander";
|
|
35
35
|
import { writeFileSync as writeFileSync$1 } from "fs";
|
|
36
36
|
import { join as join$1 } from "path";
|
|
37
37
|
import * as zlib from "node:zlib";
|
|
38
|
-
import { ApplicationAutoScalingClient, DescribeScalableTargetsCommand, DescribeScalingPoliciesCommand } from "@aws-sdk/client-application-auto-scaling";
|
|
38
|
+
import { ApplicationAutoScalingClient, DeleteScalingPolicyCommand, DeregisterScalableTargetCommand, DescribeScalableTargetsCommand, DescribeScalingPoliciesCommand, PutScalingPolicyCommand, RegisterScalableTargetCommand } from "@aws-sdk/client-application-auto-scaling";
|
|
39
39
|
import { ApiGatewayV2Client, CreateApiCommand, CreateAuthorizerCommand as CreateAuthorizerCommand$1, CreateIntegrationCommand, CreateRouteCommand as CreateRouteCommand$1, CreateStageCommand as CreateStageCommand$1, DeleteApiCommand, DeleteAuthorizerCommand as DeleteAuthorizerCommand$1, DeleteIntegrationCommand, DeleteRouteCommand as DeleteRouteCommand$1, DeleteStageCommand as DeleteStageCommand$1, GetApiCommand, GetApisCommand, GetAuthorizerCommand as GetAuthorizerCommand$1, GetIntegrationCommand, GetRouteCommand, GetStageCommand as GetStageCommand$1, NotFoundException as NotFoundException$3, UpdateApiCommand, UpdateAuthorizerCommand as UpdateAuthorizerCommand$1, UpdateIntegrationCommand, UpdateRouteCommand, UpdateStageCommand as UpdateStageCommand$1 } from "@aws-sdk/client-apigatewayv2";
|
|
40
40
|
import { CreateStateMachineCommand, DeleteStateMachineCommand, DescribeStateMachineCommand, ListStateMachinesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$9, SFNClient, StateMachineDoesNotExist, TagResourceCommand as TagResourceCommand$10, UntagResourceCommand as UntagResourceCommand$9, UpdateStateMachineCommand } from "@aws-sdk/client-sfn";
|
|
41
41
|
import { CreateClusterCommand, CreateServiceCommand, DeleteClusterCommand, DeleteServiceCommand, DeregisterTaskDefinitionCommand, DescribeClustersCommand, DescribeServicesCommand, DescribeTaskDefinitionCommand, ECSClient, ListClustersCommand, ListServicesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$10, PutClusterCapacityProvidersCommand, RegisterTaskDefinitionCommand, TagResourceCommand as TagResourceCommand$11, UntagResourceCommand as UntagResourceCommand$10, UpdateClusterCommand, UpdateServiceCommand } from "@aws-sdk/client-ecs";
|
|
@@ -7984,6 +7984,20 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
7984
7984
|
return client;
|
|
7985
7985
|
}
|
|
7986
7986
|
/**
|
|
7987
|
+
* Lazy-init + cache the local-region `ApplicationAutoScalingClient`.
|
|
7988
|
+
* Previously `applyAutoScalingDiff` constructed a fresh client per
|
|
7989
|
+
* call when no `client` arg was passed, leaking SDK clients (each
|
|
7990
|
+
* holds its own HTTP agent) on multi-stack runs with many
|
|
7991
|
+
* GlobalTables (PR #403 review minor #4).
|
|
7992
|
+
*/
|
|
7993
|
+
localAutoScalingClient;
|
|
7994
|
+
async getLocalAutoScalingClient() {
|
|
7995
|
+
if (this.localAutoScalingClient) return this.localAutoScalingClient;
|
|
7996
|
+
const region = await this.dynamoDBClient.config.region() ?? "";
|
|
7997
|
+
this.localAutoScalingClient = new ApplicationAutoScalingClient({ region });
|
|
7998
|
+
return this.localAutoScalingClient;
|
|
7999
|
+
}
|
|
8000
|
+
/**
|
|
7987
8001
|
* Construct the regional table ARN for a cross-region replica of a
|
|
7988
8002
|
* GlobalTable. AWS replicates the same `TableName` across every
|
|
7989
8003
|
* replica region, with each replica's ARN differing only in the
|
|
@@ -8237,10 +8251,19 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
8237
8251
|
await this.dynamoDBClient.send(new UpdateTableCommand(billingUpdate));
|
|
8238
8252
|
await this.waitForTableActiveAfterUpdate(physicalId, logicalId);
|
|
8239
8253
|
}
|
|
8254
|
+
const writeAutoScalingOld = (previousProperties["WriteProvisionedThroughputSettings"] ?? {})["WriteCapacityAutoScalingSettings"];
|
|
8255
|
+
const writeAutoScalingNew = (properties["WriteProvisionedThroughputSettings"] ?? {})["WriteCapacityAutoScalingSettings"];
|
|
8256
|
+
const effectiveNewAutoScaling = oldBilling === "PROVISIONED" && newBilling === "PAY_PER_REQUEST" ? void 0 : writeAutoScalingNew;
|
|
8257
|
+
if ((newBilling === "PROVISIONED" || oldBilling === "PROVISIONED") && !deepEqual$1(writeAutoScalingOld, effectiveNewAutoScaling)) await this.applyAutoScalingDiff(physicalId, "dynamodb:table:WriteCapacityUnits", writeAutoScalingOld, effectiveNewAutoScaling);
|
|
8240
8258
|
const replicaDiff = diffReplicas(previousProperties["Replicas"] ?? [], properties["Replicas"] ?? []);
|
|
8241
8259
|
for (const replica of replicaDiff.removed) {
|
|
8242
8260
|
const region = replica["Region"];
|
|
8243
8261
|
if (!region || region === currentRegion) continue;
|
|
8262
|
+
const removedReadAutoScaling = (replica["ReadProvisionedThroughputSettings"] ?? {})["ReadCapacityAutoScalingSettings"];
|
|
8263
|
+
if (removedReadAutoScaling) {
|
|
8264
|
+
const regionalAutoScalingClient = this.getRegionalAutoScalingClient(region);
|
|
8265
|
+
await this.applyAutoScalingDiff(physicalId, "dynamodb:table:ReadCapacityUnits", removedReadAutoScaling, void 0, regionalAutoScalingClient);
|
|
8266
|
+
}
|
|
8244
8267
|
await this.dynamoDBClient.send(new UpdateTableCommand({
|
|
8245
8268
|
TableName: physicalId,
|
|
8246
8269
|
ReplicaUpdates: [{ Delete: { RegionName: region } }]
|
|
@@ -8251,11 +8274,17 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
8251
8274
|
const region = replica["Region"];
|
|
8252
8275
|
if (!region || region === currentRegion) continue;
|
|
8253
8276
|
await this.addReplica(physicalId, replica, region, logicalId);
|
|
8277
|
+
const newReadAutoScaling = (replica["ReadProvisionedThroughputSettings"] ?? {})["ReadCapacityAutoScalingSettings"];
|
|
8278
|
+
if (newBilling === "PROVISIONED" && newReadAutoScaling) {
|
|
8279
|
+
const regionalAutoScalingClient = this.getRegionalAutoScalingClient(region);
|
|
8280
|
+
await this.applyAutoScalingDiff(physicalId, "dynamodb:table:ReadCapacityUnits", void 0, newReadAutoScaling, regionalAutoScalingClient);
|
|
8281
|
+
}
|
|
8254
8282
|
}
|
|
8255
8283
|
for (const replica of replicaDiff.modified) {
|
|
8256
8284
|
const region = replica["Region"];
|
|
8257
8285
|
if (!region || region === currentRegion) continue;
|
|
8258
|
-
const
|
|
8286
|
+
const oldReplica = (previousProperties["Replicas"] ?? []).find((r) => r["Region"] === region);
|
|
8287
|
+
const oldReplicaTags = oldReplica?.["Tags"];
|
|
8259
8288
|
const newReplicaTags = replica["Tags"];
|
|
8260
8289
|
if (!deepEqual$1(oldReplicaTags, newReplicaTags)) if (tableArn) {
|
|
8261
8290
|
const replicaArn = this.replicaArnForRegion(tableArn, region);
|
|
@@ -8267,6 +8296,13 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
8267
8296
|
}
|
|
8268
8297
|
else this.logger.warn(`Could not derive replica ARN for region ${region} from ${tableArn} — skipping Tags propagation for ${physicalId}`);
|
|
8269
8298
|
} else this.logger.warn(`Local DescribeTable returned no TableArn — cannot propagate Tags to cross-region replica ${region} of ${physicalId}`);
|
|
8299
|
+
const oldReadAutoScaling = (oldReplica?.["ReadProvisionedThroughputSettings"] ?? {})["ReadCapacityAutoScalingSettings"];
|
|
8300
|
+
const newReadAutoScaling = (replica["ReadProvisionedThroughputSettings"] ?? {})["ReadCapacityAutoScalingSettings"];
|
|
8301
|
+
const effectiveNewReadAutoScaling = newBilling === "PAY_PER_REQUEST" ? void 0 : newReadAutoScaling;
|
|
8302
|
+
if ((newBilling === "PROVISIONED" || oldBilling === "PROVISIONED") && !deepEqual$1(oldReadAutoScaling, effectiveNewReadAutoScaling)) {
|
|
8303
|
+
const regionalAutoScalingClient = this.getRegionalAutoScalingClient(region);
|
|
8304
|
+
await this.applyAutoScalingDiff(physicalId, "dynamodb:table:ReadCapacityUnits", oldReadAutoScaling, effectiveNewReadAutoScaling, regionalAutoScalingClient);
|
|
8305
|
+
}
|
|
8270
8306
|
const updateAction = { RegionName: region };
|
|
8271
8307
|
if (replica["KMSMasterKeyId"] !== void 0) updateAction.KMSMasterKeyId = replica["KMSMasterKeyId"];
|
|
8272
8308
|
if (replica["GlobalSecondaryIndexes"]) updateAction.GlobalSecondaryIndexes = replica["GlobalSecondaryIndexes"];
|
|
@@ -8405,6 +8441,127 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
8405
8441
|
}
|
|
8406
8442
|
}
|
|
8407
8443
|
/**
|
|
8444
|
+
* Apply an application-autoscaling diff for one (tableName, dimension)
|
|
8445
|
+
* pair (Issue #402 / PR closing Issue #395's deferred items).
|
|
8446
|
+
*
|
|
8447
|
+
* Dimension is either:
|
|
8448
|
+
* - `dynamodb:table:WriteCapacityUnits` (table-level write capacity),
|
|
8449
|
+
* paired with the local-region autoscaling client.
|
|
8450
|
+
* - `dynamodb:table:ReadCapacityUnits` (per-replica read capacity),
|
|
8451
|
+
* paired with a region-scoped autoscaling client returned by
|
|
8452
|
+
* `getRegionalAutoScalingClient`.
|
|
8453
|
+
*
|
|
8454
|
+
* Diff semantics (idempotent upsert, per Issue #402 spec):
|
|
8455
|
+
* - new auto-scaling settings present (Min/Max + TargetValue) →
|
|
8456
|
+
* `RegisterScalableTarget` (upsert) + `PutScalingPolicy` (upsert).
|
|
8457
|
+
* AWS's `RegisterScalableTarget` accepts no-op Min/Max changes
|
|
8458
|
+
* silently, and `PutScalingPolicy` is idempotent on the same
|
|
8459
|
+
* policy name (`DynamoDB{Write,Read}CapacityUtilization:table/<name>`).
|
|
8460
|
+
* - old auto-scaling settings present but new ones absent (= null) →
|
|
8461
|
+
* `DeleteScalingPolicy` + `DeregisterScalableTarget`. AWS rejects
|
|
8462
|
+
* `DeregisterScalableTarget` on a still-policy-attached target,
|
|
8463
|
+
* so the policy must be deleted FIRST.
|
|
8464
|
+
* - neither side has auto-scaling settings → no-op.
|
|
8465
|
+
*
|
|
8466
|
+
* **Best-effort**: any AWS error is logged at WARN with the per-API
|
|
8467
|
+
* recovery command and the deploy continues — auto-scaling drift is
|
|
8468
|
+
* recoverable on the next deploy, and an aborted deploy is much worse
|
|
8469
|
+
* UX than a transient auto-scaling miss. This matches the cross-region
|
|
8470
|
+
* Tags propagation contract (PR #393).
|
|
8471
|
+
*
|
|
8472
|
+
* **Policy naming** matches AWS's CDK / console default:
|
|
8473
|
+
* `DynamoDBWriteCapacityUtilization:table/<table-name>` (write)
|
|
8474
|
+
* `DynamoDBReadCapacityUtilization:table/<table-name>` (read)
|
|
8475
|
+
* so re-imports against a console-created target also match.
|
|
8476
|
+
*
|
|
8477
|
+
* **`SeedCapacity` is intentionally NOT forwarded** — it is a CFn
|
|
8478
|
+
* create-only field with no corresponding `RegisterScalableTarget`
|
|
8479
|
+
* surface; `readAutoScalingSettings` also explicitly skips it.
|
|
8480
|
+
*/
|
|
8481
|
+
async applyAutoScalingDiff(tableName, dimension, oldSettings, newSettings, client) {
|
|
8482
|
+
const isWrite = dimension === "dynamodb:table:WriteCapacityUnits";
|
|
8483
|
+
const policyName = isWrite ? `DynamoDBWriteCapacityUtilization:table/${tableName}` : `DynamoDBReadCapacityUtilization:table/${tableName}`;
|
|
8484
|
+
const metricType = isWrite ? "DynamoDBWriteCapacityUtilization" : "DynamoDBReadCapacityUtilization";
|
|
8485
|
+
const resourceId = `table/${tableName}`;
|
|
8486
|
+
const asClient = client ?? await this.getLocalAutoScalingClient();
|
|
8487
|
+
const oldEnabled = oldSettings !== void 0 && oldSettings !== null;
|
|
8488
|
+
const newEnabled = newSettings !== void 0 && newSettings !== null;
|
|
8489
|
+
if (!oldEnabled && !newEnabled) return;
|
|
8490
|
+
if (newEnabled) {
|
|
8491
|
+
const minCapacity = Number(newSettings["MinCapacity"] ?? 0);
|
|
8492
|
+
const maxCapacity = Number(newSettings["MaxCapacity"] ?? 0);
|
|
8493
|
+
if (!Number.isFinite(minCapacity) || !Number.isFinite(maxCapacity)) {
|
|
8494
|
+
this.logger.warn(`Cannot apply auto-scaling diff on ${tableName} (${dimension}): MinCapacity / MaxCapacity must be numbers, got ${String(newSettings["MinCapacity"])} / ${String(newSettings["MaxCapacity"])}`);
|
|
8495
|
+
return;
|
|
8496
|
+
}
|
|
8497
|
+
try {
|
|
8498
|
+
await asClient.send(new RegisterScalableTargetCommand({
|
|
8499
|
+
ServiceNamespace: "dynamodb",
|
|
8500
|
+
ResourceId: resourceId,
|
|
8501
|
+
ScalableDimension: dimension,
|
|
8502
|
+
MinCapacity: minCapacity,
|
|
8503
|
+
MaxCapacity: maxCapacity
|
|
8504
|
+
}));
|
|
8505
|
+
} catch (err) {
|
|
8506
|
+
this.logger.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}`);
|
|
8507
|
+
return;
|
|
8508
|
+
}
|
|
8509
|
+
const tttCfg = newSettings["TargetTrackingScalingPolicyConfiguration"] ?? {};
|
|
8510
|
+
const targetValue = Number(tttCfg["TargetValue"]);
|
|
8511
|
+
if (!Number.isFinite(targetValue)) {
|
|
8512
|
+
this.logger.warn(`Auto-scaling target registered on ${tableName} (${dimension}) but TargetValue is missing or non-numeric — skipping PutScalingPolicy. Provide TargetTrackingScalingPolicyConfiguration.TargetValue in the template.`);
|
|
8513
|
+
return;
|
|
8514
|
+
}
|
|
8515
|
+
const targetTrackingConfig = {
|
|
8516
|
+
PredefinedMetricSpecification: { PredefinedMetricType: metricType },
|
|
8517
|
+
TargetValue: targetValue
|
|
8518
|
+
};
|
|
8519
|
+
if (tttCfg["ScaleInCooldown"] !== void 0) targetTrackingConfig["ScaleInCooldown"] = Number(tttCfg["ScaleInCooldown"]);
|
|
8520
|
+
if (tttCfg["ScaleOutCooldown"] !== void 0) targetTrackingConfig["ScaleOutCooldown"] = Number(tttCfg["ScaleOutCooldown"]);
|
|
8521
|
+
if (tttCfg["DisableScaleIn"] !== void 0) targetTrackingConfig["DisableScaleIn"] = Boolean(tttCfg["DisableScaleIn"]);
|
|
8522
|
+
try {
|
|
8523
|
+
await asClient.send(new PutScalingPolicyCommand({
|
|
8524
|
+
PolicyName: policyName,
|
|
8525
|
+
ServiceNamespace: "dynamodb",
|
|
8526
|
+
ResourceId: resourceId,
|
|
8527
|
+
ScalableDimension: dimension,
|
|
8528
|
+
PolicyType: "TargetTrackingScaling",
|
|
8529
|
+
TargetTrackingScalingPolicyConfiguration: targetTrackingConfig
|
|
8530
|
+
}));
|
|
8531
|
+
this.logger.debug(`Upserted auto-scaling policy ${policyName} on ${tableName} (${dimension})`);
|
|
8532
|
+
} catch (err) {
|
|
8533
|
+
this.logger.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`);
|
|
8534
|
+
}
|
|
8535
|
+
return;
|
|
8536
|
+
}
|
|
8537
|
+
const isObjectNotFound = (err) => {
|
|
8538
|
+
if (!(err instanceof Error)) return false;
|
|
8539
|
+
const name = err.name ?? "";
|
|
8540
|
+
const msg = err.message ?? "";
|
|
8541
|
+
return name === "ObjectNotFoundException" || msg.includes("No scaling policy found") || msg.includes("No scalable target found");
|
|
8542
|
+
};
|
|
8543
|
+
try {
|
|
8544
|
+
await asClient.send(new DeleteScalingPolicyCommand({
|
|
8545
|
+
PolicyName: policyName,
|
|
8546
|
+
ServiceNamespace: "dynamodb",
|
|
8547
|
+
ResourceId: resourceId,
|
|
8548
|
+
ScalableDimension: dimension
|
|
8549
|
+
}));
|
|
8550
|
+
} catch (err) {
|
|
8551
|
+
if (!isObjectNotFound(err)) this.logger.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}`);
|
|
8552
|
+
}
|
|
8553
|
+
try {
|
|
8554
|
+
await asClient.send(new DeregisterScalableTargetCommand({
|
|
8555
|
+
ServiceNamespace: "dynamodb",
|
|
8556
|
+
ResourceId: resourceId,
|
|
8557
|
+
ScalableDimension: dimension
|
|
8558
|
+
}));
|
|
8559
|
+
this.logger.debug(`Deregistered auto-scaling target ${resourceId} (${dimension})`);
|
|
8560
|
+
} catch (err) {
|
|
8561
|
+
if (!isObjectNotFound(err)) this.logger.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}`);
|
|
8562
|
+
}
|
|
8563
|
+
}
|
|
8564
|
+
/**
|
|
8408
8565
|
* Delete a DynamoDB Global Table.
|
|
8409
8566
|
*
|
|
8410
8567
|
* Order is load-bearing:
|
|
@@ -8450,6 +8607,7 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
8450
8607
|
const region = replica.RegionName;
|
|
8451
8608
|
if (!region || region === currentRegion) continue;
|
|
8452
8609
|
try {
|
|
8610
|
+
await this.applyAutoScalingDiff(physicalId, "dynamodb:table:ReadCapacityUnits", {}, void 0, this.getRegionalAutoScalingClient(region));
|
|
8453
8611
|
await this.dynamoDBClient.send(new UpdateTableCommand({
|
|
8454
8612
|
TableName: physicalId,
|
|
8455
8613
|
ReplicaUpdates: [{ Delete: { RegionName: region } }]
|
|
@@ -8459,6 +8617,9 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
8459
8617
|
if (!(replicaErr instanceof ResourceNotFoundException$1)) throw replicaErr;
|
|
8460
8618
|
}
|
|
8461
8619
|
}
|
|
8620
|
+
const localAsClient = await this.getLocalAutoScalingClient();
|
|
8621
|
+
await this.applyAutoScalingDiff(physicalId, "dynamodb:table:ReadCapacityUnits", {}, void 0, localAsClient);
|
|
8622
|
+
await this.applyAutoScalingDiff(physicalId, "dynamodb:table:WriteCapacityUnits", {}, void 0, localAsClient);
|
|
8462
8623
|
} catch (describeErr) {
|
|
8463
8624
|
if (!(describeErr instanceof ResourceNotFoundException$1)) {
|
|
8464
8625
|
const cause = describeErr instanceof Error ? describeErr : void 0;
|
|
@@ -18395,8 +18556,8 @@ var RDSProvider = class {
|
|
|
18395
18556
|
|
|
18396
18557
|
//#endregion
|
|
18397
18558
|
//#region src/provisioning/providers/rds-dbproxy-provider.ts
|
|
18398
|
-
const POLL_INTERVAL_MS = 5e3;
|
|
18399
|
-
const POLL_TIMEOUT_MS = 900 * 1e3;
|
|
18559
|
+
const POLL_INTERVAL_MS$1 = 5e3;
|
|
18560
|
+
const POLL_TIMEOUT_MS$1 = 900 * 1e3;
|
|
18400
18561
|
/**
|
|
18401
18562
|
* AWS RDS DBProxy Provider
|
|
18402
18563
|
*
|
|
@@ -18483,7 +18644,7 @@ var RDSDBProxyProvider = class {
|
|
|
18483
18644
|
let endpoint;
|
|
18484
18645
|
let dbProxyArn;
|
|
18485
18646
|
let vpcId;
|
|
18486
|
-
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
18647
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS$1;
|
|
18487
18648
|
let status;
|
|
18488
18649
|
while (Date.now() < deadline) {
|
|
18489
18650
|
try {
|
|
@@ -18500,7 +18661,7 @@ var RDSDBProxyProvider = class {
|
|
|
18500
18661
|
if (error instanceof DBProxyNotFoundFault) {} else if (error instanceof ProvisioningError) throw error;
|
|
18501
18662
|
else throw this.wrapError(error, "CREATE (poll)", resourceType, logicalId, dbProxyName);
|
|
18502
18663
|
}
|
|
18503
|
-
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
18664
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS$1));
|
|
18504
18665
|
}
|
|
18505
18666
|
if (!endpoint || !dbProxyArn) throw new ProvisioningError(`Timed out waiting for DBProxy ${dbProxyName} to become available (last status: ${status ?? "unknown"})`, resourceType, logicalId, dbProxyName);
|
|
18506
18667
|
return {
|
|
@@ -18514,6 +18675,11 @@ var RDSDBProxyProvider = class {
|
|
|
18514
18675
|
}
|
|
18515
18676
|
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
18516
18677
|
const client = this.getClient();
|
|
18678
|
+
for (const field of [
|
|
18679
|
+
"DBProxyName",
|
|
18680
|
+
"EngineFamily",
|
|
18681
|
+
"VpcSubnetIds"
|
|
18682
|
+
]) if (JSON.stringify(properties[field]) !== JSON.stringify(previousProperties[field])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `${field} is immutable on AWS::RDS::DBProxy — destroy + redeploy to change it`);
|
|
18517
18683
|
const input = { DBProxyName: physicalId };
|
|
18518
18684
|
let hasModify = false;
|
|
18519
18685
|
for (const key of [
|
|
@@ -18556,7 +18722,7 @@ var RDSDBProxyProvider = class {
|
|
|
18556
18722
|
}
|
|
18557
18723
|
throw this.wrapError(error, "DELETE", resourceType, logicalId, physicalId);
|
|
18558
18724
|
}
|
|
18559
|
-
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
18725
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS$1;
|
|
18560
18726
|
while (Date.now() < deadline) {
|
|
18561
18727
|
try {
|
|
18562
18728
|
await client.send(new DescribeDBProxiesCommand({ DBProxyName: physicalId }));
|
|
@@ -18567,7 +18733,7 @@ var RDSDBProxyProvider = class {
|
|
|
18567
18733
|
}
|
|
18568
18734
|
throw this.wrapError(error, "DELETE (poll)", resourceType, logicalId, physicalId);
|
|
18569
18735
|
}
|
|
18570
|
-
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
18736
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS$1));
|
|
18571
18737
|
}
|
|
18572
18738
|
throw new ProvisioningError(`Timed out waiting for DBProxy ${physicalId} to fully delete`, resourceType, logicalId, physicalId);
|
|
18573
18739
|
}
|
|
@@ -18742,6 +18908,337 @@ var RDSDBProxyProvider = class {
|
|
|
18742
18908
|
}
|
|
18743
18909
|
};
|
|
18744
18910
|
|
|
18911
|
+
//#endregion
|
|
18912
|
+
//#region src/provisioning/providers/rds-dbproxy-endpoint-provider.ts
|
|
18913
|
+
const POLL_INTERVAL_MS = 5e3;
|
|
18914
|
+
const POLL_TIMEOUT_MS = 900 * 1e3;
|
|
18915
|
+
/**
|
|
18916
|
+
* AWS RDS DBProxyEndpoint Provider
|
|
18917
|
+
*
|
|
18918
|
+
* Implements resource provisioning for `AWS::RDS::DBProxyEndpoint` — the
|
|
18919
|
+
* additional read/write or read-only endpoint that can be attached to a
|
|
18920
|
+
* parent DBProxy.
|
|
18921
|
+
*
|
|
18922
|
+
* **Why a dedicated SDK provider** (per `feedback_dedicated_provider_over_special_case.md`):
|
|
18923
|
+
* completes the RDS DBProxy family started in PR #387 (`DBProxyTargetGroup`)
|
|
18924
|
+
* and PR #394 (`DBProxy`). Keeps the whole family on one codebase so create /
|
|
18925
|
+
* update / delete handling stays consistent across the parent + endpoints +
|
|
18926
|
+
* target-group children.
|
|
18927
|
+
*
|
|
18928
|
+
* **Lifecycle**:
|
|
18929
|
+
* - `create`: validates required fields (`DBProxyName` / `VpcSubnetIds`),
|
|
18930
|
+
* issues `CreateDBProxyEndpointCommand`, then polls `DescribeDBProxyEndpoints`
|
|
18931
|
+
* until `Status === 'available'`. Returns `physicalId = DBProxyEndpointName`
|
|
18932
|
+
* plus `Endpoint` / `DBProxyEndpointArn` / `IsDefault` / `VpcId` in
|
|
18933
|
+
* `attributes`.
|
|
18934
|
+
* - `update`: `ModifyDBProxyEndpointCommand` for the mutable fields
|
|
18935
|
+
* (`VpcSecurityGroupIds` → SDK input `VpcSecurityGroupIds`,
|
|
18936
|
+
* `NewDBProxyEndpointName` via rename). Tags diff via separate
|
|
18937
|
+
* `AddTagsToResource` / `RemoveTagsFromResource` calls. DBProxyName /
|
|
18938
|
+
* VpcSubnetIds / TargetRole are immutable on AWS.
|
|
18939
|
+
* - `delete`: `DeleteDBProxyEndpointCommand`, then polls until
|
|
18940
|
+
* `DBProxyEndpointNotFoundFault`. Idempotent on NotFound (region-match
|
|
18941
|
+
* gated). `DBProxyNotFoundFault` also idempotent — if the parent DBProxy
|
|
18942
|
+
* is already gone via CASCADE, the endpoint is too.
|
|
18943
|
+
* - `getAttribute`: `Endpoint` / `DBProxyEndpointArn` / `IsDefault` / `VpcId`
|
|
18944
|
+
* via `DescribeDBProxyEndpoints`, cached per `(physicalId, attribute)`.
|
|
18945
|
+
* - `import`: explicit `--resource <id>=<DBProxyEndpointName>` first; falls
|
|
18946
|
+
* back to paginated auto-lookup via `DescribeDBProxyEndpoints` +
|
|
18947
|
+
* `ListTagsForResource` matching `aws:cdk:path`.
|
|
18948
|
+
*
|
|
18949
|
+
* **physicalId** = DBProxyEndpointName (matches CFn `primaryIdentifier`).
|
|
18950
|
+
*/
|
|
18951
|
+
var RDSDBProxyEndpointProvider = class {
|
|
18952
|
+
rdsClient;
|
|
18953
|
+
providerRegion = process.env["AWS_REGION"];
|
|
18954
|
+
logger = getLogger().child("RDSDBProxyEndpointProvider");
|
|
18955
|
+
attributeCache = /* @__PURE__ */ new Map();
|
|
18956
|
+
handledProperties = new Map([["AWS::RDS::DBProxyEndpoint", new Set([
|
|
18957
|
+
"DBProxyEndpointName",
|
|
18958
|
+
"DBProxyName",
|
|
18959
|
+
"VpcSubnetIds",
|
|
18960
|
+
"VpcSecurityGroupIds",
|
|
18961
|
+
"TargetRole",
|
|
18962
|
+
"Tags"
|
|
18963
|
+
])]]);
|
|
18964
|
+
getClient() {
|
|
18965
|
+
if (!this.rdsClient) this.rdsClient = new RDSClient(this.providerRegion ? { region: this.providerRegion } : {});
|
|
18966
|
+
return this.rdsClient;
|
|
18967
|
+
}
|
|
18968
|
+
async create(logicalId, resourceType, properties) {
|
|
18969
|
+
const dbProxyName = properties["DBProxyName"];
|
|
18970
|
+
if (!dbProxyName) throw new ProvisioningError(`DBProxyName is required for AWS::RDS::DBProxyEndpoint ${logicalId}`, resourceType, logicalId);
|
|
18971
|
+
const dbProxyEndpointName = properties["DBProxyEndpointName"] ?? generateResourceName(logicalId, { maxLength: 64 });
|
|
18972
|
+
const vpcSubnetIds = properties["VpcSubnetIds"];
|
|
18973
|
+
if (!vpcSubnetIds || vpcSubnetIds.length === 0) throw new ProvisioningError(`VpcSubnetIds (at least one) is required for AWS::RDS::DBProxyEndpoint ${logicalId}`, resourceType, logicalId);
|
|
18974
|
+
const client = this.getClient();
|
|
18975
|
+
this.logger.debug(`Creating DBProxyEndpoint ${dbProxyEndpointName} (proxy=${dbProxyName})`);
|
|
18976
|
+
try {
|
|
18977
|
+
await client.send(new CreateDBProxyEndpointCommand({
|
|
18978
|
+
DBProxyName: dbProxyName,
|
|
18979
|
+
DBProxyEndpointName: dbProxyEndpointName,
|
|
18980
|
+
VpcSubnetIds: vpcSubnetIds,
|
|
18981
|
+
VpcSecurityGroupIds: properties["VpcSecurityGroupIds"],
|
|
18982
|
+
TargetRole: properties["TargetRole"],
|
|
18983
|
+
Tags: this.toAwsTags(properties["Tags"])
|
|
18984
|
+
}));
|
|
18985
|
+
} catch (error) {
|
|
18986
|
+
throw this.wrapError(error, "CREATE", resourceType, logicalId, void 0);
|
|
18987
|
+
}
|
|
18988
|
+
let endpoint;
|
|
18989
|
+
let arn;
|
|
18990
|
+
let isDefault;
|
|
18991
|
+
let vpcId;
|
|
18992
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
18993
|
+
let status;
|
|
18994
|
+
while (Date.now() < deadline) {
|
|
18995
|
+
try {
|
|
18996
|
+
const ep = (await client.send(new DescribeDBProxyEndpointsCommand({
|
|
18997
|
+
DBProxyName: dbProxyName,
|
|
18998
|
+
DBProxyEndpointName: dbProxyEndpointName
|
|
18999
|
+
}))).DBProxyEndpoints?.[0];
|
|
19000
|
+
status = ep?.Status;
|
|
19001
|
+
if (status === "available") {
|
|
19002
|
+
endpoint = ep?.Endpoint;
|
|
19003
|
+
arn = ep?.DBProxyEndpointArn;
|
|
19004
|
+
isDefault = ep?.IsDefault;
|
|
19005
|
+
vpcId = ep?.VpcId;
|
|
19006
|
+
break;
|
|
19007
|
+
}
|
|
19008
|
+
if (status === "incompatible-network" || status === "insufficient-resource-limits") throw new ProvisioningError(`DBProxyEndpoint ${dbProxyEndpointName} entered terminal failure state: ${status}`, resourceType, logicalId, dbProxyEndpointName);
|
|
19009
|
+
} catch (error) {
|
|
19010
|
+
if (error instanceof DBProxyEndpointNotFoundFault || error instanceof DBProxyNotFoundFault) {} else if (error instanceof ProvisioningError) throw error;
|
|
19011
|
+
else throw this.wrapError(error, "CREATE (poll)", resourceType, logicalId, dbProxyEndpointName);
|
|
19012
|
+
}
|
|
19013
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
19014
|
+
}
|
|
19015
|
+
if (!endpoint || !arn) throw new ProvisioningError(`Timed out waiting for DBProxyEndpoint ${dbProxyEndpointName} to become available (last status: ${status ?? "unknown"})`, resourceType, logicalId, dbProxyEndpointName);
|
|
19016
|
+
return {
|
|
19017
|
+
physicalId: dbProxyEndpointName,
|
|
19018
|
+
attributes: {
|
|
19019
|
+
Endpoint: endpoint,
|
|
19020
|
+
DBProxyEndpointArn: arn,
|
|
19021
|
+
IsDefault: isDefault ?? false,
|
|
19022
|
+
VpcId: vpcId ?? ""
|
|
19023
|
+
}
|
|
19024
|
+
};
|
|
19025
|
+
}
|
|
19026
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
19027
|
+
const client = this.getClient();
|
|
19028
|
+
for (const field of [
|
|
19029
|
+
"DBProxyName",
|
|
19030
|
+
"DBProxyEndpointName",
|
|
19031
|
+
"VpcSubnetIds",
|
|
19032
|
+
"TargetRole"
|
|
19033
|
+
]) if (JSON.stringify(properties[field]) !== JSON.stringify(previousProperties[field])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `${field} is immutable on AWS::RDS::DBProxyEndpoint — destroy + redeploy to change it`);
|
|
19034
|
+
const oldSG = previousProperties["VpcSecurityGroupIds"] ?? [];
|
|
19035
|
+
const newSG = properties["VpcSecurityGroupIds"] ?? [];
|
|
19036
|
+
if (JSON.stringify(oldSG) !== JSON.stringify(newSG)) {
|
|
19037
|
+
this.logger.debug(`Updating DBProxyEndpoint ${physicalId} security groups`);
|
|
19038
|
+
try {
|
|
19039
|
+
await client.send(new ModifyDBProxyEndpointCommand({
|
|
19040
|
+
DBProxyEndpointName: physicalId,
|
|
19041
|
+
VpcSecurityGroupIds: newSG
|
|
19042
|
+
}));
|
|
19043
|
+
} catch (error) {
|
|
19044
|
+
throw this.wrapError(error, "UPDATE", resourceType, logicalId, physicalId);
|
|
19045
|
+
}
|
|
19046
|
+
}
|
|
19047
|
+
await this.applyTagDiff(physicalId, previousProperties["Tags"], properties["Tags"], resourceType, logicalId);
|
|
19048
|
+
this.invalidateAttributeCache(physicalId);
|
|
19049
|
+
return {
|
|
19050
|
+
physicalId,
|
|
19051
|
+
wasReplaced: false
|
|
19052
|
+
};
|
|
19053
|
+
}
|
|
19054
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
19055
|
+
const client = this.getClient();
|
|
19056
|
+
this.logger.debug(`Deleting DBProxyEndpoint ${physicalId}`);
|
|
19057
|
+
try {
|
|
19058
|
+
await client.send(new DeleteDBProxyEndpointCommand({ DBProxyEndpointName: physicalId }));
|
|
19059
|
+
} catch (error) {
|
|
19060
|
+
if (error instanceof DBProxyEndpointNotFoundFault || error instanceof DBProxyNotFoundFault) {
|
|
19061
|
+
assertRegionMatch(await client.config.region(), context?.expectedRegion, resourceType, logicalId, physicalId);
|
|
19062
|
+
this.logger.debug(`DBProxyEndpoint ${physicalId} or parent already gone, treating as success`);
|
|
19063
|
+
return;
|
|
19064
|
+
}
|
|
19065
|
+
throw this.wrapError(error, "DELETE", resourceType, logicalId, physicalId);
|
|
19066
|
+
}
|
|
19067
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
19068
|
+
while (Date.now() < deadline) {
|
|
19069
|
+
try {
|
|
19070
|
+
await client.send(new DescribeDBProxyEndpointsCommand({ DBProxyEndpointName: physicalId }));
|
|
19071
|
+
} catch (error) {
|
|
19072
|
+
if (error instanceof DBProxyEndpointNotFoundFault || error instanceof DBProxyNotFoundFault) {
|
|
19073
|
+
this.logger.debug(`DBProxyEndpoint ${physicalId} fully deleted`);
|
|
19074
|
+
return;
|
|
19075
|
+
}
|
|
19076
|
+
throw this.wrapError(error, "DELETE (poll)", resourceType, logicalId, physicalId);
|
|
19077
|
+
}
|
|
19078
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
19079
|
+
}
|
|
19080
|
+
throw new ProvisioningError(`Timed out waiting for DBProxyEndpoint ${physicalId} to fully delete`, resourceType, logicalId, physicalId);
|
|
19081
|
+
}
|
|
19082
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
19083
|
+
const cacheKey = `${physicalId}:${attributeName}`;
|
|
19084
|
+
const cached = this.attributeCache.get(cacheKey);
|
|
19085
|
+
if (cached !== void 0) return cached;
|
|
19086
|
+
if (attributeName !== "Endpoint" && attributeName !== "DBProxyEndpointArn" && attributeName !== "IsDefault" && attributeName !== "VpcId") {
|
|
19087
|
+
this.logger.warn(`Unknown attribute ${attributeName} for AWS::RDS::DBProxyEndpoint, returning undefined`);
|
|
19088
|
+
return;
|
|
19089
|
+
}
|
|
19090
|
+
try {
|
|
19091
|
+
const ep = (await this.getClient().send(new DescribeDBProxyEndpointsCommand({ DBProxyEndpointName: physicalId }))).DBProxyEndpoints?.[0];
|
|
19092
|
+
if (!ep) return void 0;
|
|
19093
|
+
const value = {
|
|
19094
|
+
Endpoint: ep.Endpoint,
|
|
19095
|
+
DBProxyEndpointArn: ep.DBProxyEndpointArn,
|
|
19096
|
+
IsDefault: ep.IsDefault ?? false,
|
|
19097
|
+
VpcId: ep.VpcId
|
|
19098
|
+
}[attributeName];
|
|
19099
|
+
if (value !== void 0) this.attributeCache.set(cacheKey, value);
|
|
19100
|
+
return value;
|
|
19101
|
+
} catch (error) {
|
|
19102
|
+
if (error instanceof DBProxyEndpointNotFoundFault || error instanceof DBProxyNotFoundFault) return;
|
|
19103
|
+
throw error;
|
|
19104
|
+
}
|
|
19105
|
+
}
|
|
19106
|
+
async import(input) {
|
|
19107
|
+
const explicit = resolveExplicitPhysicalId(input, "DBProxyEndpointName");
|
|
19108
|
+
if (explicit) return this.buildImportResult(explicit);
|
|
19109
|
+
const client = this.getClient();
|
|
19110
|
+
let marker;
|
|
19111
|
+
do {
|
|
19112
|
+
const describe = await client.send(new DescribeDBProxyEndpointsCommand({
|
|
19113
|
+
Marker: marker,
|
|
19114
|
+
MaxRecords: 100
|
|
19115
|
+
}));
|
|
19116
|
+
for (const ep of describe.DBProxyEndpoints ?? []) {
|
|
19117
|
+
if (!ep.DBProxyEndpointArn) continue;
|
|
19118
|
+
try {
|
|
19119
|
+
if (matchesCdkPath((await client.send(new ListTagsForResourceCommand$8({ ResourceName: ep.DBProxyEndpointArn }))).TagList ?? [], input.cdkPath)) return this.buildImportResult(ep.DBProxyEndpointName ?? "");
|
|
19120
|
+
} catch (error) {
|
|
19121
|
+
this.logger.debug(`ListTagsForResource failed for ${ep.DBProxyEndpointName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
19122
|
+
}
|
|
19123
|
+
}
|
|
19124
|
+
marker = describe.Marker;
|
|
19125
|
+
} while (marker);
|
|
19126
|
+
return null;
|
|
19127
|
+
}
|
|
19128
|
+
async readCurrentState(physicalId) {
|
|
19129
|
+
const client = this.getClient();
|
|
19130
|
+
let ep;
|
|
19131
|
+
try {
|
|
19132
|
+
ep = (await client.send(new DescribeDBProxyEndpointsCommand({ DBProxyEndpointName: physicalId }))).DBProxyEndpoints?.[0];
|
|
19133
|
+
if (!ep) return void 0;
|
|
19134
|
+
} catch (error) {
|
|
19135
|
+
if (error instanceof DBProxyEndpointNotFoundFault || error instanceof DBProxyNotFoundFault) return;
|
|
19136
|
+
throw error;
|
|
19137
|
+
}
|
|
19138
|
+
const e = ep;
|
|
19139
|
+
const result = {
|
|
19140
|
+
DBProxyEndpointName: e.DBProxyEndpointName,
|
|
19141
|
+
DBProxyName: e.DBProxyName,
|
|
19142
|
+
VpcSubnetIds: e.VpcSubnetIds ?? [],
|
|
19143
|
+
VpcSecurityGroupIds: e.VpcSecurityGroupIds ?? [],
|
|
19144
|
+
TargetRole: e.TargetRole ?? "READ_WRITE"
|
|
19145
|
+
};
|
|
19146
|
+
if (e.DBProxyEndpointArn) try {
|
|
19147
|
+
result["Tags"] = normalizeAwsTagsToCfn((await client.send(new ListTagsForResourceCommand$8({ ResourceName: e.DBProxyEndpointArn }))).TagList ?? []);
|
|
19148
|
+
} catch (error) {
|
|
19149
|
+
this.logger.debug(`ListTagsForResource failed for ${physicalId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
19150
|
+
result["Tags"] = [];
|
|
19151
|
+
}
|
|
19152
|
+
else result["Tags"] = [];
|
|
19153
|
+
return result;
|
|
19154
|
+
}
|
|
19155
|
+
async applyTagDiff(physicalId, oldTags, newTags, resourceType, logicalId) {
|
|
19156
|
+
const oldMap = this.toTagMap(oldTags);
|
|
19157
|
+
const newMap = this.toTagMap(newTags);
|
|
19158
|
+
if (oldMap.size === newMap.size && [...oldMap.keys()].every((k) => newMap.has(k)) && [...oldMap.entries()].every(([k, v]) => newMap.get(k) === v)) return;
|
|
19159
|
+
const client = this.getClient();
|
|
19160
|
+
const arnCacheKey = `${physicalId}:DBProxyEndpointArn`;
|
|
19161
|
+
let arn = this.attributeCache.get(arnCacheKey);
|
|
19162
|
+
if (!arn) try {
|
|
19163
|
+
arn = (await client.send(new DescribeDBProxyEndpointsCommand({ DBProxyEndpointName: physicalId }))).DBProxyEndpoints?.[0]?.DBProxyEndpointArn;
|
|
19164
|
+
if (arn) this.attributeCache.set(arnCacheKey, arn);
|
|
19165
|
+
} catch (error) {
|
|
19166
|
+
this.logger.debug(`Skipping tag diff for ${physicalId} (no ARN): ${error instanceof Error ? error.message : String(error)}`);
|
|
19167
|
+
return;
|
|
19168
|
+
}
|
|
19169
|
+
if (!arn) return;
|
|
19170
|
+
const toRemove = [];
|
|
19171
|
+
const toAdd = [];
|
|
19172
|
+
for (const k of oldMap.keys()) if (!newMap.has(k)) toRemove.push(k);
|
|
19173
|
+
for (const [k, v] of newMap.entries()) if (oldMap.get(k) !== v) toAdd.push({
|
|
19174
|
+
Key: k,
|
|
19175
|
+
Value: v
|
|
19176
|
+
});
|
|
19177
|
+
if (toRemove.length > 0) try {
|
|
19178
|
+
await client.send(new RemoveTagsFromResourceCommand$1({
|
|
19179
|
+
ResourceName: arn,
|
|
19180
|
+
TagKeys: toRemove
|
|
19181
|
+
}));
|
|
19182
|
+
} catch (error) {
|
|
19183
|
+
throw this.wrapError(error, "UPDATE (remove tags)", resourceType, logicalId, physicalId);
|
|
19184
|
+
}
|
|
19185
|
+
if (toAdd.length > 0) try {
|
|
19186
|
+
await client.send(new AddTagsToResourceCommand$1({
|
|
19187
|
+
ResourceName: arn,
|
|
19188
|
+
Tags: toAdd
|
|
19189
|
+
}));
|
|
19190
|
+
} catch (error) {
|
|
19191
|
+
throw this.wrapError(error, "UPDATE (add tags)", resourceType, logicalId, physicalId);
|
|
19192
|
+
}
|
|
19193
|
+
}
|
|
19194
|
+
toTagMap(tags) {
|
|
19195
|
+
const map = /* @__PURE__ */ new Map();
|
|
19196
|
+
if (Array.isArray(tags)) {
|
|
19197
|
+
for (const entry of tags) if (entry?.Key !== void 0) map.set(entry.Key, entry.Value ?? "");
|
|
19198
|
+
}
|
|
19199
|
+
return map;
|
|
19200
|
+
}
|
|
19201
|
+
toAwsTags(tags) {
|
|
19202
|
+
if (!Array.isArray(tags) || tags.length === 0) return void 0;
|
|
19203
|
+
return tags.filter((t) => t.Key !== void 0).map((t) => ({
|
|
19204
|
+
Key: t.Key,
|
|
19205
|
+
Value: t.Value ?? ""
|
|
19206
|
+
}));
|
|
19207
|
+
}
|
|
19208
|
+
async buildImportResult(physicalId) {
|
|
19209
|
+
try {
|
|
19210
|
+
const ep = (await this.getClient().send(new DescribeDBProxyEndpointsCommand({ DBProxyEndpointName: physicalId }))).DBProxyEndpoints?.[0];
|
|
19211
|
+
return {
|
|
19212
|
+
physicalId,
|
|
19213
|
+
attributes: {
|
|
19214
|
+
Endpoint: ep?.Endpoint ?? "",
|
|
19215
|
+
DBProxyEndpointArn: ep?.DBProxyEndpointArn ?? "",
|
|
19216
|
+
IsDefault: ep?.IsDefault ?? false,
|
|
19217
|
+
VpcId: ep?.VpcId ?? ""
|
|
19218
|
+
}
|
|
19219
|
+
};
|
|
19220
|
+
} catch {
|
|
19221
|
+
return {
|
|
19222
|
+
physicalId,
|
|
19223
|
+
attributes: {
|
|
19224
|
+
Endpoint: "",
|
|
19225
|
+
DBProxyEndpointArn: "",
|
|
19226
|
+
IsDefault: false,
|
|
19227
|
+
VpcId: ""
|
|
19228
|
+
}
|
|
19229
|
+
};
|
|
19230
|
+
}
|
|
19231
|
+
}
|
|
19232
|
+
invalidateAttributeCache(physicalId) {
|
|
19233
|
+
for (const key of this.attributeCache.keys()) if (key.startsWith(`${physicalId}:`)) this.attributeCache.delete(key);
|
|
19234
|
+
}
|
|
19235
|
+
wrapError(error, op, resourceType, logicalId, physicalId) {
|
|
19236
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
19237
|
+
const cause = error instanceof Error ? error : void 0;
|
|
19238
|
+
return new ProvisioningError(`${op} failed for ${logicalId}: ${message}`, resourceType, logicalId, physicalId, cause);
|
|
19239
|
+
}
|
|
19240
|
+
};
|
|
19241
|
+
|
|
18745
19242
|
//#endregion
|
|
18746
19243
|
//#region src/provisioning/providers/rds-dbproxy-targetgroup-provider.ts
|
|
18747
19244
|
/**
|
|
@@ -18861,6 +19358,12 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
18861
19358
|
const dbProxyName = properties["DBProxyName"];
|
|
18862
19359
|
if (!dbProxyName) throw new ProvisioningError(`DBProxyName is required for AWS::RDS::DBProxyTargetGroup ${logicalId} update`, resourceType, logicalId, physicalId);
|
|
18863
19360
|
const targetGroupName = properties["TargetGroupName"] ?? "default";
|
|
19361
|
+
for (const field of ["DBProxyName", "TargetGroupName"]) {
|
|
19362
|
+
const oldVal = previousProperties[field];
|
|
19363
|
+
const newVal = properties[field];
|
|
19364
|
+
const normalize = (v) => field === "TargetGroupName" && (v === void 0 || v === "default") ? "default" : v;
|
|
19365
|
+
if (JSON.stringify(normalize(oldVal)) !== JSON.stringify(normalize(newVal))) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `${field} is immutable on AWS::RDS::DBProxyTargetGroup — destroy + redeploy to change it`);
|
|
19366
|
+
}
|
|
18864
19367
|
const client = this.getClient();
|
|
18865
19368
|
const oldPool = previousProperties["ConnectionPoolConfigurationInfo"];
|
|
18866
19369
|
const newPool = properties["ConnectionPoolConfigurationInfo"];
|
|
@@ -29703,6 +30206,7 @@ function registerAllProviders(registry) {
|
|
|
29703
30206
|
registry.register("AWS::RDS::DBCluster", rdsProvider);
|
|
29704
30207
|
registry.register("AWS::RDS::DBInstance", rdsProvider);
|
|
29705
30208
|
registry.register("AWS::RDS::DBProxy", new RDSDBProxyProvider());
|
|
30209
|
+
registry.register("AWS::RDS::DBProxyEndpoint", new RDSDBProxyEndpointProvider());
|
|
29706
30210
|
registry.register("AWS::RDS::DBProxyTargetGroup", new RDSDBProxyTargetGroupProvider());
|
|
29707
30211
|
const docdbProvider = new DocDBProvider();
|
|
29708
30212
|
registry.register("AWS::DocDB::DBSubnetGroup", docdbProvider);
|
|
@@ -44683,7 +45187,7 @@ function reorderArgs(argv) {
|
|
|
44683
45187
|
*/
|
|
44684
45188
|
async function main() {
|
|
44685
45189
|
const program = new Command();
|
|
44686
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
45190
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.109.0");
|
|
44687
45191
|
program.addCommand(createBootstrapCommand());
|
|
44688
45192
|
program.addCommand(createSynthCommand());
|
|
44689
45193
|
program.addCommand(createListCommand());
|