@go-to-k/cdkd 0.30.1 → 0.31.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/README.md +25 -6
- package/dist/cli.js +238 -47
- package/dist/cli.js.map +3 -3
- package/dist/go-to-k-cdkd-0.31.0.tgz +0 -0
- package/dist/index.js +50 -1
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.30.1.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`,
|
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"
|
|
@@ -7506,7 +7510,11 @@ Error: ${err.message || "Unknown error"}`,
|
|
|
7506
7510
|
};
|
|
7507
7511
|
|
|
7508
7512
|
// src/provisioning/providers/custom-resource-provider.ts
|
|
7509
|
-
import {
|
|
7513
|
+
import {
|
|
7514
|
+
InvokeCommand,
|
|
7515
|
+
waitUntilFunctionActiveV2,
|
|
7516
|
+
waitUntilFunctionUpdatedV2
|
|
7517
|
+
} from "@aws-sdk/client-lambda";
|
|
7510
7518
|
import { PublishCommand } from "@aws-sdk/client-sns";
|
|
7511
7519
|
import {
|
|
7512
7520
|
S3Client as S3Client6,
|
|
@@ -7790,9 +7798,54 @@ var CustomResourceProvider = class _CustomResourceProvider {
|
|
|
7790
7798
|
await this.publishToSns(serviceToken, request);
|
|
7791
7799
|
return await this.pollS3Response(responseKey, logicalId, operation);
|
|
7792
7800
|
}
|
|
7801
|
+
await this.waitForBackingLambdaReady(serviceToken, logicalId);
|
|
7793
7802
|
const response = await this.invokeLambda(serviceToken, request);
|
|
7794
7803
|
return await this.getCustomResourceResponse(response, responseKey, logicalId, operation);
|
|
7795
7804
|
}
|
|
7805
|
+
/**
|
|
7806
|
+
* Block until the backing Lambda function for a Custom Resource is in a
|
|
7807
|
+
* state that accepts a synchronous Invoke.
|
|
7808
|
+
*
|
|
7809
|
+
* Two sequential waiters:
|
|
7810
|
+
* 1. `waitUntilFunctionActiveV2` — handles the post-CreateFunction
|
|
7811
|
+
* `Pending` window (image pull, VPC ENI attachment, layer init).
|
|
7812
|
+
* 2. `waitUntilFunctionUpdatedV2` — handles the post-Update
|
|
7813
|
+
* `InProgress` window (configuration / code swap settling).
|
|
7814
|
+
* Together they cover the only two transient states that reject
|
|
7815
|
+
* synchronous Invokes.
|
|
7816
|
+
*
|
|
7817
|
+
* In the common case (Lambda has been Active for a while, no in-flight
|
|
7818
|
+
* Update), both waiters return on first poll → ~2 GetFunction calls →
|
|
7819
|
+
* ~200ms overhead. That's the price for correctness; the alternative
|
|
7820
|
+
* (whole-stack Active wait at Lambda CREATE) is ~5–10 minutes per
|
|
7821
|
+
* VPC-attached function.
|
|
7822
|
+
*
|
|
7823
|
+
* `serviceToken` is the Lambda function ARN; the Lambda SDK accepts
|
|
7824
|
+
* both name and ARN as `FunctionName`, so we pass the ARN through
|
|
7825
|
+
* unchanged.
|
|
7826
|
+
*
|
|
7827
|
+
* `maxWaitTime` is set generously (10 min) because VPC ENI attachment
|
|
7828
|
+
* has been observed to take 8+ minutes in pathological cases. The
|
|
7829
|
+
* deploy engine's per-resource `--resource-timeout` (default 30 min)
|
|
7830
|
+
* still bounds the outer Custom Resource provisioning attempt, so
|
|
7831
|
+
* this waiter cap is layered defense, not the only timeout.
|
|
7832
|
+
*/
|
|
7833
|
+
async waitForBackingLambdaReady(serviceToken, logicalId) {
|
|
7834
|
+
try {
|
|
7835
|
+
await waitUntilFunctionActiveV2(
|
|
7836
|
+
{ client: this.lambdaClient, maxWaitTime: 600 },
|
|
7837
|
+
{ FunctionName: serviceToken }
|
|
7838
|
+
);
|
|
7839
|
+
await waitUntilFunctionUpdatedV2(
|
|
7840
|
+
{ client: this.lambdaClient, maxWaitTime: 600 },
|
|
7841
|
+
{ FunctionName: serviceToken }
|
|
7842
|
+
);
|
|
7843
|
+
} catch (error) {
|
|
7844
|
+
throw new Error(
|
|
7845
|
+
`Lambda backing custom resource ${logicalId} (${serviceToken}) did not reach a ready state for Invoke: ${error instanceof Error ? error.message : String(error)}`
|
|
7846
|
+
);
|
|
7847
|
+
}
|
|
7848
|
+
}
|
|
7796
7849
|
/**
|
|
7797
7850
|
* Publish custom resource request to an SNS topic
|
|
7798
7851
|
*/
|
|
@@ -12967,8 +13020,7 @@ import {
|
|
|
12967
13020
|
ListFunctionsCommand,
|
|
12968
13021
|
ListTagsCommand,
|
|
12969
13022
|
ResourceNotFoundException,
|
|
12970
|
-
|
|
12971
|
-
waitUntilFunctionUpdatedV2
|
|
13023
|
+
waitUntilFunctionUpdatedV2 as waitUntilFunctionUpdatedV22
|
|
12972
13024
|
} from "@aws-sdk/client-lambda";
|
|
12973
13025
|
import {
|
|
12974
13026
|
DescribeNetworkInterfacesCommand,
|
|
@@ -13011,14 +13063,20 @@ var LambdaFunctionProvider = class {
|
|
|
13011
13063
|
eniWaitTimeoutMs = 10 * 60 * 1e3;
|
|
13012
13064
|
eniWaitInitialDelayMs = 1e4;
|
|
13013
13065
|
eniWaitMaxDelayMs = 3e4;
|
|
13014
|
-
// Budget for the post-
|
|
13015
|
-
//
|
|
13016
|
-
//
|
|
13017
|
-
//
|
|
13018
|
-
//
|
|
13019
|
-
//
|
|
13066
|
+
// Budget for the post-Update wait that blocks until LastUpdateStatus
|
|
13067
|
+
// === 'Successful'. Required to prevent the SECOND in-flight call (e.g.
|
|
13068
|
+
// UpdateFunctionCode immediately after UpdateFunctionConfiguration)
|
|
13069
|
+
// from racing the first with "function is currently in the following
|
|
13070
|
+
// state: InProgress". Update typically settles in seconds; the 10-min
|
|
13071
|
+
// cap is generous slack for layer-update / VPC-detach edge cases.
|
|
13020
13072
|
// Seconds (the SDK waiter contract is seconds, not ms).
|
|
13021
|
-
|
|
13073
|
+
//
|
|
13074
|
+
// The post-CreateFunction `State=Active` wait used to live here too
|
|
13075
|
+
// (PR #121) but doubled deploy time on benchmark stacks because every
|
|
13076
|
+
// Lambda paid the cost regardless of whether anything synchronously
|
|
13077
|
+
// invoked it. The Active wait now lives in `CustomResourceProvider`
|
|
13078
|
+
// (the only deploy-time consumer that breaks against Pending).
|
|
13079
|
+
functionUpdateMaxWaitSeconds = 10 * 60;
|
|
13022
13080
|
// delstack-style ENI cleanup tunables.
|
|
13023
13081
|
// - initial sleep: gives AWS time to publish post-detach ENI state via
|
|
13024
13082
|
// DescribeNetworkInterfaces (right after the update, the API can return
|
|
@@ -13087,7 +13145,6 @@ var LambdaFunctionProvider = class {
|
|
|
13087
13145
|
Tags: tags
|
|
13088
13146
|
};
|
|
13089
13147
|
const response = await this.lambdaClient.send(new CreateFunctionCommand(createParams));
|
|
13090
|
-
await this.waitForFunctionActive(logicalId, resourceType, functionName);
|
|
13091
13148
|
this.logger.debug(`Successfully created Lambda function ${logicalId}: ${functionName}`);
|
|
13092
13149
|
return {
|
|
13093
13150
|
physicalId: response.FunctionName || functionName,
|
|
@@ -13097,9 +13154,6 @@ var LambdaFunctionProvider = class {
|
|
|
13097
13154
|
}
|
|
13098
13155
|
};
|
|
13099
13156
|
} catch (error) {
|
|
13100
|
-
if (error instanceof ProvisioningError) {
|
|
13101
|
-
throw error;
|
|
13102
|
-
}
|
|
13103
13157
|
const cause = error instanceof Error ? error : void 0;
|
|
13104
13158
|
throw new ProvisioningError(
|
|
13105
13159
|
`Failed to create Lambda function ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -13355,45 +13409,28 @@ var LambdaFunctionProvider = class {
|
|
|
13355
13409
|
* Timeout is a soft warning — downstream Subnet/SG deletion has its own
|
|
13356
13410
|
* retries.
|
|
13357
13411
|
*/
|
|
13358
|
-
/**
|
|
13359
|
-
* Block until the function's State === 'Active'.
|
|
13360
|
-
*
|
|
13361
|
-
* Used after CreateFunction. Wraps the SDK's built-in
|
|
13362
|
-
* `waitUntilFunctionActiveV2` (acceptors: SUCCESS=Active, FAILURE=Failed,
|
|
13363
|
-
* RETRY=Pending). The waiter throws on FAILURE / TIMEOUT — both surface
|
|
13364
|
-
* as `ProvisioningError` with the function-name as physicalId so the
|
|
13365
|
-
* deploy engine's per-resource error handling treats them identically to
|
|
13366
|
-
* a CreateFunction failure.
|
|
13367
|
-
*/
|
|
13368
|
-
async waitForFunctionActive(logicalId, resourceType, functionName) {
|
|
13369
|
-
try {
|
|
13370
|
-
await waitUntilFunctionActiveV2(
|
|
13371
|
-
{ client: this.lambdaClient, maxWaitTime: this.functionReadyMaxWaitSeconds },
|
|
13372
|
-
{ FunctionName: functionName }
|
|
13373
|
-
);
|
|
13374
|
-
} catch (error) {
|
|
13375
|
-
const cause = error instanceof Error ? error : void 0;
|
|
13376
|
-
throw new ProvisioningError(
|
|
13377
|
-
`Lambda function ${logicalId} did not reach Active state: ${error instanceof Error ? error.message : String(error)}`,
|
|
13378
|
-
resourceType,
|
|
13379
|
-
logicalId,
|
|
13380
|
-
functionName,
|
|
13381
|
-
cause
|
|
13382
|
-
);
|
|
13383
|
-
}
|
|
13384
|
-
}
|
|
13385
13412
|
/**
|
|
13386
13413
|
* Block until the function's LastUpdateStatus === 'Successful'.
|
|
13387
13414
|
*
|
|
13388
13415
|
* Used after UpdateFunctionConfiguration / UpdateFunctionCode. Wraps the
|
|
13389
13416
|
* SDK's `waitUntilFunctionUpdatedV2` (acceptors: SUCCESS=Successful,
|
|
13390
|
-
* FAILURE=Failed, RETRY=InProgress).
|
|
13391
|
-
* `
|
|
13417
|
+
* FAILURE=Failed, RETRY=InProgress). Errors are surfaced as
|
|
13418
|
+
* `ProvisioningError` so the deploy engine's per-resource error
|
|
13419
|
+
* handling treats them identically to an Update API failure.
|
|
13420
|
+
*
|
|
13421
|
+
* NOTE: post-CreateFunction `State=Active` wait was deliberately moved
|
|
13422
|
+
* out of this provider in favor of an on-demand wait inside
|
|
13423
|
+
* `CustomResourceProvider.sendRequest` (the only deploy-time consumer
|
|
13424
|
+
* that breaks against a Pending Lambda). Blocking the entire deploy
|
|
13425
|
+
* DAG behind every Lambda's Active transition more than doubled
|
|
13426
|
+
* deploy time on benchmark stacks; the on-demand wait scoped to the
|
|
13427
|
+
* one resource type that actually needs it preserves the bug fix
|
|
13428
|
+
* without paying the whole-stack tax.
|
|
13392
13429
|
*/
|
|
13393
13430
|
async waitForFunctionUpdated(logicalId, resourceType, functionName) {
|
|
13394
13431
|
try {
|
|
13395
|
-
await
|
|
13396
|
-
{ client: this.lambdaClient, maxWaitTime: this.
|
|
13432
|
+
await waitUntilFunctionUpdatedV22(
|
|
13433
|
+
{ client: this.lambdaClient, maxWaitTime: this.functionUpdateMaxWaitSeconds },
|
|
13397
13434
|
{ FunctionName: functionName }
|
|
13398
13435
|
);
|
|
13399
13436
|
} catch (error) {
|
|
@@ -16757,6 +16794,11 @@ import {
|
|
|
16757
16794
|
DeleteInternetGatewayCommand,
|
|
16758
16795
|
AttachInternetGatewayCommand,
|
|
16759
16796
|
DetachInternetGatewayCommand,
|
|
16797
|
+
CreateNatGatewayCommand,
|
|
16798
|
+
DeleteNatGatewayCommand,
|
|
16799
|
+
DescribeNatGatewaysCommand,
|
|
16800
|
+
waitUntilNatGatewayAvailable,
|
|
16801
|
+
waitUntilNatGatewayDeleted,
|
|
16760
16802
|
CreateRouteTableCommand,
|
|
16761
16803
|
DeleteRouteTableCommand,
|
|
16762
16804
|
CreateRouteCommand,
|
|
@@ -16802,6 +16844,20 @@ var EC2Provider = class {
|
|
|
16802
16844
|
],
|
|
16803
16845
|
["AWS::EC2::InternetGateway", /* @__PURE__ */ new Set(["Tags"])],
|
|
16804
16846
|
["AWS::EC2::VPCGatewayAttachment", /* @__PURE__ */ new Set(["VpcId", "InternetGatewayId"])],
|
|
16847
|
+
[
|
|
16848
|
+
"AWS::EC2::NatGateway",
|
|
16849
|
+
/* @__PURE__ */ new Set([
|
|
16850
|
+
"AllocationId",
|
|
16851
|
+
"SubnetId",
|
|
16852
|
+
"ConnectivityType",
|
|
16853
|
+
"PrivateIpAddress",
|
|
16854
|
+
"SecondaryAllocationIds",
|
|
16855
|
+
"SecondaryPrivateIpAddresses",
|
|
16856
|
+
"SecondaryPrivateIpAddressCount",
|
|
16857
|
+
"MaxDrainDurationSeconds",
|
|
16858
|
+
"Tags"
|
|
16859
|
+
])
|
|
16860
|
+
],
|
|
16805
16861
|
["AWS::EC2::RouteTable", /* @__PURE__ */ new Set(["VpcId", "Tags"])],
|
|
16806
16862
|
[
|
|
16807
16863
|
"AWS::EC2::Route",
|
|
@@ -16889,6 +16945,8 @@ var EC2Provider = class {
|
|
|
16889
16945
|
return this.createInternetGateway(logicalId, resourceType, properties);
|
|
16890
16946
|
case "AWS::EC2::VPCGatewayAttachment":
|
|
16891
16947
|
return this.createVpcGatewayAttachment(logicalId, resourceType, properties);
|
|
16948
|
+
case "AWS::EC2::NatGateway":
|
|
16949
|
+
return this.createNatGateway(logicalId, resourceType, properties);
|
|
16892
16950
|
case "AWS::EC2::RouteTable":
|
|
16893
16951
|
return this.createRouteTable(logicalId, resourceType, properties);
|
|
16894
16952
|
case "AWS::EC2::Route":
|
|
@@ -16925,6 +16983,8 @@ var EC2Provider = class {
|
|
|
16925
16983
|
return this.updateInternetGateway(logicalId, physicalId);
|
|
16926
16984
|
case "AWS::EC2::VPCGatewayAttachment":
|
|
16927
16985
|
return this.updateVpcGatewayAttachment(logicalId, physicalId);
|
|
16986
|
+
case "AWS::EC2::NatGateway":
|
|
16987
|
+
return this.updateNatGateway(logicalId, physicalId);
|
|
16928
16988
|
case "AWS::EC2::RouteTable":
|
|
16929
16989
|
return this.updateRouteTable(logicalId, physicalId);
|
|
16930
16990
|
case "AWS::EC2::Route":
|
|
@@ -16978,6 +17038,8 @@ var EC2Provider = class {
|
|
|
16978
17038
|
return this.deleteInternetGateway(logicalId, physicalId, resourceType, context);
|
|
16979
17039
|
case "AWS::EC2::VPCGatewayAttachment":
|
|
16980
17040
|
return this.deleteVpcGatewayAttachment(logicalId, physicalId, resourceType, context);
|
|
17041
|
+
case "AWS::EC2::NatGateway":
|
|
17042
|
+
return this.deleteNatGateway(logicalId, physicalId, resourceType, context);
|
|
16981
17043
|
case "AWS::EC2::RouteTable":
|
|
16982
17044
|
return this.deleteRouteTable(logicalId, physicalId, resourceType, context);
|
|
16983
17045
|
case "AWS::EC2::Route":
|
|
@@ -17546,6 +17608,118 @@ var EC2Provider = class {
|
|
|
17546
17608
|
);
|
|
17547
17609
|
}
|
|
17548
17610
|
}
|
|
17611
|
+
// ─── AWS::EC2::NatGateway ─────────────────────────────────────────
|
|
17612
|
+
//
|
|
17613
|
+
// CloudFormation parity: by default we wait for the new NAT gateway to
|
|
17614
|
+
// reach `available` state before marking the resource created. NAT
|
|
17615
|
+
// provisioning takes ~1–2 minutes (often the longest single step in a
|
|
17616
|
+
// VPC stack). Pass `--no-wait` to skip the wait — `CreateNatGateway`
|
|
17617
|
+
// returns the `NatGatewayId` immediately so dependent Routes /
|
|
17618
|
+
// Subnets that only need the ID can proceed against a still-`pending`
|
|
17619
|
+
// gateway. Anything that requires actual NAT-routed egress (e.g. a
|
|
17620
|
+
// Lambda invocation that hits the internet during deploy) must not
|
|
17621
|
+
// rely on the gateway being live; with `--no-wait`, AWS continues
|
|
17622
|
+
// provisioning asynchronously after the deploy returns.
|
|
17623
|
+
async createNatGateway(logicalId, resourceType, properties) {
|
|
17624
|
+
this.logger.debug(`Creating NatGateway ${logicalId}`);
|
|
17625
|
+
const subnetId = properties["SubnetId"];
|
|
17626
|
+
if (!subnetId) {
|
|
17627
|
+
throw new ProvisioningError(
|
|
17628
|
+
`SubnetId is required for NatGateway ${logicalId}`,
|
|
17629
|
+
resourceType,
|
|
17630
|
+
logicalId
|
|
17631
|
+
);
|
|
17632
|
+
}
|
|
17633
|
+
try {
|
|
17634
|
+
const response = await this.ec2Client.send(
|
|
17635
|
+
new CreateNatGatewayCommand({
|
|
17636
|
+
SubnetId: subnetId,
|
|
17637
|
+
AllocationId: properties["AllocationId"],
|
|
17638
|
+
ConnectivityType: properties["ConnectivityType"] ?? void 0,
|
|
17639
|
+
PrivateIpAddress: properties["PrivateIpAddress"],
|
|
17640
|
+
SecondaryAllocationIds: properties["SecondaryAllocationIds"],
|
|
17641
|
+
SecondaryPrivateIpAddresses: properties["SecondaryPrivateIpAddresses"],
|
|
17642
|
+
SecondaryPrivateIpAddressCount: properties["SecondaryPrivateIpAddressCount"]
|
|
17643
|
+
})
|
|
17644
|
+
);
|
|
17645
|
+
const natGatewayId = response.NatGateway.NatGatewayId;
|
|
17646
|
+
await this.applyTags(natGatewayId, properties, logicalId);
|
|
17647
|
+
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
17648
|
+
this.logger.debug(`Waiting for NatGateway ${natGatewayId} to reach available state...`);
|
|
17649
|
+
await waitUntilNatGatewayAvailable(
|
|
17650
|
+
// 15-min cap matches AWS's documented worst case for NAT
|
|
17651
|
+
// provisioning. Per-resource `--resource-timeout` (default
|
|
17652
|
+
// 30 min) still bounds the outer call as a backstop.
|
|
17653
|
+
{ client: this.ec2Client, maxWaitTime: 15 * 60 },
|
|
17654
|
+
{ NatGatewayIds: [natGatewayId] }
|
|
17655
|
+
);
|
|
17656
|
+
this.logger.debug(`NatGateway ${natGatewayId} is available`);
|
|
17657
|
+
} else {
|
|
17658
|
+
this.logger.debug(
|
|
17659
|
+
`NatGateway ${natGatewayId} created (skipping available-state wait per --no-wait)`
|
|
17660
|
+
);
|
|
17661
|
+
}
|
|
17662
|
+
this.logger.debug(`Successfully created NatGateway ${logicalId}: ${natGatewayId}`);
|
|
17663
|
+
return {
|
|
17664
|
+
physicalId: natGatewayId,
|
|
17665
|
+
attributes: {
|
|
17666
|
+
NatGatewayId: natGatewayId
|
|
17667
|
+
}
|
|
17668
|
+
};
|
|
17669
|
+
} catch (error) {
|
|
17670
|
+
const cause = error instanceof Error ? error : void 0;
|
|
17671
|
+
throw new ProvisioningError(
|
|
17672
|
+
`Failed to create NatGateway ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
17673
|
+
resourceType,
|
|
17674
|
+
logicalId,
|
|
17675
|
+
void 0,
|
|
17676
|
+
cause
|
|
17677
|
+
);
|
|
17678
|
+
}
|
|
17679
|
+
}
|
|
17680
|
+
updateNatGateway(logicalId, physicalId) {
|
|
17681
|
+
this.logger.debug(`Updating NatGateway ${logicalId}: ${physicalId} (no-op)`);
|
|
17682
|
+
return Promise.resolve({ physicalId, wasReplaced: false });
|
|
17683
|
+
}
|
|
17684
|
+
async deleteNatGateway(logicalId, physicalId, resourceType, context) {
|
|
17685
|
+
this.logger.debug(`Deleting NatGateway ${logicalId}: ${physicalId}`);
|
|
17686
|
+
try {
|
|
17687
|
+
await this.ec2Client.send(new DeleteNatGatewayCommand({ NatGatewayId: physicalId }));
|
|
17688
|
+
} catch (error) {
|
|
17689
|
+
if (this.isNotFoundError(error)) {
|
|
17690
|
+
const clientRegion = await this.ec2Client.config.region();
|
|
17691
|
+
assertRegionMatch(
|
|
17692
|
+
clientRegion,
|
|
17693
|
+
context?.expectedRegion,
|
|
17694
|
+
resourceType,
|
|
17695
|
+
logicalId,
|
|
17696
|
+
physicalId
|
|
17697
|
+
);
|
|
17698
|
+
this.logger.debug(`NatGateway ${physicalId} does not exist, skipping deletion`);
|
|
17699
|
+
return;
|
|
17700
|
+
}
|
|
17701
|
+
const cause = error instanceof Error ? error : void 0;
|
|
17702
|
+
throw new ProvisioningError(
|
|
17703
|
+
`Failed to delete NatGateway ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
17704
|
+
resourceType,
|
|
17705
|
+
logicalId,
|
|
17706
|
+
physicalId,
|
|
17707
|
+
cause
|
|
17708
|
+
);
|
|
17709
|
+
}
|
|
17710
|
+
this.logger.debug(`Waiting for NatGateway ${physicalId} to reach deleted state...`);
|
|
17711
|
+
try {
|
|
17712
|
+
await waitUntilNatGatewayDeleted(
|
|
17713
|
+
{ client: this.ec2Client, maxWaitTime: 15 * 60 },
|
|
17714
|
+
{ NatGatewayIds: [physicalId] }
|
|
17715
|
+
);
|
|
17716
|
+
} catch (error) {
|
|
17717
|
+
this.logger.warn(
|
|
17718
|
+
`Wait for NatGateway ${physicalId} deletion did not complete cleanly: ${error instanceof Error ? error.message : String(error)} \u2014 proceeding with downstream delete steps`
|
|
17719
|
+
);
|
|
17720
|
+
}
|
|
17721
|
+
this.logger.debug(`Successfully deleted NatGateway ${logicalId}`);
|
|
17722
|
+
}
|
|
17549
17723
|
// ─── AWS::EC2::RouteTable ─────────────────────────────────────────
|
|
17550
17724
|
async createRouteTable(logicalId, resourceType, properties) {
|
|
17551
17725
|
this.logger.debug(`Creating RouteTable ${logicalId}`);
|
|
@@ -18755,6 +18929,15 @@ var EC2Provider = class {
|
|
|
18755
18929
|
const sg = resp.SecurityGroups?.[0];
|
|
18756
18930
|
return sg?.GroupId ? { physicalId: sg.GroupId, attributes: {} } : null;
|
|
18757
18931
|
}
|
|
18932
|
+
case "AWS::EC2::NatGateway": {
|
|
18933
|
+
const resp = await this.ec2Client.send(
|
|
18934
|
+
new DescribeNatGatewaysCommand({
|
|
18935
|
+
Filter: [{ Name: `tag:${CDK_PATH_TAG}`, Values: [input.cdkPath] }]
|
|
18936
|
+
})
|
|
18937
|
+
);
|
|
18938
|
+
const gw = resp.NatGateways?.find((g) => g.State !== "deleted" && g.State !== "deleting");
|
|
18939
|
+
return gw?.NatGatewayId ? { physicalId: gw.NatGatewayId, attributes: {} } : null;
|
|
18940
|
+
}
|
|
18758
18941
|
default:
|
|
18759
18942
|
return null;
|
|
18760
18943
|
}
|
|
@@ -18783,6 +18966,13 @@ var EC2Provider = class {
|
|
|
18783
18966
|
);
|
|
18784
18967
|
return resp.SecurityGroups?.[0] ? { physicalId, attributes: {} } : null;
|
|
18785
18968
|
}
|
|
18969
|
+
case "AWS::EC2::NatGateway": {
|
|
18970
|
+
const resp = await this.ec2Client.send(
|
|
18971
|
+
new DescribeNatGatewaysCommand({ NatGatewayIds: [physicalId] })
|
|
18972
|
+
);
|
|
18973
|
+
const gw = resp.NatGateways?.find((g) => g.State !== "deleted" && g.State !== "deleting");
|
|
18974
|
+
return gw ? { physicalId, attributes: {} } : null;
|
|
18975
|
+
}
|
|
18786
18976
|
default:
|
|
18787
18977
|
return null;
|
|
18788
18978
|
}
|
|
@@ -31106,6 +31296,7 @@ function registerAllProviders(registry) {
|
|
|
31106
31296
|
registry.register("AWS::EC2::Subnet", ec2Provider);
|
|
31107
31297
|
registry.register("AWS::EC2::InternetGateway", ec2Provider);
|
|
31108
31298
|
registry.register("AWS::EC2::VPCGatewayAttachment", ec2Provider);
|
|
31299
|
+
registry.register("AWS::EC2::NatGateway", ec2Provider);
|
|
31109
31300
|
registry.register("AWS::EC2::RouteTable", ec2Provider);
|
|
31110
31301
|
registry.register("AWS::EC2::Route", ec2Provider);
|
|
31111
31302
|
registry.register("AWS::EC2::SubnetRouteTableAssociation", ec2Provider);
|
|
@@ -36139,7 +36330,7 @@ function reorderArgs(argv) {
|
|
|
36139
36330
|
}
|
|
36140
36331
|
async function main() {
|
|
36141
36332
|
const program = new Command13();
|
|
36142
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
36333
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.31.0");
|
|
36143
36334
|
program.addCommand(createBootstrapCommand());
|
|
36144
36335
|
program.addCommand(createSynthCommand());
|
|
36145
36336
|
program.addCommand(createListCommand());
|