@go-to-k/cdkd 0.58.0 → 0.59.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -2
- package/dist/cli.js +929 -75
- package/dist/cli.js.map +4 -4
- package/dist/go-to-k-cdkd-0.59.1.tgz +0 -0
- package/dist/index.js +25 -1
- package/dist/index.js.map +2 -2
- package/package.json +3 -2
- package/dist/go-to-k-cdkd-0.58.0.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -650,7 +650,11 @@ var contextOptions = [
|
|
|
650
650
|
var destroyOptions = [
|
|
651
651
|
new Option("-f, --force", "Do not ask for confirmation before destroying the stacks").default(
|
|
652
652
|
false
|
|
653
|
-
)
|
|
653
|
+
),
|
|
654
|
+
new Option(
|
|
655
|
+
"--remove-protection",
|
|
656
|
+
"Bypass deletion protection on protected resources by flipping the per-resource protection flag off in-place before delete. Covers stack-level terminationProtection (CDK property) and resource-level protection on AWS::Logs::LogGroup, AWS::RDS::DBInstance, AWS::RDS::DBCluster, AWS::DynamoDB::Table, AWS::EC2::Instance, and AWS::ElasticLoadBalancingV2::LoadBalancer."
|
|
657
|
+
).default(false)
|
|
654
658
|
];
|
|
655
659
|
|
|
656
660
|
// src/provisioning/resource-name.ts
|
|
@@ -5709,7 +5713,10 @@ import { GetFunctionUrlConfigCommand } from "@aws-sdk/client-lambda";
|
|
|
5709
5713
|
|
|
5710
5714
|
// src/deployment/intrinsic-function-resolver.ts
|
|
5711
5715
|
import { GetCallerIdentityCommand as GetCallerIdentityCommand3 } from "@aws-sdk/client-sts";
|
|
5712
|
-
import {
|
|
5716
|
+
import {
|
|
5717
|
+
DescribeAvailabilityZonesCommand as DescribeAvailabilityZonesCommand2,
|
|
5718
|
+
DescribeLaunchTemplatesCommand
|
|
5719
|
+
} from "@aws-sdk/client-ec2";
|
|
5713
5720
|
import { GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
|
|
5714
5721
|
import { GetParameterCommand as GetParameterCommand2 } from "@aws-sdk/client-ssm";
|
|
5715
5722
|
init_aws_clients();
|
|
@@ -6185,6 +6192,27 @@ var IntrinsicFunctionResolver = class {
|
|
|
6185
6192
|
return physicalId;
|
|
6186
6193
|
}
|
|
6187
6194
|
}
|
|
6195
|
+
if (resourceType === "AWS::EC2::LaunchTemplate") {
|
|
6196
|
+
if (attributeName === "LatestVersionNumber" || attributeName === "DefaultVersionNumber") {
|
|
6197
|
+
try {
|
|
6198
|
+
const clients = getAwsClients();
|
|
6199
|
+
const response = await clients.ec2.send(
|
|
6200
|
+
new DescribeLaunchTemplatesCommand({ LaunchTemplateIds: [physicalId] })
|
|
6201
|
+
);
|
|
6202
|
+
const lt = response.LaunchTemplates?.[0];
|
|
6203
|
+
const value = attributeName === "LatestVersionNumber" ? lt?.LatestVersionNumber : lt?.DefaultVersionNumber;
|
|
6204
|
+
if (value !== void 0 && value !== null) {
|
|
6205
|
+
return String(value);
|
|
6206
|
+
}
|
|
6207
|
+
} catch (err) {
|
|
6208
|
+
this.logger.warn(
|
|
6209
|
+
`DescribeLaunchTemplates(${physicalId}) failed for ${attributeName}: ${err instanceof Error ? err.message : String(err)}`
|
|
6210
|
+
);
|
|
6211
|
+
}
|
|
6212
|
+
return attributeName === "LatestVersionNumber" ? "$Latest" : "$Default";
|
|
6213
|
+
}
|
|
6214
|
+
return physicalId;
|
|
6215
|
+
}
|
|
6188
6216
|
this.logger.warn(
|
|
6189
6217
|
`Unknown attribute ${attributeName} for resource type ${resourceType}, returning physical ID`
|
|
6190
6218
|
);
|
|
@@ -16684,6 +16712,7 @@ import {
|
|
|
16684
16712
|
ListTagsOfResourceCommand,
|
|
16685
16713
|
TagResourceCommand as TagResourceCommand4,
|
|
16686
16714
|
UntagResourceCommand as UntagResourceCommand4,
|
|
16715
|
+
UpdateTableCommand,
|
|
16687
16716
|
ResourceNotFoundException as ResourceNotFoundException6
|
|
16688
16717
|
} from "@aws-sdk/client-dynamodb";
|
|
16689
16718
|
init_aws_clients();
|
|
@@ -16849,6 +16878,32 @@ var DynamoDBTableProvider = class {
|
|
|
16849
16878
|
*/
|
|
16850
16879
|
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
16851
16880
|
this.logger.debug(`Deleting DynamoDB table ${logicalId}: ${physicalId}`);
|
|
16881
|
+
if (context?.removeProtection === true) {
|
|
16882
|
+
try {
|
|
16883
|
+
await this.dynamoDBClient.send(
|
|
16884
|
+
new UpdateTableCommand({
|
|
16885
|
+
TableName: physicalId,
|
|
16886
|
+
DeletionProtectionEnabled: false
|
|
16887
|
+
})
|
|
16888
|
+
);
|
|
16889
|
+
this.logger.debug(
|
|
16890
|
+
`Disabled DeletionProtectionEnabled on DynamoDB table ${logicalId}, waiting for ACTIVE`
|
|
16891
|
+
);
|
|
16892
|
+
try {
|
|
16893
|
+
await this.waitForTableActiveAfterUpdate(physicalId);
|
|
16894
|
+
} catch (waitErr) {
|
|
16895
|
+
this.logger.debug(
|
|
16896
|
+
`Could not wait for table ${physicalId} ACTIVE after disabling protection: ${waitErr instanceof Error ? waitErr.message : String(waitErr)}`
|
|
16897
|
+
);
|
|
16898
|
+
}
|
|
16899
|
+
} catch (flipError) {
|
|
16900
|
+
if (!(flipError instanceof ResourceNotFoundException6)) {
|
|
16901
|
+
this.logger.debug(
|
|
16902
|
+
`Could not disable DeletionProtectionEnabled on ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`
|
|
16903
|
+
);
|
|
16904
|
+
}
|
|
16905
|
+
}
|
|
16906
|
+
}
|
|
16852
16907
|
try {
|
|
16853
16908
|
await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: physicalId }));
|
|
16854
16909
|
this.logger.debug(`Successfully deleted DynamoDB table ${logicalId}`);
|
|
@@ -16941,6 +16996,28 @@ var DynamoDBTableProvider = class {
|
|
|
16941
16996
|
}
|
|
16942
16997
|
throw new Error(`Table ${tableName} did not reach ACTIVE status within ${maxAttempts} seconds`);
|
|
16943
16998
|
}
|
|
16999
|
+
/**
|
|
17000
|
+
* Poll DescribeTable until the table reaches ACTIVE after an UpdateTable
|
|
17001
|
+
* call. Distinct from `waitForTableActive` because `UpdateTable`
|
|
17002
|
+
* transitions the table to `UPDATING` (not `CREATING`); a status
|
|
17003
|
+
* mismatch should not throw — just keep polling — and the call may
|
|
17004
|
+
* also return immediately ACTIVE on the no-op path (already disabled).
|
|
17005
|
+
*/
|
|
17006
|
+
async waitForTableActiveAfterUpdate(tableName, maxAttempts = 60) {
|
|
17007
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
17008
|
+
const response = await this.dynamoDBClient.send(
|
|
17009
|
+
new DescribeTableCommand2({ TableName: tableName })
|
|
17010
|
+
);
|
|
17011
|
+
const status = response.Table?.TableStatus;
|
|
17012
|
+
if (status === "ACTIVE") {
|
|
17013
|
+
return;
|
|
17014
|
+
}
|
|
17015
|
+
await new Promise((resolve4) => setTimeout(resolve4, 1e3));
|
|
17016
|
+
}
|
|
17017
|
+
throw new Error(
|
|
17018
|
+
`Table ${tableName} did not reach ACTIVE status within ${maxAttempts} seconds after UpdateTable`
|
|
17019
|
+
);
|
|
17020
|
+
}
|
|
16944
17021
|
/**
|
|
16945
17022
|
* Resolve a single `Fn::GetAtt` attribute for an existing DynamoDB table.
|
|
16946
17023
|
*
|
|
@@ -17420,6 +17497,23 @@ var LogsLogGroupProvider = class {
|
|
|
17420
17497
|
*/
|
|
17421
17498
|
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
17422
17499
|
this.logger.debug(`Deleting log group ${logicalId}: ${physicalId}`);
|
|
17500
|
+
if (context?.removeProtection === true) {
|
|
17501
|
+
try {
|
|
17502
|
+
await this.logsClient.send(
|
|
17503
|
+
new PutLogGroupDeletionProtectionCommand({
|
|
17504
|
+
logGroupIdentifier: physicalId,
|
|
17505
|
+
deletionProtectionEnabled: false
|
|
17506
|
+
})
|
|
17507
|
+
);
|
|
17508
|
+
this.logger.debug(
|
|
17509
|
+
`Disabled DeletionProtectionEnabled on log group ${logicalId} before delete`
|
|
17510
|
+
);
|
|
17511
|
+
} catch (flipError) {
|
|
17512
|
+
this.logger.debug(
|
|
17513
|
+
`Could not disable DeletionProtectionEnabled on ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`
|
|
17514
|
+
);
|
|
17515
|
+
}
|
|
17516
|
+
}
|
|
17423
17517
|
try {
|
|
17424
17518
|
await this.logsClient.send(new DeleteLogGroupCommand({ logGroupName: physicalId }));
|
|
17425
17519
|
this.logger.debug(`Successfully deleted log group ${logicalId}`);
|
|
@@ -19675,7 +19769,8 @@ import {
|
|
|
19675
19769
|
DescribeNetworkInterfacesCommand as DescribeNetworkInterfacesCommand2,
|
|
19676
19770
|
DeleteNetworkInterfaceCommand as DeleteNetworkInterfaceCommand2,
|
|
19677
19771
|
DescribeVolumesCommand,
|
|
19678
|
-
DescribeInstanceAttributeCommand
|
|
19772
|
+
DescribeInstanceAttributeCommand,
|
|
19773
|
+
ModifyInstanceAttributeCommand
|
|
19679
19774
|
} from "@aws-sdk/client-ec2";
|
|
19680
19775
|
init_aws_clients();
|
|
19681
19776
|
var EC2Provider = class {
|
|
@@ -21323,6 +21418,25 @@ var EC2Provider = class {
|
|
|
21323
21418
|
}
|
|
21324
21419
|
async deleteInstance(logicalId, physicalId, resourceType, context) {
|
|
21325
21420
|
this.logger.debug(`Terminating EC2 Instance ${logicalId}: ${physicalId}`);
|
|
21421
|
+
if (context?.removeProtection === true) {
|
|
21422
|
+
try {
|
|
21423
|
+
await this.ec2Client.send(
|
|
21424
|
+
new ModifyInstanceAttributeCommand({
|
|
21425
|
+
InstanceId: physicalId,
|
|
21426
|
+
DisableApiTermination: { Value: false }
|
|
21427
|
+
})
|
|
21428
|
+
);
|
|
21429
|
+
this.logger.debug(
|
|
21430
|
+
`Disabled DisableApiTermination on EC2 Instance ${logicalId} before termination`
|
|
21431
|
+
);
|
|
21432
|
+
} catch (flipError) {
|
|
21433
|
+
if (!this.isNotFoundError(flipError)) {
|
|
21434
|
+
this.logger.debug(
|
|
21435
|
+
`Could not disable DisableApiTermination on ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`
|
|
21436
|
+
);
|
|
21437
|
+
}
|
|
21438
|
+
}
|
|
21439
|
+
}
|
|
21326
21440
|
try {
|
|
21327
21441
|
await this.ec2Client.send(new TerminateInstancesCommand({ InstanceIds: [physicalId] }));
|
|
21328
21442
|
this.logger.debug(`Terminate requested for EC2 Instance ${logicalId}, waiting...`);
|
|
@@ -28246,6 +28360,25 @@ var ELBv2Provider = class {
|
|
|
28246
28360
|
}
|
|
28247
28361
|
async deleteLoadBalancer(logicalId, physicalId, resourceType, context) {
|
|
28248
28362
|
this.logger.debug(`Deleting LoadBalancer ${logicalId}: ${physicalId}`);
|
|
28363
|
+
if (context?.removeProtection === true) {
|
|
28364
|
+
try {
|
|
28365
|
+
await this.getClient().send(
|
|
28366
|
+
new ModifyLoadBalancerAttributesCommand({
|
|
28367
|
+
LoadBalancerArn: physicalId,
|
|
28368
|
+
Attributes: [{ Key: "deletion_protection.enabled", Value: "false" }]
|
|
28369
|
+
})
|
|
28370
|
+
);
|
|
28371
|
+
this.logger.debug(
|
|
28372
|
+
`Disabled deletion_protection.enabled on LoadBalancer ${logicalId} before delete`
|
|
28373
|
+
);
|
|
28374
|
+
} catch (flipError) {
|
|
28375
|
+
if (!this.isNotFoundError(flipError)) {
|
|
28376
|
+
this.logger.debug(
|
|
28377
|
+
`Could not disable deletion_protection.enabled on ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`
|
|
28378
|
+
);
|
|
28379
|
+
}
|
|
28380
|
+
}
|
|
28381
|
+
}
|
|
28249
28382
|
try {
|
|
28250
28383
|
await this.getClient().send(new DeleteLoadBalancerCommand({ LoadBalancerArn: physicalId }));
|
|
28251
28384
|
this.logger.debug(`Successfully deleted LoadBalancer ${logicalId}`);
|
|
@@ -29257,18 +29390,22 @@ var RDSProvider = class {
|
|
|
29257
29390
|
async deleteDBCluster(logicalId, physicalId, resourceType, context) {
|
|
29258
29391
|
this.logger.debug(`Deleting DBCluster ${logicalId}: ${physicalId}`);
|
|
29259
29392
|
try {
|
|
29260
|
-
|
|
29261
|
-
|
|
29262
|
-
|
|
29263
|
-
|
|
29264
|
-
|
|
29265
|
-
|
|
29266
|
-
|
|
29267
|
-
|
|
29268
|
-
if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) {
|
|
29269
|
-
this.logger.debug(
|
|
29270
|
-
`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`
|
|
29393
|
+
if (context?.removeProtection === true) {
|
|
29394
|
+
try {
|
|
29395
|
+
await this.getClient().send(
|
|
29396
|
+
new ModifyDBClusterCommand({
|
|
29397
|
+
DBClusterIdentifier: physicalId,
|
|
29398
|
+
DeletionProtection: false,
|
|
29399
|
+
ApplyImmediately: true
|
|
29400
|
+
})
|
|
29271
29401
|
);
|
|
29402
|
+
this.logger.debug(`Disabled DeletionProtection on DBCluster ${logicalId} before delete`);
|
|
29403
|
+
} catch (disableError) {
|
|
29404
|
+
if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) {
|
|
29405
|
+
this.logger.debug(
|
|
29406
|
+
`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`
|
|
29407
|
+
);
|
|
29408
|
+
}
|
|
29272
29409
|
}
|
|
29273
29410
|
}
|
|
29274
29411
|
await this.getClient().send(
|
|
@@ -29392,19 +29529,22 @@ var RDSProvider = class {
|
|
|
29392
29529
|
async deleteDBInstance(logicalId, physicalId, resourceType, context) {
|
|
29393
29530
|
this.logger.debug(`Deleting DBInstance ${logicalId}: ${physicalId}`);
|
|
29394
29531
|
try {
|
|
29395
|
-
|
|
29396
|
-
|
|
29397
|
-
|
|
29398
|
-
|
|
29399
|
-
|
|
29400
|
-
|
|
29401
|
-
|
|
29402
|
-
|
|
29403
|
-
} catch (disableError) {
|
|
29404
|
-
if (!this.isNotFoundError(disableError, "DBInstanceNotFoundFault")) {
|
|
29405
|
-
this.logger.debug(
|
|
29406
|
-
`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`
|
|
29532
|
+
if (context?.removeProtection === true) {
|
|
29533
|
+
try {
|
|
29534
|
+
await this.getClient().send(
|
|
29535
|
+
new ModifyDBInstanceCommand({
|
|
29536
|
+
DBInstanceIdentifier: physicalId,
|
|
29537
|
+
DeletionProtection: false,
|
|
29538
|
+
ApplyImmediately: true
|
|
29539
|
+
})
|
|
29407
29540
|
);
|
|
29541
|
+
this.logger.debug(`Disabled DeletionProtection on DBInstance ${logicalId} before delete`);
|
|
29542
|
+
} catch (disableError) {
|
|
29543
|
+
if (!this.isNotFoundError(disableError, "DBInstanceNotFoundFault")) {
|
|
29544
|
+
this.logger.debug(
|
|
29545
|
+
`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`
|
|
29546
|
+
);
|
|
29547
|
+
}
|
|
29408
29548
|
}
|
|
29409
29549
|
}
|
|
29410
29550
|
await this.getClient().send(
|
|
@@ -31447,56 +31587,69 @@ var CognitoUserPoolProvider = class {
|
|
|
31447
31587
|
}
|
|
31448
31588
|
}
|
|
31449
31589
|
/**
|
|
31450
|
-
* Delete a Cognito User Pool
|
|
31590
|
+
* Delete a Cognito User Pool.
|
|
31591
|
+
*
|
|
31592
|
+
* When `context.removeProtection === true`, `DeletionProtection` is flipped
|
|
31593
|
+
* from `ACTIVE` to `INACTIVE` via `UpdateUserPool` before deletion. The
|
|
31594
|
+
* call is idempotent — AWS accepts the no-op already-disabled case
|
|
31595
|
+
* without error. Without `removeProtection`, AWS rejects the delete on a
|
|
31596
|
+
* protected pool with `InvalidParameterException` and the destroy fails;
|
|
31597
|
+
* the user is expected to set `--remove-protection` explicitly.
|
|
31451
31598
|
*
|
|
31452
|
-
*
|
|
31599
|
+
* Pre-PR behavior was an unconditional flip-off; that silent bypass has
|
|
31600
|
+
* been gated on `--remove-protection` to match the rest of the
|
|
31601
|
+
* deletion-protection-bearing types and CDK CLI's refuse-on-protected
|
|
31602
|
+
* semantics. See PR body for migration notes.
|
|
31453
31603
|
*/
|
|
31454
31604
|
async delete(logicalId, physicalId, resourceType, properties, context) {
|
|
31455
31605
|
this.logger.debug(`Deleting Cognito User Pool ${logicalId}: ${physicalId}`);
|
|
31456
31606
|
try {
|
|
31457
|
-
|
|
31458
|
-
|
|
31459
|
-
|
|
31460
|
-
|
|
31461
|
-
|
|
31462
|
-
|
|
31463
|
-
|
|
31464
|
-
|
|
31465
|
-
DeletionProtection
|
|
31466
|
-
})
|
|
31467
|
-
|
|
31468
|
-
|
|
31469
|
-
|
|
31470
|
-
|
|
31471
|
-
|
|
31472
|
-
|
|
31473
|
-
|
|
31607
|
+
if (context?.removeProtection === true) {
|
|
31608
|
+
const templatedActive = properties?.["DeletionProtection"] === "ACTIVE";
|
|
31609
|
+
let needsFlip = templatedActive;
|
|
31610
|
+
if (!templatedActive) {
|
|
31611
|
+
try {
|
|
31612
|
+
const describeResponse = await this.getClient().send(
|
|
31613
|
+
new DescribeUserPoolCommand({ UserPoolId: physicalId })
|
|
31614
|
+
);
|
|
31615
|
+
needsFlip = describeResponse.UserPool?.DeletionProtection === "ACTIVE";
|
|
31616
|
+
} catch (descError) {
|
|
31617
|
+
if (descError instanceof ResourceNotFoundException12) {
|
|
31618
|
+
const clientRegion = await this.getClient().config.region();
|
|
31619
|
+
assertRegionMatch(
|
|
31620
|
+
clientRegion,
|
|
31621
|
+
context?.expectedRegion,
|
|
31622
|
+
resourceType,
|
|
31623
|
+
logicalId,
|
|
31624
|
+
physicalId
|
|
31625
|
+
);
|
|
31626
|
+
this.logger.debug(
|
|
31627
|
+
`Cognito User Pool ${physicalId} does not exist, skipping deletion`
|
|
31628
|
+
);
|
|
31629
|
+
return;
|
|
31630
|
+
}
|
|
31474
31631
|
this.logger.debug(
|
|
31475
|
-
`
|
|
31632
|
+
`Failed to describe Cognito User Pool ${physicalId}, attempting flip-off anyway`
|
|
31476
31633
|
);
|
|
31634
|
+
needsFlip = true;
|
|
31635
|
+
}
|
|
31636
|
+
}
|
|
31637
|
+
if (needsFlip) {
|
|
31638
|
+
this.logger.debug(
|
|
31639
|
+
`Disabling DeletionProtection on Cognito User Pool ${physicalId} before deletion (--remove-protection)`
|
|
31640
|
+
);
|
|
31641
|
+
try {
|
|
31477
31642
|
await this.getClient().send(
|
|
31478
31643
|
new UpdateUserPoolCommand({
|
|
31479
31644
|
UserPoolId: physicalId,
|
|
31480
31645
|
DeletionProtection: "INACTIVE"
|
|
31481
31646
|
})
|
|
31482
31647
|
);
|
|
31483
|
-
}
|
|
31484
|
-
|
|
31485
|
-
|
|
31486
|
-
const clientRegion = await this.getClient().config.region();
|
|
31487
|
-
assertRegionMatch(
|
|
31488
|
-
clientRegion,
|
|
31489
|
-
context?.expectedRegion,
|
|
31490
|
-
resourceType,
|
|
31491
|
-
logicalId,
|
|
31492
|
-
physicalId
|
|
31648
|
+
} catch (flipError) {
|
|
31649
|
+
this.logger.debug(
|
|
31650
|
+
`Could not disable DeletionProtection for ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`
|
|
31493
31651
|
);
|
|
31494
|
-
this.logger.debug(`Cognito User Pool ${physicalId} does not exist, skipping deletion`);
|
|
31495
|
-
return;
|
|
31496
31652
|
}
|
|
31497
|
-
this.logger.debug(
|
|
31498
|
-
`Failed to describe Cognito User Pool ${physicalId}, proceeding with delete`
|
|
31499
|
-
);
|
|
31500
31653
|
}
|
|
31501
31654
|
}
|
|
31502
31655
|
await this.getClient().send(new DeleteUserPoolCommand({ UserPoolId: physicalId }));
|
|
@@ -33885,7 +34038,7 @@ import {
|
|
|
33885
34038
|
UpdateDatabaseCommand,
|
|
33886
34039
|
DeleteDatabaseCommand,
|
|
33887
34040
|
CreateTableCommand as CreateTableCommand2,
|
|
33888
|
-
UpdateTableCommand,
|
|
34041
|
+
UpdateTableCommand as UpdateTableCommand2,
|
|
33889
34042
|
DeleteTableCommand as DeleteTableCommand2,
|
|
33890
34043
|
GetDatabaseCommand,
|
|
33891
34044
|
GetDatabasesCommand,
|
|
@@ -34145,7 +34298,7 @@ var GlueProvider = class {
|
|
|
34145
34298
|
const catalogId = properties["CatalogId"];
|
|
34146
34299
|
try {
|
|
34147
34300
|
await this.getClient().send(
|
|
34148
|
-
new
|
|
34301
|
+
new UpdateTableCommand2({
|
|
34149
34302
|
CatalogId: catalogId,
|
|
34150
34303
|
DatabaseName: databaseName,
|
|
34151
34304
|
TableInput: this.buildTableInput(tableInput)
|
|
@@ -39884,6 +40037,646 @@ var ECRProvider = class {
|
|
|
39884
40037
|
}
|
|
39885
40038
|
};
|
|
39886
40039
|
|
|
40040
|
+
// src/provisioning/providers/asg-provider.ts
|
|
40041
|
+
import {
|
|
40042
|
+
AutoScalingClient,
|
|
40043
|
+
CreateAutoScalingGroupCommand,
|
|
40044
|
+
UpdateAutoScalingGroupCommand,
|
|
40045
|
+
DeleteAutoScalingGroupCommand,
|
|
40046
|
+
DescribeAutoScalingGroupsCommand
|
|
40047
|
+
} from "@aws-sdk/client-auto-scaling";
|
|
40048
|
+
var ASGProvider = class {
|
|
40049
|
+
asgClient;
|
|
40050
|
+
providerRegion = process.env["AWS_REGION"];
|
|
40051
|
+
logger = getLogger().child("ASGProvider");
|
|
40052
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
40053
|
+
[
|
|
40054
|
+
"AWS::AutoScaling::AutoScalingGroup",
|
|
40055
|
+
/* @__PURE__ */ new Set([
|
|
40056
|
+
"AutoScalingGroupName",
|
|
40057
|
+
"LaunchTemplate",
|
|
40058
|
+
"MinSize",
|
|
40059
|
+
"MaxSize",
|
|
40060
|
+
"DesiredCapacity",
|
|
40061
|
+
"VPCZoneIdentifier",
|
|
40062
|
+
"AvailabilityZones",
|
|
40063
|
+
"HealthCheckType",
|
|
40064
|
+
"HealthCheckGracePeriod",
|
|
40065
|
+
"Cooldown",
|
|
40066
|
+
"DefaultCooldown",
|
|
40067
|
+
"Tags",
|
|
40068
|
+
"TerminationPolicies",
|
|
40069
|
+
"NewInstancesProtectedFromScaleIn",
|
|
40070
|
+
"CapacityRebalance",
|
|
40071
|
+
"ServiceLinkedRoleARN",
|
|
40072
|
+
"MaxInstanceLifetime",
|
|
40073
|
+
"LoadBalancerNames",
|
|
40074
|
+
"TargetGroupARNs",
|
|
40075
|
+
"MetricsCollection",
|
|
40076
|
+
"LifecycleHookSpecificationList",
|
|
40077
|
+
"MixedInstancesPolicy",
|
|
40078
|
+
"Context",
|
|
40079
|
+
"DesiredCapacityType",
|
|
40080
|
+
"DefaultInstanceWarmup",
|
|
40081
|
+
"TrafficSources",
|
|
40082
|
+
"AvailabilityZoneDistribution",
|
|
40083
|
+
"AvailabilityZoneImpairmentPolicy",
|
|
40084
|
+
"SkipZonalShiftValidation",
|
|
40085
|
+
"CapacityReservationSpecification",
|
|
40086
|
+
"InstanceMaintenancePolicy",
|
|
40087
|
+
"DeletionProtection"
|
|
40088
|
+
])
|
|
40089
|
+
]
|
|
40090
|
+
]);
|
|
40091
|
+
getClient() {
|
|
40092
|
+
if (!this.asgClient) {
|
|
40093
|
+
this.asgClient = new AutoScalingClient(
|
|
40094
|
+
this.providerRegion ? { region: this.providerRegion } : {}
|
|
40095
|
+
);
|
|
40096
|
+
}
|
|
40097
|
+
return this.asgClient;
|
|
40098
|
+
}
|
|
40099
|
+
// ─── Dispatch ─────────────────────────────────────────────────────
|
|
40100
|
+
async create(logicalId, resourceType, properties) {
|
|
40101
|
+
if (resourceType !== "AWS::AutoScaling::AutoScalingGroup") {
|
|
40102
|
+
throw new ProvisioningError(
|
|
40103
|
+
`Unsupported resource type: ${resourceType}`,
|
|
40104
|
+
resourceType,
|
|
40105
|
+
logicalId
|
|
40106
|
+
);
|
|
40107
|
+
}
|
|
40108
|
+
const groupName = properties["AutoScalingGroupName"] || generateResourceName(logicalId, { maxLength: 255 });
|
|
40109
|
+
this.logger.debug(`Creating AutoScalingGroup ${logicalId}: ${groupName}`);
|
|
40110
|
+
try {
|
|
40111
|
+
const launchTemplate = this.buildLaunchTemplate(properties);
|
|
40112
|
+
const tags = this.buildTags(groupName, properties);
|
|
40113
|
+
const vpcZoneIdentifier = this.joinVpcZoneIdentifier(properties["VPCZoneIdentifier"]);
|
|
40114
|
+
const minSize = properties["MinSize"] != null ? Number(properties["MinSize"]) : 0;
|
|
40115
|
+
const maxSize = properties["MaxSize"] != null ? Number(properties["MaxSize"]) : minSize;
|
|
40116
|
+
await this.getClient().send(
|
|
40117
|
+
new CreateAutoScalingGroupCommand({
|
|
40118
|
+
AutoScalingGroupName: groupName,
|
|
40119
|
+
MinSize: minSize,
|
|
40120
|
+
MaxSize: maxSize,
|
|
40121
|
+
...properties["DesiredCapacity"] != null && {
|
|
40122
|
+
DesiredCapacity: Number(properties["DesiredCapacity"])
|
|
40123
|
+
},
|
|
40124
|
+
...launchTemplate && { LaunchTemplate: launchTemplate },
|
|
40125
|
+
...properties["MixedInstancesPolicy"] !== void 0 && {
|
|
40126
|
+
MixedInstancesPolicy: properties["MixedInstancesPolicy"]
|
|
40127
|
+
},
|
|
40128
|
+
...vpcZoneIdentifier !== void 0 && { VPCZoneIdentifier: vpcZoneIdentifier },
|
|
40129
|
+
...properties["AvailabilityZones"] !== void 0 && {
|
|
40130
|
+
AvailabilityZones: properties["AvailabilityZones"]
|
|
40131
|
+
},
|
|
40132
|
+
...properties["HealthCheckType"] !== void 0 && {
|
|
40133
|
+
HealthCheckType: properties["HealthCheckType"]
|
|
40134
|
+
},
|
|
40135
|
+
...properties["HealthCheckGracePeriod"] != null && {
|
|
40136
|
+
HealthCheckGracePeriod: Number(properties["HealthCheckGracePeriod"])
|
|
40137
|
+
},
|
|
40138
|
+
...properties["Cooldown"] != null && {
|
|
40139
|
+
DefaultCooldown: Number(properties["Cooldown"])
|
|
40140
|
+
},
|
|
40141
|
+
...properties["DefaultCooldown"] != null && {
|
|
40142
|
+
DefaultCooldown: Number(properties["DefaultCooldown"])
|
|
40143
|
+
},
|
|
40144
|
+
...properties["TerminationPolicies"] !== void 0 && {
|
|
40145
|
+
TerminationPolicies: properties["TerminationPolicies"]
|
|
40146
|
+
},
|
|
40147
|
+
...properties["NewInstancesProtectedFromScaleIn"] !== void 0 && {
|
|
40148
|
+
NewInstancesProtectedFromScaleIn: properties["NewInstancesProtectedFromScaleIn"]
|
|
40149
|
+
},
|
|
40150
|
+
...properties["CapacityRebalance"] !== void 0 && {
|
|
40151
|
+
CapacityRebalance: properties["CapacityRebalance"]
|
|
40152
|
+
},
|
|
40153
|
+
...properties["ServiceLinkedRoleARN"] !== void 0 && {
|
|
40154
|
+
ServiceLinkedRoleARN: properties["ServiceLinkedRoleARN"]
|
|
40155
|
+
},
|
|
40156
|
+
...properties["MaxInstanceLifetime"] != null && {
|
|
40157
|
+
MaxInstanceLifetime: Number(properties["MaxInstanceLifetime"])
|
|
40158
|
+
},
|
|
40159
|
+
...properties["LoadBalancerNames"] !== void 0 && {
|
|
40160
|
+
LoadBalancerNames: properties["LoadBalancerNames"]
|
|
40161
|
+
},
|
|
40162
|
+
...properties["TargetGroupARNs"] !== void 0 && {
|
|
40163
|
+
TargetGroupARNs: properties["TargetGroupARNs"]
|
|
40164
|
+
},
|
|
40165
|
+
...properties["Context"] !== void 0 && {
|
|
40166
|
+
Context: properties["Context"]
|
|
40167
|
+
},
|
|
40168
|
+
...properties["DesiredCapacityType"] !== void 0 && {
|
|
40169
|
+
DesiredCapacityType: properties["DesiredCapacityType"]
|
|
40170
|
+
},
|
|
40171
|
+
...properties["DefaultInstanceWarmup"] != null && {
|
|
40172
|
+
DefaultInstanceWarmup: Number(properties["DefaultInstanceWarmup"])
|
|
40173
|
+
},
|
|
40174
|
+
...properties["LifecycleHookSpecificationList"] !== void 0 && {
|
|
40175
|
+
LifecycleHookSpecificationList: properties["LifecycleHookSpecificationList"]
|
|
40176
|
+
},
|
|
40177
|
+
...properties["TrafficSources"] !== void 0 && {
|
|
40178
|
+
TrafficSources: properties["TrafficSources"]
|
|
40179
|
+
},
|
|
40180
|
+
...properties["AvailabilityZoneDistribution"] !== void 0 && {
|
|
40181
|
+
AvailabilityZoneDistribution: properties["AvailabilityZoneDistribution"]
|
|
40182
|
+
},
|
|
40183
|
+
...properties["AvailabilityZoneImpairmentPolicy"] !== void 0 && {
|
|
40184
|
+
AvailabilityZoneImpairmentPolicy: properties["AvailabilityZoneImpairmentPolicy"]
|
|
40185
|
+
},
|
|
40186
|
+
...properties["SkipZonalShiftValidation"] !== void 0 && {
|
|
40187
|
+
SkipZonalShiftValidation: properties["SkipZonalShiftValidation"]
|
|
40188
|
+
},
|
|
40189
|
+
...properties["CapacityReservationSpecification"] !== void 0 && {
|
|
40190
|
+
CapacityReservationSpecification: properties["CapacityReservationSpecification"]
|
|
40191
|
+
},
|
|
40192
|
+
...properties["InstanceMaintenancePolicy"] !== void 0 && {
|
|
40193
|
+
InstanceMaintenancePolicy: properties["InstanceMaintenancePolicy"]
|
|
40194
|
+
},
|
|
40195
|
+
...properties["DeletionProtection"] !== void 0 && {
|
|
40196
|
+
DeletionProtection: properties["DeletionProtection"]
|
|
40197
|
+
},
|
|
40198
|
+
...tags.length > 0 && { Tags: tags }
|
|
40199
|
+
})
|
|
40200
|
+
);
|
|
40201
|
+
this.logger.debug(`Successfully created AutoScalingGroup ${logicalId}: ${groupName}`);
|
|
40202
|
+
const arn = await this.fetchArn(groupName);
|
|
40203
|
+
const attributes = {};
|
|
40204
|
+
if (arn)
|
|
40205
|
+
attributes["Arn"] = arn;
|
|
40206
|
+
if (launchTemplate?.LaunchTemplateId) {
|
|
40207
|
+
attributes["LaunchTemplateID"] = launchTemplate.LaunchTemplateId;
|
|
40208
|
+
}
|
|
40209
|
+
return { physicalId: groupName, attributes };
|
|
40210
|
+
} catch (error) {
|
|
40211
|
+
const cause = error instanceof Error ? error : void 0;
|
|
40212
|
+
throw new ProvisioningError(
|
|
40213
|
+
`Failed to create AutoScalingGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
40214
|
+
resourceType,
|
|
40215
|
+
logicalId,
|
|
40216
|
+
groupName,
|
|
40217
|
+
cause
|
|
40218
|
+
);
|
|
40219
|
+
}
|
|
40220
|
+
}
|
|
40221
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
40222
|
+
if (resourceType !== "AWS::AutoScaling::AutoScalingGroup") {
|
|
40223
|
+
throw new ProvisioningError(
|
|
40224
|
+
`Unsupported resource type: ${resourceType}`,
|
|
40225
|
+
resourceType,
|
|
40226
|
+
logicalId,
|
|
40227
|
+
physicalId
|
|
40228
|
+
);
|
|
40229
|
+
}
|
|
40230
|
+
this.logger.debug(`Updating AutoScalingGroup ${logicalId}: ${physicalId}`);
|
|
40231
|
+
const stringEq = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
40232
|
+
if (!stringEq(properties["AutoScalingGroupName"], previousProperties["AutoScalingGroupName"])) {
|
|
40233
|
+
throw new ResourceUpdateNotSupportedError(
|
|
40234
|
+
resourceType,
|
|
40235
|
+
logicalId,
|
|
40236
|
+
"AutoScalingGroupName is immutable; use cdkd deploy --replace to replace the group"
|
|
40237
|
+
);
|
|
40238
|
+
}
|
|
40239
|
+
if (!stringEq(properties["Tags"] ?? [], previousProperties["Tags"] ?? [])) {
|
|
40240
|
+
throw new ResourceUpdateNotSupportedError(
|
|
40241
|
+
resourceType,
|
|
40242
|
+
logicalId,
|
|
40243
|
+
"Tags updates on AWS::AutoScaling::AutoScalingGroup are not yet supported by cdkd; use cdkd deploy --replace, or update the tags via AWS console / CLI"
|
|
40244
|
+
);
|
|
40245
|
+
}
|
|
40246
|
+
if (!stringEq(
|
|
40247
|
+
properties["LoadBalancerNames"] ?? [],
|
|
40248
|
+
previousProperties["LoadBalancerNames"] ?? []
|
|
40249
|
+
)) {
|
|
40250
|
+
throw new ResourceUpdateNotSupportedError(
|
|
40251
|
+
resourceType,
|
|
40252
|
+
logicalId,
|
|
40253
|
+
"LoadBalancerNames diffs require Attach/Detach calls; use cdkd deploy --replace"
|
|
40254
|
+
);
|
|
40255
|
+
}
|
|
40256
|
+
if (!stringEq(properties["TargetGroupARNs"] ?? [], previousProperties["TargetGroupARNs"] ?? [])) {
|
|
40257
|
+
throw new ResourceUpdateNotSupportedError(
|
|
40258
|
+
resourceType,
|
|
40259
|
+
logicalId,
|
|
40260
|
+
"TargetGroupARNs diffs require Attach/Detach calls; use cdkd deploy --replace"
|
|
40261
|
+
);
|
|
40262
|
+
}
|
|
40263
|
+
if (!stringEq(
|
|
40264
|
+
properties["LifecycleHookSpecificationList"] ?? [],
|
|
40265
|
+
previousProperties["LifecycleHookSpecificationList"] ?? []
|
|
40266
|
+
)) {
|
|
40267
|
+
throw new ResourceUpdateNotSupportedError(
|
|
40268
|
+
resourceType,
|
|
40269
|
+
logicalId,
|
|
40270
|
+
"LifecycleHookSpecificationList diffs require PutLifecycleHook / DeleteLifecycleHook calls; use cdkd deploy --replace"
|
|
40271
|
+
);
|
|
40272
|
+
}
|
|
40273
|
+
if (!stringEq(
|
|
40274
|
+
properties["MetricsCollection"] ?? [],
|
|
40275
|
+
previousProperties["MetricsCollection"] ?? []
|
|
40276
|
+
)) {
|
|
40277
|
+
throw new ResourceUpdateNotSupportedError(
|
|
40278
|
+
resourceType,
|
|
40279
|
+
logicalId,
|
|
40280
|
+
"MetricsCollection diffs require EnableMetricsCollection / DisableMetricsCollection calls; use cdkd deploy --replace"
|
|
40281
|
+
);
|
|
40282
|
+
}
|
|
40283
|
+
if (!stringEq(properties["TrafficSources"] ?? [], previousProperties["TrafficSources"] ?? [])) {
|
|
40284
|
+
throw new ResourceUpdateNotSupportedError(
|
|
40285
|
+
resourceType,
|
|
40286
|
+
logicalId,
|
|
40287
|
+
"TrafficSources diffs require AttachTrafficSources / DetachTrafficSources calls; use cdkd deploy --replace"
|
|
40288
|
+
);
|
|
40289
|
+
}
|
|
40290
|
+
try {
|
|
40291
|
+
const launchTemplate = this.buildLaunchTemplate(properties);
|
|
40292
|
+
const vpcZoneIdentifier = this.joinVpcZoneIdentifier(properties["VPCZoneIdentifier"]);
|
|
40293
|
+
await this.getClient().send(
|
|
40294
|
+
new UpdateAutoScalingGroupCommand({
|
|
40295
|
+
AutoScalingGroupName: physicalId,
|
|
40296
|
+
...properties["MinSize"] != null && { MinSize: Number(properties["MinSize"]) },
|
|
40297
|
+
...properties["MaxSize"] != null && { MaxSize: Number(properties["MaxSize"]) },
|
|
40298
|
+
...properties["DesiredCapacity"] != null && {
|
|
40299
|
+
DesiredCapacity: Number(properties["DesiredCapacity"])
|
|
40300
|
+
},
|
|
40301
|
+
...launchTemplate && { LaunchTemplate: launchTemplate },
|
|
40302
|
+
...properties["MixedInstancesPolicy"] !== void 0 && {
|
|
40303
|
+
MixedInstancesPolicy: properties["MixedInstancesPolicy"]
|
|
40304
|
+
},
|
|
40305
|
+
...vpcZoneIdentifier !== void 0 && { VPCZoneIdentifier: vpcZoneIdentifier },
|
|
40306
|
+
...properties["AvailabilityZones"] !== void 0 && {
|
|
40307
|
+
AvailabilityZones: properties["AvailabilityZones"]
|
|
40308
|
+
},
|
|
40309
|
+
...properties["HealthCheckType"] !== void 0 && {
|
|
40310
|
+
HealthCheckType: properties["HealthCheckType"]
|
|
40311
|
+
},
|
|
40312
|
+
...properties["HealthCheckGracePeriod"] != null && {
|
|
40313
|
+
HealthCheckGracePeriod: Number(properties["HealthCheckGracePeriod"])
|
|
40314
|
+
},
|
|
40315
|
+
...properties["Cooldown"] != null && {
|
|
40316
|
+
DefaultCooldown: Number(properties["Cooldown"])
|
|
40317
|
+
},
|
|
40318
|
+
...properties["DefaultCooldown"] != null && {
|
|
40319
|
+
DefaultCooldown: Number(properties["DefaultCooldown"])
|
|
40320
|
+
},
|
|
40321
|
+
...properties["TerminationPolicies"] !== void 0 && {
|
|
40322
|
+
TerminationPolicies: properties["TerminationPolicies"]
|
|
40323
|
+
},
|
|
40324
|
+
...properties["NewInstancesProtectedFromScaleIn"] !== void 0 && {
|
|
40325
|
+
NewInstancesProtectedFromScaleIn: properties["NewInstancesProtectedFromScaleIn"]
|
|
40326
|
+
},
|
|
40327
|
+
...properties["CapacityRebalance"] !== void 0 && {
|
|
40328
|
+
CapacityRebalance: properties["CapacityRebalance"]
|
|
40329
|
+
},
|
|
40330
|
+
...properties["ServiceLinkedRoleARN"] !== void 0 && {
|
|
40331
|
+
ServiceLinkedRoleARN: properties["ServiceLinkedRoleARN"]
|
|
40332
|
+
},
|
|
40333
|
+
...properties["MaxInstanceLifetime"] != null && {
|
|
40334
|
+
MaxInstanceLifetime: Number(properties["MaxInstanceLifetime"])
|
|
40335
|
+
},
|
|
40336
|
+
...properties["Context"] !== void 0 && {
|
|
40337
|
+
Context: properties["Context"]
|
|
40338
|
+
},
|
|
40339
|
+
...properties["DesiredCapacityType"] !== void 0 && {
|
|
40340
|
+
DesiredCapacityType: properties["DesiredCapacityType"]
|
|
40341
|
+
},
|
|
40342
|
+
...properties["DefaultInstanceWarmup"] != null && {
|
|
40343
|
+
DefaultInstanceWarmup: Number(properties["DefaultInstanceWarmup"])
|
|
40344
|
+
},
|
|
40345
|
+
...properties["AvailabilityZoneDistribution"] !== void 0 && {
|
|
40346
|
+
AvailabilityZoneDistribution: properties["AvailabilityZoneDistribution"]
|
|
40347
|
+
},
|
|
40348
|
+
...properties["AvailabilityZoneImpairmentPolicy"] !== void 0 && {
|
|
40349
|
+
AvailabilityZoneImpairmentPolicy: properties["AvailabilityZoneImpairmentPolicy"]
|
|
40350
|
+
},
|
|
40351
|
+
...properties["SkipZonalShiftValidation"] !== void 0 && {
|
|
40352
|
+
SkipZonalShiftValidation: properties["SkipZonalShiftValidation"]
|
|
40353
|
+
},
|
|
40354
|
+
...properties["CapacityReservationSpecification"] !== void 0 && {
|
|
40355
|
+
CapacityReservationSpecification: properties["CapacityReservationSpecification"]
|
|
40356
|
+
},
|
|
40357
|
+
...properties["InstanceMaintenancePolicy"] !== void 0 && {
|
|
40358
|
+
InstanceMaintenancePolicy: properties["InstanceMaintenancePolicy"]
|
|
40359
|
+
},
|
|
40360
|
+
...properties["DeletionProtection"] !== void 0 && {
|
|
40361
|
+
DeletionProtection: properties["DeletionProtection"]
|
|
40362
|
+
}
|
|
40363
|
+
})
|
|
40364
|
+
);
|
|
40365
|
+
this.logger.debug(`Successfully updated AutoScalingGroup ${logicalId}`);
|
|
40366
|
+
const arn = await this.fetchArn(physicalId);
|
|
40367
|
+
const attributes = {};
|
|
40368
|
+
if (arn)
|
|
40369
|
+
attributes["Arn"] = arn;
|
|
40370
|
+
if (launchTemplate?.LaunchTemplateId) {
|
|
40371
|
+
attributes["LaunchTemplateID"] = launchTemplate.LaunchTemplateId;
|
|
40372
|
+
}
|
|
40373
|
+
return { physicalId, wasReplaced: false, attributes };
|
|
40374
|
+
} catch (error) {
|
|
40375
|
+
if (error instanceof ResourceUpdateNotSupportedError)
|
|
40376
|
+
throw error;
|
|
40377
|
+
const cause = error instanceof Error ? error : void 0;
|
|
40378
|
+
throw new ProvisioningError(
|
|
40379
|
+
`Failed to update AutoScalingGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
40380
|
+
resourceType,
|
|
40381
|
+
logicalId,
|
|
40382
|
+
physicalId,
|
|
40383
|
+
cause
|
|
40384
|
+
);
|
|
40385
|
+
}
|
|
40386
|
+
}
|
|
40387
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
40388
|
+
this.logger.debug(`Deleting AutoScalingGroup ${logicalId}: ${physicalId}`);
|
|
40389
|
+
if (context?.removeProtection === true) {
|
|
40390
|
+
try {
|
|
40391
|
+
await this.getClient().send(
|
|
40392
|
+
new UpdateAutoScalingGroupCommand({
|
|
40393
|
+
AutoScalingGroupName: physicalId,
|
|
40394
|
+
DeletionProtection: "none"
|
|
40395
|
+
})
|
|
40396
|
+
);
|
|
40397
|
+
this.logger.debug(
|
|
40398
|
+
`Disabled DeletionProtection on AutoScalingGroup ${logicalId} before delete`
|
|
40399
|
+
);
|
|
40400
|
+
} catch (flipError) {
|
|
40401
|
+
this.logger.debug(
|
|
40402
|
+
`Could not disable DeletionProtection on ${physicalId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`
|
|
40403
|
+
);
|
|
40404
|
+
}
|
|
40405
|
+
}
|
|
40406
|
+
try {
|
|
40407
|
+
await this.getClient().send(
|
|
40408
|
+
new DeleteAutoScalingGroupCommand({
|
|
40409
|
+
AutoScalingGroupName: physicalId,
|
|
40410
|
+
ForceDelete: context?.removeProtection === true
|
|
40411
|
+
})
|
|
40412
|
+
);
|
|
40413
|
+
this.logger.debug(`Successfully initiated deletion of AutoScalingGroup ${logicalId}`);
|
|
40414
|
+
await this.waitForGroupDeleted(physicalId);
|
|
40415
|
+
} catch (error) {
|
|
40416
|
+
if (this.isNotFoundError(error)) {
|
|
40417
|
+
const clientRegion = await this.getClient().config.region();
|
|
40418
|
+
assertRegionMatch(
|
|
40419
|
+
clientRegion,
|
|
40420
|
+
context?.expectedRegion,
|
|
40421
|
+
resourceType,
|
|
40422
|
+
logicalId,
|
|
40423
|
+
physicalId
|
|
40424
|
+
);
|
|
40425
|
+
this.logger.debug(`AutoScalingGroup ${physicalId} does not exist, skipping deletion`);
|
|
40426
|
+
return;
|
|
40427
|
+
}
|
|
40428
|
+
const cause = error instanceof Error ? error : void 0;
|
|
40429
|
+
throw new ProvisioningError(
|
|
40430
|
+
`Failed to delete AutoScalingGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
40431
|
+
resourceType,
|
|
40432
|
+
logicalId,
|
|
40433
|
+
physicalId,
|
|
40434
|
+
cause
|
|
40435
|
+
);
|
|
40436
|
+
}
|
|
40437
|
+
}
|
|
40438
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
40439
|
+
const group = await this.describeGroup(physicalId);
|
|
40440
|
+
if (!group) {
|
|
40441
|
+
throw new ProvisioningError(
|
|
40442
|
+
`AutoScalingGroup ${physicalId} not found while resolving attribute ${attributeName}`,
|
|
40443
|
+
"AWS::AutoScaling::AutoScalingGroup",
|
|
40444
|
+
physicalId,
|
|
40445
|
+
physicalId
|
|
40446
|
+
);
|
|
40447
|
+
}
|
|
40448
|
+
switch (attributeName) {
|
|
40449
|
+
case "Arn":
|
|
40450
|
+
case "AutoScalingGroupARN":
|
|
40451
|
+
return group.AutoScalingGroupARN ?? "";
|
|
40452
|
+
case "LaunchConfigurationName":
|
|
40453
|
+
return group.LaunchConfigurationName ?? "";
|
|
40454
|
+
case "LaunchTemplateID":
|
|
40455
|
+
case "LaunchTemplateId":
|
|
40456
|
+
return group.LaunchTemplate?.LaunchTemplateId ?? "";
|
|
40457
|
+
default:
|
|
40458
|
+
return "";
|
|
40459
|
+
}
|
|
40460
|
+
}
|
|
40461
|
+
/**
|
|
40462
|
+
* Read the AWS-current AutoScalingGroup configuration in CFn-property shape.
|
|
40463
|
+
*
|
|
40464
|
+
* Surfaces the user-controllable subset of `DescribeAutoScalingGroups`,
|
|
40465
|
+
* with always-emit placeholders on user-controllable top-level keys per
|
|
40466
|
+
* the cdkd PR #145 always-emit convention so that v3 `observedProperties`
|
|
40467
|
+
* baseline catches console-side ADDs to fields a clean deploy did not
|
|
40468
|
+
* template (e.g. a console-set `DeletionProtection: 'prevent-force-deletion'`
|
|
40469
|
+
* on a group originally created without it).
|
|
40470
|
+
*
|
|
40471
|
+
* Returns `undefined` when the group is gone.
|
|
40472
|
+
*/
|
|
40473
|
+
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
40474
|
+
let group;
|
|
40475
|
+
try {
|
|
40476
|
+
group = await this.describeGroup(physicalId);
|
|
40477
|
+
} catch (err) {
|
|
40478
|
+
if (this.isNotFoundError(err))
|
|
40479
|
+
return void 0;
|
|
40480
|
+
throw err;
|
|
40481
|
+
}
|
|
40482
|
+
if (!group)
|
|
40483
|
+
return void 0;
|
|
40484
|
+
const result = {};
|
|
40485
|
+
if (group.AutoScalingGroupName !== void 0) {
|
|
40486
|
+
result["AutoScalingGroupName"] = group.AutoScalingGroupName;
|
|
40487
|
+
}
|
|
40488
|
+
if (group.LaunchTemplate) {
|
|
40489
|
+
const lt = {};
|
|
40490
|
+
if (group.LaunchTemplate.LaunchTemplateId !== void 0) {
|
|
40491
|
+
lt["LaunchTemplateId"] = group.LaunchTemplate.LaunchTemplateId;
|
|
40492
|
+
}
|
|
40493
|
+
if (group.LaunchTemplate.LaunchTemplateName !== void 0) {
|
|
40494
|
+
lt["LaunchTemplateName"] = group.LaunchTemplate.LaunchTemplateName;
|
|
40495
|
+
}
|
|
40496
|
+
if (group.LaunchTemplate.Version !== void 0) {
|
|
40497
|
+
lt["Version"] = group.LaunchTemplate.Version;
|
|
40498
|
+
}
|
|
40499
|
+
result["LaunchTemplate"] = lt;
|
|
40500
|
+
}
|
|
40501
|
+
result["MinSize"] = group.MinSize ?? 0;
|
|
40502
|
+
result["MaxSize"] = group.MaxSize ?? 0;
|
|
40503
|
+
if (group.DesiredCapacity !== void 0)
|
|
40504
|
+
result["DesiredCapacity"] = group.DesiredCapacity;
|
|
40505
|
+
if (group.VPCZoneIdentifier !== void 0 && group.VPCZoneIdentifier !== "") {
|
|
40506
|
+
result["VPCZoneIdentifier"] = group.VPCZoneIdentifier.split(",").map((s) => s.trim());
|
|
40507
|
+
} else {
|
|
40508
|
+
result["VPCZoneIdentifier"] = [];
|
|
40509
|
+
}
|
|
40510
|
+
result["AvailabilityZones"] = group.AvailabilityZones ?? [];
|
|
40511
|
+
if (group.HealthCheckType !== void 0)
|
|
40512
|
+
result["HealthCheckType"] = group.HealthCheckType;
|
|
40513
|
+
if (group.HealthCheckGracePeriod !== void 0) {
|
|
40514
|
+
result["HealthCheckGracePeriod"] = group.HealthCheckGracePeriod;
|
|
40515
|
+
}
|
|
40516
|
+
if (group.DefaultCooldown !== void 0) {
|
|
40517
|
+
result["Cooldown"] = group.DefaultCooldown;
|
|
40518
|
+
}
|
|
40519
|
+
result["NewInstancesProtectedFromScaleIn"] = group.NewInstancesProtectedFromScaleIn ?? false;
|
|
40520
|
+
result["TerminationPolicies"] = group.TerminationPolicies ?? [];
|
|
40521
|
+
result["CapacityRebalance"] = group.CapacityRebalance ?? false;
|
|
40522
|
+
if (group.ServiceLinkedRoleARN !== void 0) {
|
|
40523
|
+
result["ServiceLinkedRoleARN"] = group.ServiceLinkedRoleARN;
|
|
40524
|
+
}
|
|
40525
|
+
if (group.MaxInstanceLifetime !== void 0) {
|
|
40526
|
+
result["MaxInstanceLifetime"] = group.MaxInstanceLifetime;
|
|
40527
|
+
}
|
|
40528
|
+
result["LoadBalancerNames"] = group.LoadBalancerNames ?? [];
|
|
40529
|
+
result["TargetGroupARNs"] = group.TargetGroupARNs ?? [];
|
|
40530
|
+
if (group.Context !== void 0)
|
|
40531
|
+
result["Context"] = group.Context;
|
|
40532
|
+
if (group.DesiredCapacityType !== void 0) {
|
|
40533
|
+
result["DesiredCapacityType"] = group.DesiredCapacityType;
|
|
40534
|
+
}
|
|
40535
|
+
if (group.DefaultInstanceWarmup !== void 0) {
|
|
40536
|
+
result["DefaultInstanceWarmup"] = group.DefaultInstanceWarmup;
|
|
40537
|
+
}
|
|
40538
|
+
if (group.MixedInstancesPolicy !== void 0) {
|
|
40539
|
+
result["MixedInstancesPolicy"] = group.MixedInstancesPolicy;
|
|
40540
|
+
}
|
|
40541
|
+
if (group.AvailabilityZoneDistribution !== void 0) {
|
|
40542
|
+
result["AvailabilityZoneDistribution"] = group.AvailabilityZoneDistribution;
|
|
40543
|
+
}
|
|
40544
|
+
if (group.AvailabilityZoneImpairmentPolicy !== void 0) {
|
|
40545
|
+
result["AvailabilityZoneImpairmentPolicy"] = group.AvailabilityZoneImpairmentPolicy;
|
|
40546
|
+
}
|
|
40547
|
+
if (group.CapacityReservationSpecification !== void 0) {
|
|
40548
|
+
result["CapacityReservationSpecification"] = group.CapacityReservationSpecification;
|
|
40549
|
+
}
|
|
40550
|
+
if (group.InstanceMaintenancePolicy !== void 0) {
|
|
40551
|
+
result["InstanceMaintenancePolicy"] = group.InstanceMaintenancePolicy;
|
|
40552
|
+
}
|
|
40553
|
+
if (group.DeletionProtection !== void 0) {
|
|
40554
|
+
result["DeletionProtection"] = group.DeletionProtection;
|
|
40555
|
+
} else {
|
|
40556
|
+
result["DeletionProtection"] = "none";
|
|
40557
|
+
}
|
|
40558
|
+
result["Tags"] = normalizeAwsTagsToCfn(group.Tags);
|
|
40559
|
+
return result;
|
|
40560
|
+
}
|
|
40561
|
+
/**
|
|
40562
|
+
* MetricsCollection / LifecycleHookSpecificationList / TrafficSources
|
|
40563
|
+
* are surfaced via separate APIs (`DescribeMetricsCollectionTypes` etc.
|
|
40564
|
+
* + `DescribeLifecycleHooks` + `DescribeTrafficSources`) that this v1
|
|
40565
|
+
* does not yet wire up — declare them as drift-unknown so the comparator
|
|
40566
|
+
* does not fire false-positive drift on every clean run.
|
|
40567
|
+
*/
|
|
40568
|
+
getDriftUnknownPaths(_resourceType) {
|
|
40569
|
+
return [
|
|
40570
|
+
"MetricsCollection",
|
|
40571
|
+
"LifecycleHookSpecificationList",
|
|
40572
|
+
"TrafficSources",
|
|
40573
|
+
"NotificationConfigurations"
|
|
40574
|
+
];
|
|
40575
|
+
}
|
|
40576
|
+
// ─── Helpers ──────────────────────────────────────────────────────
|
|
40577
|
+
buildLaunchTemplate(properties) {
|
|
40578
|
+
const lt = properties["LaunchTemplate"];
|
|
40579
|
+
if (!lt)
|
|
40580
|
+
return void 0;
|
|
40581
|
+
const out = {};
|
|
40582
|
+
if (lt.LaunchTemplateId !== void 0)
|
|
40583
|
+
out.LaunchTemplateId = lt.LaunchTemplateId;
|
|
40584
|
+
if (lt.LaunchTemplateName !== void 0)
|
|
40585
|
+
out.LaunchTemplateName = lt.LaunchTemplateName;
|
|
40586
|
+
if (lt.Version !== void 0) {
|
|
40587
|
+
out.Version = String(lt.Version);
|
|
40588
|
+
}
|
|
40589
|
+
if (out.LaunchTemplateId === void 0 && out.LaunchTemplateName === void 0) {
|
|
40590
|
+
return void 0;
|
|
40591
|
+
}
|
|
40592
|
+
return out;
|
|
40593
|
+
}
|
|
40594
|
+
/**
|
|
40595
|
+
* CFn `Tags` is `[{Key, Value, PropagateAtLaunch?}]`. AWS expects each
|
|
40596
|
+
* tag to also carry `ResourceId: <groupName>` and `ResourceType:
|
|
40597
|
+
* 'auto-scaling-group'`. We tack those on at create time so the SDK
|
|
40598
|
+
* input shape matches without forcing the user to template them.
|
|
40599
|
+
*/
|
|
40600
|
+
buildTags(groupName, properties) {
|
|
40601
|
+
const raw = properties["Tags"];
|
|
40602
|
+
if (!raw)
|
|
40603
|
+
return [];
|
|
40604
|
+
return raw.filter((t) => t.Key !== void 0).map((t) => ({
|
|
40605
|
+
ResourceId: groupName,
|
|
40606
|
+
ResourceType: "auto-scaling-group",
|
|
40607
|
+
Key: t.Key,
|
|
40608
|
+
Value: t.Value ?? "",
|
|
40609
|
+
PropagateAtLaunch: t.PropagateAtLaunch ?? false
|
|
40610
|
+
}));
|
|
40611
|
+
}
|
|
40612
|
+
/**
|
|
40613
|
+
* CFn `VPCZoneIdentifier` is a list of subnet ids; the AWS SDK input
|
|
40614
|
+
* field is a comma-joined string.
|
|
40615
|
+
*/
|
|
40616
|
+
joinVpcZoneIdentifier(value) {
|
|
40617
|
+
if (value === void 0 || value === null)
|
|
40618
|
+
return void 0;
|
|
40619
|
+
if (Array.isArray(value)) {
|
|
40620
|
+
const cleaned = value.map((v) => String(v).trim()).filter((v) => v.length > 0);
|
|
40621
|
+
if (cleaned.length === 0)
|
|
40622
|
+
return void 0;
|
|
40623
|
+
return cleaned.join(",");
|
|
40624
|
+
}
|
|
40625
|
+
if (typeof value === "string")
|
|
40626
|
+
return value;
|
|
40627
|
+
return void 0;
|
|
40628
|
+
}
|
|
40629
|
+
async describeGroup(groupName) {
|
|
40630
|
+
const response = await this.getClient().send(
|
|
40631
|
+
new DescribeAutoScalingGroupsCommand({
|
|
40632
|
+
AutoScalingGroupNames: [groupName]
|
|
40633
|
+
})
|
|
40634
|
+
);
|
|
40635
|
+
return response.AutoScalingGroups?.[0];
|
|
40636
|
+
}
|
|
40637
|
+
async fetchArn(groupName) {
|
|
40638
|
+
try {
|
|
40639
|
+
const group = await this.describeGroup(groupName);
|
|
40640
|
+
return group?.AutoScalingGroupARN;
|
|
40641
|
+
} catch (err) {
|
|
40642
|
+
this.logger.debug(
|
|
40643
|
+
`DescribeAutoScalingGroups(${groupName}) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
40644
|
+
);
|
|
40645
|
+
return void 0;
|
|
40646
|
+
}
|
|
40647
|
+
}
|
|
40648
|
+
isNotFoundError(error) {
|
|
40649
|
+
if (!(error instanceof Error))
|
|
40650
|
+
return false;
|
|
40651
|
+
const name = error.name ?? "";
|
|
40652
|
+
const message = error.message.toLowerCase();
|
|
40653
|
+
return name === "ValidationError" && (message.includes("autoscalinggroup name not found") || message.includes("not found") || message.includes("does not exist"));
|
|
40654
|
+
}
|
|
40655
|
+
async waitForGroupDeleted(groupName, maxWaitMs = 9e5) {
|
|
40656
|
+
const startTime = Date.now();
|
|
40657
|
+
let delay = 5e3;
|
|
40658
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
40659
|
+
try {
|
|
40660
|
+
const group = await this.describeGroup(groupName);
|
|
40661
|
+
if (!group)
|
|
40662
|
+
return;
|
|
40663
|
+
} catch (error) {
|
|
40664
|
+
if (this.isNotFoundError(error))
|
|
40665
|
+
return;
|
|
40666
|
+
throw error;
|
|
40667
|
+
}
|
|
40668
|
+
await this.sleep(delay);
|
|
40669
|
+
delay = Math.min(delay * 2, 3e4);
|
|
40670
|
+
}
|
|
40671
|
+
throw new Error(
|
|
40672
|
+
`Timed out waiting for AutoScalingGroup ${groupName} to be deleted (15 minute cap)`
|
|
40673
|
+
);
|
|
40674
|
+
}
|
|
40675
|
+
sleep(ms) {
|
|
40676
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
40677
|
+
}
|
|
40678
|
+
};
|
|
40679
|
+
|
|
39887
40680
|
// src/provisioning/register-providers.ts
|
|
39888
40681
|
function registerAllProviders(registry) {
|
|
39889
40682
|
registry.register("AWS::IAM::Role", new IAMRoleProvider());
|
|
@@ -39990,6 +40783,7 @@ function registerAllProviders(registry) {
|
|
|
39990
40783
|
registry.register("AWS::CodeBuild::Project", new CodeBuildProvider());
|
|
39991
40784
|
registry.register("AWS::S3Vectors::VectorBucket", new S3VectorsProvider());
|
|
39992
40785
|
registry.register("AWS::ECR::Repository", new ECRProvider());
|
|
40786
|
+
registry.register("AWS::AutoScaling::AutoScalingGroup", new ASGProvider());
|
|
39993
40787
|
const s3TablesProvider = new S3TablesProvider();
|
|
39994
40788
|
registry.register("AWS::S3Tables::TableBucket", s3TablesProvider);
|
|
39995
40789
|
registry.register("AWS::S3Tables::Namespace", s3TablesProvider);
|
|
@@ -42952,6 +43746,43 @@ init_aws_clients();
|
|
|
42952
43746
|
// src/cli/commands/destroy-runner.ts
|
|
42953
43747
|
import * as readline2 from "node:readline/promises";
|
|
42954
43748
|
init_aws_clients();
|
|
43749
|
+
var PROTECTION_PROPERTY_BY_TYPE = {
|
|
43750
|
+
"AWS::Logs::LogGroup": "DeletionProtectionEnabled",
|
|
43751
|
+
"AWS::RDS::DBInstance": "DeletionProtection",
|
|
43752
|
+
"AWS::RDS::DBCluster": "DeletionProtection",
|
|
43753
|
+
"AWS::DynamoDB::Table": "DeletionProtectionEnabled",
|
|
43754
|
+
"AWS::EC2::Instance": "DisableApiTermination",
|
|
43755
|
+
"AWS::Cognito::UserPool": "DeletionProtection",
|
|
43756
|
+
"AWS::AutoScaling::AutoScalingGroup": "DeletionProtection"
|
|
43757
|
+
};
|
|
43758
|
+
var PROTECTION_ACTIVE_VALUES_BY_TYPE = {
|
|
43759
|
+
"AWS::Cognito::UserPool": /* @__PURE__ */ new Set(["ACTIVE"]),
|
|
43760
|
+
"AWS::AutoScaling::AutoScalingGroup": /* @__PURE__ */ new Set(["prevent-force-deletion", "prevent-all-deletion"])
|
|
43761
|
+
};
|
|
43762
|
+
function countProtectedResources(state) {
|
|
43763
|
+
let count = 0;
|
|
43764
|
+
for (const resource of Object.values(state.resources ?? {})) {
|
|
43765
|
+
const propName = PROTECTION_PROPERTY_BY_TYPE[resource.resourceType];
|
|
43766
|
+
if (propName) {
|
|
43767
|
+
const recorded = resource.properties?.[propName] ?? resource.observedProperties?.[propName];
|
|
43768
|
+
const activeValues = PROTECTION_ACTIVE_VALUES_BY_TYPE[resource.resourceType];
|
|
43769
|
+
if (activeValues) {
|
|
43770
|
+
if (activeValues.has(recorded))
|
|
43771
|
+
count++;
|
|
43772
|
+
} else if (recorded === true) {
|
|
43773
|
+
count++;
|
|
43774
|
+
}
|
|
43775
|
+
continue;
|
|
43776
|
+
}
|
|
43777
|
+
if (resource.resourceType === "AWS::ElasticLoadBalancingV2::LoadBalancer") {
|
|
43778
|
+
const attrs = resource.properties?.["LoadBalancerAttributes"] ?? resource.observedProperties?.["LoadBalancerAttributes"];
|
|
43779
|
+
const enabled = attrs?.find((a) => a?.Key === "deletion_protection.enabled");
|
|
43780
|
+
if (enabled?.Value === "true")
|
|
43781
|
+
count++;
|
|
43782
|
+
}
|
|
43783
|
+
}
|
|
43784
|
+
return count;
|
|
43785
|
+
}
|
|
42955
43786
|
async function runDestroyForStack(stackName, state, ctx) {
|
|
42956
43787
|
const logger = getLogger();
|
|
42957
43788
|
const result = {
|
|
@@ -42975,18 +43806,25 @@ Resources to be deleted (${resourceCount}):`);
|
|
|
42975
43806
|
for (const [logicalId, resource] of Object.entries(state.resources)) {
|
|
42976
43807
|
logger.info(` - ${logicalId} (${resource.resourceType})`);
|
|
42977
43808
|
}
|
|
43809
|
+
const protectedCount = ctx.removeProtection ? countProtectedResources(state) : 0;
|
|
42978
43810
|
if (!ctx.skipConfirmation) {
|
|
42979
43811
|
const rl = readline2.createInterface({
|
|
42980
43812
|
input: process.stdin,
|
|
42981
43813
|
output: process.stdout
|
|
42982
43814
|
});
|
|
42983
|
-
const
|
|
42984
|
-
|
|
42985
|
-
Are you sure you want to destroy stack "${stackName}" and delete all ${resourceCount} resources? (Y/n):
|
|
42986
|
-
);
|
|
43815
|
+
const prompt = ctx.removeProtection ? `
|
|
43816
|
+
About to destroy ${resourceCount} resources from stack "${stackName}", REMOVING DELETION PROTECTION on ${protectedCount} of them. Continue? (y/N): ` : `
|
|
43817
|
+
Are you sure you want to destroy stack "${stackName}" and delete all ${resourceCount} resources? (Y/n): `;
|
|
43818
|
+
const answer = await rl.question(prompt);
|
|
42987
43819
|
rl.close();
|
|
42988
43820
|
const trimmed = answer.trim().toLowerCase();
|
|
42989
|
-
if (
|
|
43821
|
+
if (ctx.removeProtection) {
|
|
43822
|
+
if (trimmed !== "y" && trimmed !== "yes") {
|
|
43823
|
+
logger.info("Destroy cancelled");
|
|
43824
|
+
result.cancelled = true;
|
|
43825
|
+
return result;
|
|
43826
|
+
}
|
|
43827
|
+
} else if (trimmed === "n" || trimmed === "no") {
|
|
42990
43828
|
logger.info("Destroy cancelled");
|
|
42991
43829
|
result.cancelled = true;
|
|
42992
43830
|
return result;
|
|
@@ -43093,7 +43931,11 @@ Acquiring lock for stack ${stackName}...`);
|
|
|
43093
43931
|
logicalId,
|
|
43094
43932
|
resource.physicalId,
|
|
43095
43933
|
resource.resourceType,
|
|
43096
|
-
resource.properties
|
|
43934
|
+
resource.properties,
|
|
43935
|
+
{
|
|
43936
|
+
...state.region !== void 0 && { expectedRegion: state.region },
|
|
43937
|
+
...ctx.removeProtection === true && { removeProtection: true }
|
|
43938
|
+
}
|
|
43097
43939
|
);
|
|
43098
43940
|
lastDeleteError = null;
|
|
43099
43941
|
break;
|
|
@@ -43315,10 +44157,16 @@ Preparing to destroy stack: ${stackName}`);
|
|
|
43315
44157
|
const synthStack = appStacks.find((s) => s.stackName === stackName);
|
|
43316
44158
|
const synthRegion = synthStack?.region;
|
|
43317
44159
|
if (synthStack?.terminationProtection === true) {
|
|
43318
|
-
|
|
43319
|
-
|
|
43320
|
-
|
|
43321
|
-
|
|
44160
|
+
if (options.removeProtection) {
|
|
44161
|
+
logger.warn(
|
|
44162
|
+
`Stack ${stackName} has terminationProtection: true \u2014 bypassing because --remove-protection set`
|
|
44163
|
+
);
|
|
44164
|
+
} else {
|
|
44165
|
+
const err = new StackTerminationProtectionError(stackName);
|
|
44166
|
+
logger.error(` \u2717 ${err.message}`);
|
|
44167
|
+
totalErrors++;
|
|
44168
|
+
continue;
|
|
44169
|
+
}
|
|
43322
44170
|
}
|
|
43323
44171
|
let stackTargetRegion;
|
|
43324
44172
|
if (refs.length === 0) {
|
|
@@ -43353,6 +44201,7 @@ Preparing to destroy stack: ${stackName}`);
|
|
|
43353
44201
|
...options.profile && { profile: options.profile },
|
|
43354
44202
|
stateBucket,
|
|
43355
44203
|
skipConfirmation: options.yes || options.force,
|
|
44204
|
+
removeProtection: options.removeProtection === true,
|
|
43356
44205
|
...options.resourceWarnAfter?.globalMs !== void 0 && {
|
|
43357
44206
|
resourceWarnAfterMs: options.resourceWarnAfter.globalMs
|
|
43358
44207
|
},
|
|
@@ -45190,6 +46039,7 @@ Preparing to destroy stack: ${stackName}${ref.region ? ` (${ref.region})` : ""}`
|
|
|
45190
46039
|
// skipped when `options.yes` is set OR `--all` was set (the user
|
|
45191
46040
|
// already accepted the batch prompt).
|
|
45192
46041
|
skipConfirmation: options.yes || options.all === true,
|
|
46042
|
+
removeProtection: options.removeProtection === true,
|
|
45193
46043
|
...options.resourceWarnAfter?.globalMs !== void 0 && {
|
|
45194
46044
|
resourceWarnAfterMs: options.resourceWarnAfter.globalMs
|
|
45195
46045
|
},
|
|
@@ -45218,7 +46068,11 @@ Preparing to destroy stack: ${stackName}${ref.region ? ` (${ref.region})` : ""}`
|
|
|
45218
46068
|
function createStateDestroyCommand() {
|
|
45219
46069
|
const cmd = new Command12("destroy").description(
|
|
45220
46070
|
"Destroy a stack's AWS resources and remove its state record without requiring the CDK app. For removing only the state record (keeping AWS resources intact), use 'cdkd state orphan'."
|
|
45221
|
-
).argument("[stacks...]", "Stack name(s) to destroy (physical CloudFormation names)").option("--all", "Destroy every stack in the state bucket", false).
|
|
46071
|
+
).argument("[stacks...]", "Stack name(s) to destroy (physical CloudFormation names)").option("--all", "Destroy every stack in the state bucket", false).option(
|
|
46072
|
+
"--remove-protection",
|
|
46073
|
+
"Bypass deletion protection on protected resources by flipping the per-resource protection flag off in-place before delete. Covers AWS::Logs::LogGroup, AWS::RDS::DBInstance, AWS::RDS::DBCluster, AWS::DynamoDB::Table, AWS::EC2::Instance, and AWS::ElasticLoadBalancingV2::LoadBalancer.",
|
|
46074
|
+
false
|
|
46075
|
+
).addOption(stackRegionOption2()).addHelpText(
|
|
45222
46076
|
"after",
|
|
45223
46077
|
[
|
|
45224
46078
|
"",
|
|
@@ -46358,7 +47212,7 @@ function reorderArgs(argv) {
|
|
|
46358
47212
|
}
|
|
46359
47213
|
async function main() {
|
|
46360
47214
|
const program = new Command14();
|
|
46361
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
47215
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.59.1");
|
|
46362
47216
|
program.addCommand(createBootstrapCommand());
|
|
46363
47217
|
program.addCommand(createSynthCommand());
|
|
46364
47218
|
program.addCommand(createListCommand());
|