@go-to-k/cdkd 0.30.2 → 0.31.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 +43 -6
- package/dist/cli.js +190 -9
- package/dist/cli.js.map +2 -2
- package/dist/go-to-k-cdkd-0.31.1.tgz +0 -0
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.30.2.tgz +0 -0
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
- **Diff calculation**: Self-implemented resource/property-level diff between desired template and current state
|
|
25
25
|
- **S3-based state management**: No DynamoDB required, uses S3 conditional writes for locking
|
|
26
26
|
- **DAG-based parallelization**: Analyze `Ref`/`Fn::GetAtt` dependencies and execute in parallel
|
|
27
|
-
- **`--no-wait` for async resources**: Skip the multi-minute wait on CloudFront / RDS / ElastiCache and return as soon as the create call returns (CloudFormation always blocks)
|
|
27
|
+
- **`--no-wait` for async resources**: Skip the multi-minute wait on CloudFront / RDS / ElastiCache / NAT Gateway and return as soon as the create call returns (CloudFormation always blocks)
|
|
28
28
|
|
|
29
29
|
> **Note**: Resource types not covered by either SDK Providers or Cloud Control API cannot be deployed with cdkd. If you encounter an unsupported resource type, deployment will fail with a clear error message.
|
|
30
30
|
|
|
@@ -372,11 +372,11 @@ cdkd state destroy MyStack --region us-east-1
|
|
|
372
372
|
|
|
373
373
|
## `--no-wait`: skip async-resource waits
|
|
374
374
|
|
|
375
|
-
CloudFront Distributions, RDS Clusters/Instances, and
|
|
376
|
-
typically take
|
|
377
|
-
cdkd waits for them to reach a ready state — the same
|
|
378
|
-
CloudFormation. Pass `--no-wait` to return as soon as the
|
|
379
|
-
returns:
|
|
375
|
+
CloudFront Distributions, RDS Clusters/Instances, ElastiCache, and
|
|
376
|
+
NAT Gateways typically take 1–15 minutes for AWS to fully provision.
|
|
377
|
+
By default cdkd waits for them to reach a ready state — the same
|
|
378
|
+
behavior as CloudFormation. Pass `--no-wait` to return as soon as the
|
|
379
|
+
create call returns:
|
|
380
380
|
|
|
381
381
|
```bash
|
|
382
382
|
cdkd deploy --no-wait
|
|
@@ -386,6 +386,25 @@ The resource is fully functional once AWS finishes the async
|
|
|
386
386
|
deployment in the background. CloudFormation has no equivalent — once
|
|
387
387
|
you submit a stack, you wait for everything.
|
|
388
388
|
|
|
389
|
+
NAT Gateway is included as of v0.31. Provisioning typically takes
|
|
390
|
+
1–2 minutes and is the dominant cost in many VPC stacks; with
|
|
391
|
+
`cdkd deploy --no-wait`, `CreateNatGateway` returns the `NatGatewayId`
|
|
392
|
+
immediately and dependent Routes that only reference the ID can
|
|
393
|
+
proceed against a still-`pending` gateway. AWS continues NAT
|
|
394
|
+
provisioning asynchronously after the deploy returns. Use this only
|
|
395
|
+
when nothing in the deploy flow needs actual NAT-routed egress (e.g.
|
|
396
|
+
no Lambda invoked during deploy that hits the internet).
|
|
397
|
+
|
|
398
|
+
`--no-wait` is **deploy-only**. `cdkd destroy` always waits for NAT
|
|
399
|
+
Gateway to reach `deleted` state — while the gateway is in
|
|
400
|
+
`deleting` AWS keeps the ENI / EIP / route-table associations
|
|
401
|
+
attached, so any concurrent `DeleteSubnet` / `DeleteInternetGateway`
|
|
402
|
+
/ `DeleteVpc` returns `DependencyViolation` and the destroy enters a
|
|
403
|
+
retry storm. Other `--no-wait` resources (CloudFront / RDS /
|
|
404
|
+
ElastiCache) don't apply to destroy either — their providers are
|
|
405
|
+
already non-blocking on delete because they're leaves in the destroy
|
|
406
|
+
DAG.
|
|
407
|
+
|
|
389
408
|
## Other CLI flags
|
|
390
409
|
|
|
391
410
|
For concurrency knobs (`--concurrency`, `--stack-concurrency`,
|
|
@@ -395,6 +414,24 @@ per-resource timeout flags (`--resource-warn-after`,
|
|
|
395
414
|
and the rationale for the 30m default), see
|
|
396
415
|
**[docs/cli-reference.md](docs/cli-reference.md)**.
|
|
397
416
|
|
|
417
|
+
## Exit codes
|
|
418
|
+
|
|
419
|
+
cdkd commands distinguish three outcomes via the process exit code so
|
|
420
|
+
CI / bench scripts can react without grepping log output:
|
|
421
|
+
|
|
422
|
+
| Exit | Meaning |
|
|
423
|
+
|------|---------|
|
|
424
|
+
| `0` | Success — command completed and no resources are in an error state |
|
|
425
|
+
| `1` | Command-level failure — auth error, bad arguments, synth crash, unhandled exception |
|
|
426
|
+
| `2` | **Partial failure** — work completed but one or more resources failed (state.json is preserved, re-running typically resolves it) |
|
|
427
|
+
|
|
428
|
+
Exit `2` is currently emitted by `cdkd destroy` and `cdkd state
|
|
429
|
+
destroy` when one or more per-resource deletes fail. The summary line
|
|
430
|
+
also switches from `✓ Stack X destroyed` to `⚠ Stack X partially
|
|
431
|
+
destroyed (...). State preserved — re-run 'cdkd destroy' / 'cdkd
|
|
432
|
+
state destroy' to clean up.` so the visual marker matches the exit
|
|
433
|
+
code.
|
|
434
|
+
|
|
398
435
|
## Example
|
|
399
436
|
|
|
400
437
|
```typescript
|
package/dist/cli.js
CHANGED
|
@@ -606,6 +606,10 @@ function validateResourceTimeouts(opts) {
|
|
|
606
606
|
}
|
|
607
607
|
}
|
|
608
608
|
}
|
|
609
|
+
var noWaitOption = new Option(
|
|
610
|
+
"--no-wait",
|
|
611
|
+
"Skip waiting for async resources to stabilize (CloudFront, RDS, ElastiCache, NAT Gateway)"
|
|
612
|
+
);
|
|
609
613
|
var deployOptions = [
|
|
610
614
|
new Option("--concurrency <number>", "Maximum concurrent resource operations").default(10).argParser((value) => parseInt(value, 10)),
|
|
611
615
|
new Option("--stack-concurrency <number>", "Maximum concurrent stack deployments").default(4).argParser((value) => parseInt(value, 10)),
|
|
@@ -617,7 +621,7 @@ var deployOptions = [
|
|
|
617
621
|
new Option("--dry-run", "Show changes without applying").default(false),
|
|
618
622
|
new Option("--skip-assets", "Skip asset publishing").default(false),
|
|
619
623
|
new Option("--no-rollback", "Skip rollback on deployment failure"),
|
|
620
|
-
|
|
624
|
+
noWaitOption,
|
|
621
625
|
new Option(
|
|
622
626
|
"-e, --exclusively",
|
|
623
627
|
"Only deploy requested stacks, do not include dependencies"
|
|
@@ -1166,6 +1170,14 @@ var DependencyError = class _DependencyError extends CdkdError {
|
|
|
1166
1170
|
Object.setPrototypeOf(this, _DependencyError.prototype);
|
|
1167
1171
|
}
|
|
1168
1172
|
};
|
|
1173
|
+
var PartialFailureError = class _PartialFailureError extends CdkdError {
|
|
1174
|
+
exitCode = 2;
|
|
1175
|
+
constructor(message, cause) {
|
|
1176
|
+
super(message, "PARTIAL_FAILURE", cause);
|
|
1177
|
+
this.name = "PartialFailureError";
|
|
1178
|
+
Object.setPrototypeOf(this, _PartialFailureError.prototype);
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1169
1181
|
function isCdkdError(error) {
|
|
1170
1182
|
return error instanceof CdkdError;
|
|
1171
1183
|
}
|
|
@@ -1189,7 +1201,8 @@ function handleError(error) {
|
|
|
1189
1201
|
if (error instanceof Error && error.stack) {
|
|
1190
1202
|
logger.debug("Stack trace:", error.stack);
|
|
1191
1203
|
}
|
|
1192
|
-
|
|
1204
|
+
const exitCode = error instanceof PartialFailureError ? error.exitCode : 1;
|
|
1205
|
+
process.exit(exitCode);
|
|
1193
1206
|
}
|
|
1194
1207
|
function withErrorHandling(fn) {
|
|
1195
1208
|
return async (...args) => {
|
|
@@ -16790,6 +16803,11 @@ import {
|
|
|
16790
16803
|
DeleteInternetGatewayCommand,
|
|
16791
16804
|
AttachInternetGatewayCommand,
|
|
16792
16805
|
DetachInternetGatewayCommand,
|
|
16806
|
+
CreateNatGatewayCommand,
|
|
16807
|
+
DeleteNatGatewayCommand,
|
|
16808
|
+
DescribeNatGatewaysCommand,
|
|
16809
|
+
waitUntilNatGatewayAvailable,
|
|
16810
|
+
waitUntilNatGatewayDeleted,
|
|
16793
16811
|
CreateRouteTableCommand,
|
|
16794
16812
|
DeleteRouteTableCommand,
|
|
16795
16813
|
CreateRouteCommand,
|
|
@@ -16835,6 +16853,20 @@ var EC2Provider = class {
|
|
|
16835
16853
|
],
|
|
16836
16854
|
["AWS::EC2::InternetGateway", /* @__PURE__ */ new Set(["Tags"])],
|
|
16837
16855
|
["AWS::EC2::VPCGatewayAttachment", /* @__PURE__ */ new Set(["VpcId", "InternetGatewayId"])],
|
|
16856
|
+
[
|
|
16857
|
+
"AWS::EC2::NatGateway",
|
|
16858
|
+
/* @__PURE__ */ new Set([
|
|
16859
|
+
"AllocationId",
|
|
16860
|
+
"SubnetId",
|
|
16861
|
+
"ConnectivityType",
|
|
16862
|
+
"PrivateIpAddress",
|
|
16863
|
+
"SecondaryAllocationIds",
|
|
16864
|
+
"SecondaryPrivateIpAddresses",
|
|
16865
|
+
"SecondaryPrivateIpAddressCount",
|
|
16866
|
+
"MaxDrainDurationSeconds",
|
|
16867
|
+
"Tags"
|
|
16868
|
+
])
|
|
16869
|
+
],
|
|
16838
16870
|
["AWS::EC2::RouteTable", /* @__PURE__ */ new Set(["VpcId", "Tags"])],
|
|
16839
16871
|
[
|
|
16840
16872
|
"AWS::EC2::Route",
|
|
@@ -16922,6 +16954,8 @@ var EC2Provider = class {
|
|
|
16922
16954
|
return this.createInternetGateway(logicalId, resourceType, properties);
|
|
16923
16955
|
case "AWS::EC2::VPCGatewayAttachment":
|
|
16924
16956
|
return this.createVpcGatewayAttachment(logicalId, resourceType, properties);
|
|
16957
|
+
case "AWS::EC2::NatGateway":
|
|
16958
|
+
return this.createNatGateway(logicalId, resourceType, properties);
|
|
16925
16959
|
case "AWS::EC2::RouteTable":
|
|
16926
16960
|
return this.createRouteTable(logicalId, resourceType, properties);
|
|
16927
16961
|
case "AWS::EC2::Route":
|
|
@@ -16958,6 +16992,8 @@ var EC2Provider = class {
|
|
|
16958
16992
|
return this.updateInternetGateway(logicalId, physicalId);
|
|
16959
16993
|
case "AWS::EC2::VPCGatewayAttachment":
|
|
16960
16994
|
return this.updateVpcGatewayAttachment(logicalId, physicalId);
|
|
16995
|
+
case "AWS::EC2::NatGateway":
|
|
16996
|
+
return this.updateNatGateway(logicalId, physicalId);
|
|
16961
16997
|
case "AWS::EC2::RouteTable":
|
|
16962
16998
|
return this.updateRouteTable(logicalId, physicalId);
|
|
16963
16999
|
case "AWS::EC2::Route":
|
|
@@ -17011,6 +17047,8 @@ var EC2Provider = class {
|
|
|
17011
17047
|
return this.deleteInternetGateway(logicalId, physicalId, resourceType, context);
|
|
17012
17048
|
case "AWS::EC2::VPCGatewayAttachment":
|
|
17013
17049
|
return this.deleteVpcGatewayAttachment(logicalId, physicalId, resourceType, context);
|
|
17050
|
+
case "AWS::EC2::NatGateway":
|
|
17051
|
+
return this.deleteNatGateway(logicalId, physicalId, resourceType, context);
|
|
17014
17052
|
case "AWS::EC2::RouteTable":
|
|
17015
17053
|
return this.deleteRouteTable(logicalId, physicalId, resourceType, context);
|
|
17016
17054
|
case "AWS::EC2::Route":
|
|
@@ -17579,6 +17617,118 @@ var EC2Provider = class {
|
|
|
17579
17617
|
);
|
|
17580
17618
|
}
|
|
17581
17619
|
}
|
|
17620
|
+
// ─── AWS::EC2::NatGateway ─────────────────────────────────────────
|
|
17621
|
+
//
|
|
17622
|
+
// CloudFormation parity: by default we wait for the new NAT gateway to
|
|
17623
|
+
// reach `available` state before marking the resource created. NAT
|
|
17624
|
+
// provisioning takes ~1–2 minutes (often the longest single step in a
|
|
17625
|
+
// VPC stack). Pass `--no-wait` to skip the wait — `CreateNatGateway`
|
|
17626
|
+
// returns the `NatGatewayId` immediately so dependent Routes /
|
|
17627
|
+
// Subnets that only need the ID can proceed against a still-`pending`
|
|
17628
|
+
// gateway. Anything that requires actual NAT-routed egress (e.g. a
|
|
17629
|
+
// Lambda invocation that hits the internet during deploy) must not
|
|
17630
|
+
// rely on the gateway being live; with `--no-wait`, AWS continues
|
|
17631
|
+
// provisioning asynchronously after the deploy returns.
|
|
17632
|
+
async createNatGateway(logicalId, resourceType, properties) {
|
|
17633
|
+
this.logger.debug(`Creating NatGateway ${logicalId}`);
|
|
17634
|
+
const subnetId = properties["SubnetId"];
|
|
17635
|
+
if (!subnetId) {
|
|
17636
|
+
throw new ProvisioningError(
|
|
17637
|
+
`SubnetId is required for NatGateway ${logicalId}`,
|
|
17638
|
+
resourceType,
|
|
17639
|
+
logicalId
|
|
17640
|
+
);
|
|
17641
|
+
}
|
|
17642
|
+
try {
|
|
17643
|
+
const response = await this.ec2Client.send(
|
|
17644
|
+
new CreateNatGatewayCommand({
|
|
17645
|
+
SubnetId: subnetId,
|
|
17646
|
+
AllocationId: properties["AllocationId"],
|
|
17647
|
+
ConnectivityType: properties["ConnectivityType"] ?? void 0,
|
|
17648
|
+
PrivateIpAddress: properties["PrivateIpAddress"],
|
|
17649
|
+
SecondaryAllocationIds: properties["SecondaryAllocationIds"],
|
|
17650
|
+
SecondaryPrivateIpAddresses: properties["SecondaryPrivateIpAddresses"],
|
|
17651
|
+
SecondaryPrivateIpAddressCount: properties["SecondaryPrivateIpAddressCount"]
|
|
17652
|
+
})
|
|
17653
|
+
);
|
|
17654
|
+
const natGatewayId = response.NatGateway.NatGatewayId;
|
|
17655
|
+
await this.applyTags(natGatewayId, properties, logicalId);
|
|
17656
|
+
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
17657
|
+
this.logger.debug(`Waiting for NatGateway ${natGatewayId} to reach available state...`);
|
|
17658
|
+
await waitUntilNatGatewayAvailable(
|
|
17659
|
+
// 15-min cap matches AWS's documented worst case for NAT
|
|
17660
|
+
// provisioning. Per-resource `--resource-timeout` (default
|
|
17661
|
+
// 30 min) still bounds the outer call as a backstop.
|
|
17662
|
+
{ client: this.ec2Client, maxWaitTime: 15 * 60 },
|
|
17663
|
+
{ NatGatewayIds: [natGatewayId] }
|
|
17664
|
+
);
|
|
17665
|
+
this.logger.debug(`NatGateway ${natGatewayId} is available`);
|
|
17666
|
+
} else {
|
|
17667
|
+
this.logger.debug(
|
|
17668
|
+
`NatGateway ${natGatewayId} created (skipping available-state wait per --no-wait)`
|
|
17669
|
+
);
|
|
17670
|
+
}
|
|
17671
|
+
this.logger.debug(`Successfully created NatGateway ${logicalId}: ${natGatewayId}`);
|
|
17672
|
+
return {
|
|
17673
|
+
physicalId: natGatewayId,
|
|
17674
|
+
attributes: {
|
|
17675
|
+
NatGatewayId: natGatewayId
|
|
17676
|
+
}
|
|
17677
|
+
};
|
|
17678
|
+
} catch (error) {
|
|
17679
|
+
const cause = error instanceof Error ? error : void 0;
|
|
17680
|
+
throw new ProvisioningError(
|
|
17681
|
+
`Failed to create NatGateway ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
17682
|
+
resourceType,
|
|
17683
|
+
logicalId,
|
|
17684
|
+
void 0,
|
|
17685
|
+
cause
|
|
17686
|
+
);
|
|
17687
|
+
}
|
|
17688
|
+
}
|
|
17689
|
+
updateNatGateway(logicalId, physicalId) {
|
|
17690
|
+
this.logger.debug(`Updating NatGateway ${logicalId}: ${physicalId} (no-op)`);
|
|
17691
|
+
return Promise.resolve({ physicalId, wasReplaced: false });
|
|
17692
|
+
}
|
|
17693
|
+
async deleteNatGateway(logicalId, physicalId, resourceType, context) {
|
|
17694
|
+
this.logger.debug(`Deleting NatGateway ${logicalId}: ${physicalId}`);
|
|
17695
|
+
try {
|
|
17696
|
+
await this.ec2Client.send(new DeleteNatGatewayCommand({ NatGatewayId: physicalId }));
|
|
17697
|
+
} catch (error) {
|
|
17698
|
+
if (this.isNotFoundError(error)) {
|
|
17699
|
+
const clientRegion = await this.ec2Client.config.region();
|
|
17700
|
+
assertRegionMatch(
|
|
17701
|
+
clientRegion,
|
|
17702
|
+
context?.expectedRegion,
|
|
17703
|
+
resourceType,
|
|
17704
|
+
logicalId,
|
|
17705
|
+
physicalId
|
|
17706
|
+
);
|
|
17707
|
+
this.logger.debug(`NatGateway ${physicalId} does not exist, skipping deletion`);
|
|
17708
|
+
return;
|
|
17709
|
+
}
|
|
17710
|
+
const cause = error instanceof Error ? error : void 0;
|
|
17711
|
+
throw new ProvisioningError(
|
|
17712
|
+
`Failed to delete NatGateway ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
17713
|
+
resourceType,
|
|
17714
|
+
logicalId,
|
|
17715
|
+
physicalId,
|
|
17716
|
+
cause
|
|
17717
|
+
);
|
|
17718
|
+
}
|
|
17719
|
+
this.logger.debug(`Waiting for NatGateway ${physicalId} to reach deleted state...`);
|
|
17720
|
+
try {
|
|
17721
|
+
await waitUntilNatGatewayDeleted(
|
|
17722
|
+
{ client: this.ec2Client, maxWaitTime: 15 * 60 },
|
|
17723
|
+
{ NatGatewayIds: [physicalId] }
|
|
17724
|
+
);
|
|
17725
|
+
} catch (error) {
|
|
17726
|
+
this.logger.warn(
|
|
17727
|
+
`Wait for NatGateway ${physicalId} deletion did not complete cleanly: ${error instanceof Error ? error.message : String(error)} \u2014 proceeding with downstream delete steps`
|
|
17728
|
+
);
|
|
17729
|
+
}
|
|
17730
|
+
this.logger.debug(`Successfully deleted NatGateway ${logicalId}`);
|
|
17731
|
+
}
|
|
17582
17732
|
// ─── AWS::EC2::RouteTable ─────────────────────────────────────────
|
|
17583
17733
|
async createRouteTable(logicalId, resourceType, properties) {
|
|
17584
17734
|
this.logger.debug(`Creating RouteTable ${logicalId}`);
|
|
@@ -18788,6 +18938,15 @@ var EC2Provider = class {
|
|
|
18788
18938
|
const sg = resp.SecurityGroups?.[0];
|
|
18789
18939
|
return sg?.GroupId ? { physicalId: sg.GroupId, attributes: {} } : null;
|
|
18790
18940
|
}
|
|
18941
|
+
case "AWS::EC2::NatGateway": {
|
|
18942
|
+
const resp = await this.ec2Client.send(
|
|
18943
|
+
new DescribeNatGatewaysCommand({
|
|
18944
|
+
Filter: [{ Name: `tag:${CDK_PATH_TAG}`, Values: [input.cdkPath] }]
|
|
18945
|
+
})
|
|
18946
|
+
);
|
|
18947
|
+
const gw = resp.NatGateways?.find((g) => g.State !== "deleted" && g.State !== "deleting");
|
|
18948
|
+
return gw?.NatGatewayId ? { physicalId: gw.NatGatewayId, attributes: {} } : null;
|
|
18949
|
+
}
|
|
18791
18950
|
default:
|
|
18792
18951
|
return null;
|
|
18793
18952
|
}
|
|
@@ -18816,6 +18975,13 @@ var EC2Provider = class {
|
|
|
18816
18975
|
);
|
|
18817
18976
|
return resp.SecurityGroups?.[0] ? { physicalId, attributes: {} } : null;
|
|
18818
18977
|
}
|
|
18978
|
+
case "AWS::EC2::NatGateway": {
|
|
18979
|
+
const resp = await this.ec2Client.send(
|
|
18980
|
+
new DescribeNatGatewaysCommand({ NatGatewayIds: [physicalId] })
|
|
18981
|
+
);
|
|
18982
|
+
const gw = resp.NatGateways?.find((g) => g.State !== "deleted" && g.State !== "deleting");
|
|
18983
|
+
return gw ? { physicalId, attributes: {} } : null;
|
|
18984
|
+
}
|
|
18819
18985
|
default:
|
|
18820
18986
|
return null;
|
|
18821
18987
|
}
|
|
@@ -31139,6 +31305,7 @@ function registerAllProviders(registry) {
|
|
|
31139
31305
|
registry.register("AWS::EC2::Subnet", ec2Provider);
|
|
31140
31306
|
registry.register("AWS::EC2::InternetGateway", ec2Provider);
|
|
31141
31307
|
registry.register("AWS::EC2::VPCGatewayAttachment", ec2Provider);
|
|
31308
|
+
registry.register("AWS::EC2::NatGateway", ec2Provider);
|
|
31142
31309
|
registry.register("AWS::EC2::RouteTable", ec2Provider);
|
|
31143
31310
|
registry.register("AWS::EC2::Route", ec2Provider);
|
|
31144
31311
|
registry.register("AWS::EC2::SubnetRouteTableAssociation", ec2Provider);
|
|
@@ -33390,10 +33557,17 @@ Acquiring lock for stack ${stackName}...`);
|
|
|
33390
33557
|
} else {
|
|
33391
33558
|
logger.warn(`${result.errorCount} resource(s) failed to delete. State preserved.`);
|
|
33392
33559
|
}
|
|
33393
|
-
|
|
33394
|
-
|
|
33560
|
+
if (result.errorCount === 0) {
|
|
33561
|
+
logger.info(
|
|
33562
|
+
`
|
|
33395
33563
|
\u2713 Stack ${stackName} destroyed (${result.deletedCount} deleted, ${result.errorCount} errors)`
|
|
33396
|
-
|
|
33564
|
+
);
|
|
33565
|
+
} else {
|
|
33566
|
+
logger.warn(
|
|
33567
|
+
`
|
|
33568
|
+
\u26A0 Stack ${stackName} partially destroyed (${result.deletedCount} deleted, ${result.errorCount} errors). State preserved \u2014 re-run 'cdkd destroy' / 'cdkd state destroy' to clean up.`
|
|
33569
|
+
);
|
|
33570
|
+
}
|
|
33397
33571
|
} finally {
|
|
33398
33572
|
renderer.stop();
|
|
33399
33573
|
logger.debug("Releasing lock...");
|
|
@@ -33513,6 +33687,7 @@ async function destroyCommand(stackArgs, options) {
|
|
|
33513
33687
|
arr.push(ref);
|
|
33514
33688
|
stateRefsByName.set(ref.stackName, arr);
|
|
33515
33689
|
}
|
|
33690
|
+
let totalErrors = 0;
|
|
33516
33691
|
for (const stackName of stackNames) {
|
|
33517
33692
|
logger.info(`
|
|
33518
33693
|
Preparing to destroy stack: ${stackName}`);
|
|
@@ -33543,7 +33718,7 @@ Preparing to destroy stack: ${stackName}`);
|
|
|
33543
33718
|
logger.warn(`No state found for stack ${stackName}, skipping`);
|
|
33544
33719
|
continue;
|
|
33545
33720
|
}
|
|
33546
|
-
await runDestroyForStack(stackName, stateResult.state, {
|
|
33721
|
+
const result = await runDestroyForStack(stackName, stateResult.state, {
|
|
33547
33722
|
stateBackend,
|
|
33548
33723
|
lockManager,
|
|
33549
33724
|
providerRegistry,
|
|
@@ -33565,6 +33740,12 @@ Preparing to destroy stack: ${stackName}`);
|
|
|
33565
33740
|
resourceTimeoutByType: options.resourceTimeout.perTypeMs
|
|
33566
33741
|
}
|
|
33567
33742
|
});
|
|
33743
|
+
totalErrors += result.errorCount;
|
|
33744
|
+
}
|
|
33745
|
+
if (totalErrors > 0) {
|
|
33746
|
+
throw new PartialFailureError(
|
|
33747
|
+
`Destroy completed with ${totalErrors} resource error(s). State preserved \u2014 inspect 'cdkd state show <stack>' and re-run 'cdkd destroy' to retry.`
|
|
33748
|
+
);
|
|
33568
33749
|
}
|
|
33569
33750
|
} finally {
|
|
33570
33751
|
awsClients.destroy();
|
|
@@ -35262,8 +35443,8 @@ Preparing to destroy stack: ${stackName}${ref.region ? ` (${ref.region})` : ""}`
|
|
|
35262
35443
|
}
|
|
35263
35444
|
}
|
|
35264
35445
|
if (totalErrors > 0) {
|
|
35265
|
-
throw new
|
|
35266
|
-
`Destroy completed with ${totalErrors} resource error(s).
|
|
35446
|
+
throw new PartialFailureError(
|
|
35447
|
+
`Destroy completed with ${totalErrors} resource error(s). State preserved \u2014 inspect 'cdkd state show <stack>' and re-run 'cdkd state destroy' to retry.`
|
|
35267
35448
|
);
|
|
35268
35449
|
}
|
|
35269
35450
|
} finally {
|
|
@@ -36172,7 +36353,7 @@ function reorderArgs(argv) {
|
|
|
36172
36353
|
}
|
|
36173
36354
|
async function main() {
|
|
36174
36355
|
const program = new Command13();
|
|
36175
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
36356
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.31.1");
|
|
36176
36357
|
program.addCommand(createBootstrapCommand());
|
|
36177
36358
|
program.addCommand(createSynthCommand());
|
|
36178
36359
|
program.addCommand(createListCommand());
|