@go-to-k/cdkd 0.60.1 → 0.60.2
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 +105 -8
- package/dist/cli.js.map +2 -2
- package/dist/go-to-k-cdkd-0.60.2.tgz +0 -0
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.60.1.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -22162,8 +22162,9 @@ var EC2Provider = class {
|
|
|
22162
22162
|
async deleteInternetGateway(logicalId, physicalId, resourceType, context) {
|
|
22163
22163
|
this.logger.debug(`Deleting InternetGateway ${logicalId}: ${physicalId}`);
|
|
22164
22164
|
try {
|
|
22165
|
-
await this.
|
|
22166
|
-
new DeleteInternetGatewayCommand({ InternetGatewayId: physicalId })
|
|
22165
|
+
await this.withDependencyViolationRetry(
|
|
22166
|
+
() => this.ec2Client.send(new DeleteInternetGatewayCommand({ InternetGatewayId: physicalId })),
|
|
22167
|
+
{ description: `DeleteInternetGateway ${logicalId} (${physicalId})` }
|
|
22167
22168
|
);
|
|
22168
22169
|
this.logger.debug(`Successfully deleted InternetGateway ${logicalId}`);
|
|
22169
22170
|
} catch (error) {
|
|
@@ -22247,11 +22248,14 @@ var EC2Provider = class {
|
|
|
22247
22248
|
}
|
|
22248
22249
|
const [internetGatewayId, vpcId] = parts;
|
|
22249
22250
|
try {
|
|
22250
|
-
await this.
|
|
22251
|
-
|
|
22252
|
-
|
|
22253
|
-
|
|
22254
|
-
|
|
22251
|
+
await this.withDependencyViolationRetry(
|
|
22252
|
+
() => this.ec2Client.send(
|
|
22253
|
+
new DetachInternetGatewayCommand({
|
|
22254
|
+
InternetGatewayId: internetGatewayId,
|
|
22255
|
+
VpcId: vpcId
|
|
22256
|
+
})
|
|
22257
|
+
),
|
|
22258
|
+
{ description: `DetachInternetGateway ${logicalId} (${internetGatewayId} from ${vpcId})` }
|
|
22255
22259
|
);
|
|
22256
22260
|
this.logger.debug(`Successfully deleted VPCGatewayAttachment ${logicalId}`);
|
|
22257
22261
|
} catch (error) {
|
|
@@ -23653,6 +23657,99 @@ var EC2Provider = class {
|
|
|
23653
23657
|
}
|
|
23654
23658
|
}
|
|
23655
23659
|
}
|
|
23660
|
+
/**
|
|
23661
|
+
* Retry an operation that AWS may reject with `DependencyViolation`
|
|
23662
|
+
* for an extended window — specifically `DeleteInternetGateway` and
|
|
23663
|
+
* `DetachInternetGateway` after a sibling EC2 Instance with an
|
|
23664
|
+
* auto-assigned public IP was terminated. AWS releases the public-IP
|
|
23665
|
+
* → IGW mapping asynchronously (5–10 min lag observed in practice);
|
|
23666
|
+
* during that window AWS rejects IGW-detach / -delete with
|
|
23667
|
+
* `DependencyViolation: Network has some mapped public address(es).
|
|
23668
|
+
* Please unmap those public address(es) before detaching the gateway.`
|
|
23669
|
+
* (or similar `has dependencies and cannot be deleted`).
|
|
23670
|
+
*
|
|
23671
|
+
* cdkd's deploy-engine `withRetry` wrapper caps at ~1 min total
|
|
23672
|
+
* (1s/2s/4s/8s × 10 attempts capped at 8s), and the destroy-runner's
|
|
23673
|
+
* inner 3-attempt loop adds ~35s on top — neither is enough for
|
|
23674
|
+
* AWS's 5–10 min release window. This helper extends the budget to
|
|
23675
|
+
* 10 min for the IGW-specific case so `cdkd destroy
|
|
23676
|
+
* --remove-protection` is self-healing on the public-IP release lag
|
|
23677
|
+
* without operator intervention.
|
|
23678
|
+
*
|
|
23679
|
+
* Modeled on the Lambda hyperplane ENI cleanup pattern (~30 min
|
|
23680
|
+
* budget) and the EC2 Subnet/SG side-channel ENI retry — both wait
|
|
23681
|
+
* on AWS-side eventual-consistency that the standard `withRetry`
|
|
23682
|
+
* budget cannot cover.
|
|
23683
|
+
*
|
|
23684
|
+
* Only `DependencyViolation` errors are retried; other errors
|
|
23685
|
+
* (NotFound, AccessDenied, throttle, etc.) propagate immediately so
|
|
23686
|
+
* the caller's existing error handling is unchanged.
|
|
23687
|
+
*
|
|
23688
|
+
* Note on retry layering: `DependencyViolation` is also in
|
|
23689
|
+
* `RETRYABLE_ERROR_MESSAGE_PATTERNS` (consumed by `withRetry`) and
|
|
23690
|
+
* the destroy-runner's inner 3-attempt loop also matches it. After
|
|
23691
|
+
* this helper's budget exhausts and re-throws, those outer retry
|
|
23692
|
+
* loops will see the error and try a few more times — adding at
|
|
23693
|
+
* most ~1 min on top of the 10 min budget, still bounded by the
|
|
23694
|
+
* per-resource `--resource-timeout` deadline (default 30 min).
|
|
23695
|
+
* That extra is harmless (worst case slightly later failure surface)
|
|
23696
|
+
* and avoids threading a per-error-class "already exhausted" flag
|
|
23697
|
+
* through every retry layer.
|
|
23698
|
+
*/
|
|
23699
|
+
async withDependencyViolationRetry(operation, opts) {
|
|
23700
|
+
const totalBudgetMs = opts.totalBudgetMs ?? 6e5;
|
|
23701
|
+
const initialDelayMs = 5e3;
|
|
23702
|
+
const maxDelayMs = 6e4;
|
|
23703
|
+
const startedAt = Date.now();
|
|
23704
|
+
let attempt = 0;
|
|
23705
|
+
let delay = initialDelayMs;
|
|
23706
|
+
while (true) {
|
|
23707
|
+
try {
|
|
23708
|
+
return await operation();
|
|
23709
|
+
} catch (error) {
|
|
23710
|
+
if (!this.isDependencyViolationError(error)) {
|
|
23711
|
+
throw error;
|
|
23712
|
+
}
|
|
23713
|
+
const elapsed = Date.now() - startedAt;
|
|
23714
|
+
if (elapsed >= totalBudgetMs) {
|
|
23715
|
+
throw error;
|
|
23716
|
+
}
|
|
23717
|
+
attempt += 1;
|
|
23718
|
+
const sleepMs = Math.min(delay, totalBudgetMs - elapsed);
|
|
23719
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
23720
|
+
this.logger.debug(
|
|
23721
|
+
`${opts.description}: dependency still mapped (attempt ${attempt}, retrying in ${sleepMs}ms): ${message}`
|
|
23722
|
+
);
|
|
23723
|
+
await this.sleep(sleepMs);
|
|
23724
|
+
delay = Math.min(delay * 2, maxDelayMs);
|
|
23725
|
+
}
|
|
23726
|
+
}
|
|
23727
|
+
}
|
|
23728
|
+
/**
|
|
23729
|
+
* Match an AWS `DependencyViolation` error by error code or message.
|
|
23730
|
+
* AWS surfaces this as `Code: 'DependencyViolation'` in the parsed SDK
|
|
23731
|
+
* error, with a human message like `The internetGateway 'igw-xxx' has
|
|
23732
|
+
* dependencies and cannot be deleted.` or `Network has some mapped
|
|
23733
|
+
* public address(es). Please unmap those public address(es)`.
|
|
23734
|
+
*/
|
|
23735
|
+
isDependencyViolationError(error) {
|
|
23736
|
+
if (!(error instanceof Error))
|
|
23737
|
+
return false;
|
|
23738
|
+
const code = error.Code ?? "";
|
|
23739
|
+
const name = error.name ?? "";
|
|
23740
|
+
if (code === "DependencyViolation" || name === "DependencyViolation")
|
|
23741
|
+
return true;
|
|
23742
|
+
const message = error.message ?? "";
|
|
23743
|
+
return message.includes("DependencyViolation") || message.includes("has dependencies and cannot be deleted") || message.includes("Network has some mapped public address");
|
|
23744
|
+
}
|
|
23745
|
+
/**
|
|
23746
|
+
* Indirect sleep so unit tests can swap in a fake-timer-aware
|
|
23747
|
+
* implementation via `vi.useFakeTimers()` without monkey-patching
|
|
23748
|
+
* `setTimeout` globally.
|
|
23749
|
+
*/
|
|
23750
|
+
sleep(ms) {
|
|
23751
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
23752
|
+
}
|
|
23656
23753
|
/**
|
|
23657
23754
|
* Check if an error indicates the resource was not found
|
|
23658
23755
|
*/
|
|
@@ -49246,7 +49343,7 @@ function reorderArgs(argv) {
|
|
|
49246
49343
|
}
|
|
49247
49344
|
async function main() {
|
|
49248
49345
|
const program = new Command14();
|
|
49249
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.60.
|
|
49346
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.60.2");
|
|
49250
49347
|
program.addCommand(createBootstrapCommand());
|
|
49251
49348
|
program.addCommand(createSynthCommand());
|
|
49252
49349
|
program.addCommand(createListCommand());
|