@go-to-k/cdkd 0.3.0 → 0.3.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 +86 -35
- package/dist/cli.js.map +2 -2
- package/dist/go-to-k-cdkd-0.3.2.tgz +0 -0
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.3.0.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -10987,7 +10987,10 @@ import {
|
|
|
10987
10987
|
GetFunctionCommand,
|
|
10988
10988
|
ResourceNotFoundException
|
|
10989
10989
|
} from "@aws-sdk/client-lambda";
|
|
10990
|
-
import {
|
|
10990
|
+
import {
|
|
10991
|
+
DescribeNetworkInterfacesCommand,
|
|
10992
|
+
DeleteNetworkInterfaceCommand
|
|
10993
|
+
} from "@aws-sdk/client-ec2";
|
|
10991
10994
|
init_aws_clients();
|
|
10992
10995
|
var LambdaFunctionProvider = class {
|
|
10993
10996
|
lambdaClient;
|
|
@@ -11196,6 +11199,24 @@ var LambdaFunctionProvider = class {
|
|
|
11196
11199
|
async delete(logicalId, physicalId, resourceType, properties) {
|
|
11197
11200
|
this.logger.debug(`Deleting Lambda function ${logicalId}: ${physicalId}`);
|
|
11198
11201
|
const hasVpcConfig = this.hasVpcConfig(properties?.["VpcConfig"]);
|
|
11202
|
+
if (hasVpcConfig) {
|
|
11203
|
+
try {
|
|
11204
|
+
await this.lambdaClient.send(
|
|
11205
|
+
new UpdateFunctionConfigurationCommand({
|
|
11206
|
+
FunctionName: physicalId,
|
|
11207
|
+
VpcConfig: { SubnetIds: [], SecurityGroupIds: [] }
|
|
11208
|
+
})
|
|
11209
|
+
);
|
|
11210
|
+
this.logger.debug(`Detached VPC config from Lambda ${physicalId} before deletion`);
|
|
11211
|
+
} catch (error) {
|
|
11212
|
+
if (error instanceof ResourceNotFoundException) {
|
|
11213
|
+
return;
|
|
11214
|
+
}
|
|
11215
|
+
this.logger.warn(
|
|
11216
|
+
`Pre-delete VPC detach failed for ${physicalId}: ${error instanceof Error ? error.message : String(error)} \u2014 continuing with delete`
|
|
11217
|
+
);
|
|
11218
|
+
}
|
|
11219
|
+
}
|
|
11199
11220
|
try {
|
|
11200
11221
|
await this.lambdaClient.send(new DeleteFunctionCommand({ FunctionName: physicalId }));
|
|
11201
11222
|
this.logger.debug(`Successfully deleted Lambda function ${logicalId}`);
|
|
@@ -11214,7 +11235,7 @@ var LambdaFunctionProvider = class {
|
|
|
11214
11235
|
);
|
|
11215
11236
|
}
|
|
11216
11237
|
if (hasVpcConfig) {
|
|
11217
|
-
await this.
|
|
11238
|
+
await this.cleanupLambdaEnis(physicalId);
|
|
11218
11239
|
}
|
|
11219
11240
|
}
|
|
11220
11241
|
/**
|
|
@@ -11275,50 +11296,78 @@ var LambdaFunctionProvider = class {
|
|
|
11275
11296
|
return Array.isArray(subnets) && subnets.length > 0;
|
|
11276
11297
|
}
|
|
11277
11298
|
/**
|
|
11278
|
-
*
|
|
11279
|
-
*
|
|
11299
|
+
* Clean up Lambda-managed ENIs for the given function: list, then attempt
|
|
11300
|
+
* DeleteNetworkInterface on each. Repeat until no matching ENIs remain
|
|
11301
|
+
* or the configured timeout elapses.
|
|
11302
|
+
*
|
|
11303
|
+
* Why direct delete (not just wait): an `available` ENI still counts as a
|
|
11304
|
+
* Subnet / SecurityGroup dependency, so DeleteSubnet / DeleteSecurityGroup
|
|
11305
|
+
* fail until the ENI itself is gone. AWS's eventual cleanup of unused
|
|
11306
|
+
* Lambda hyperplane ENIs can take well over an hour, which is far longer
|
|
11307
|
+
* than any reasonable destroy budget. Calling DeleteNetworkInterface
|
|
11308
|
+
* ourselves (best-effort) clears `available` ENIs in seconds.
|
|
11280
11309
|
*
|
|
11281
|
-
*
|
|
11282
|
-
*
|
|
11283
|
-
*
|
|
11310
|
+
* In-use ENIs (e.g. immediately after the pre-delete VPC detach) cannot
|
|
11311
|
+
* be deleted yet — we swallow that error and retry on the next iteration
|
|
11312
|
+
* once they transition to `available`.
|
|
11313
|
+
*
|
|
11314
|
+
* Lambda VPC ENI Descriptions follow the pattern
|
|
11315
|
+
* "AWS Lambda VPC ENI-<functionName>"
|
|
11316
|
+
* (and historically "AWS Lambda VPC ENI-<functionName>-<uuid>"). We
|
|
11317
|
+
* narrow the query with a `requester-id` filter and then match the
|
|
11318
|
+
* function name as a hyphen-bounded token to avoid false positives like
|
|
11319
|
+
* "myfn" matching for function "fn".
|
|
11284
11320
|
*
|
|
11285
11321
|
* Polling: starts at eniWaitInitialDelayMs (10s), exponential backoff up
|
|
11286
11322
|
* to eniWaitMaxDelayMs (30s), bounded by eniWaitTimeoutMs (10min).
|
|
11287
|
-
*
|
|
11288
|
-
*
|
|
11289
|
-
* minutes in degraded conditions, and downstream Subnet/SG deletion has
|
|
11290
|
-
* its own retries to handle the residual window.
|
|
11323
|
+
* Timeout is a soft warning — downstream Subnet/SG deletion has its own
|
|
11324
|
+
* retries.
|
|
11291
11325
|
*/
|
|
11292
|
-
async
|
|
11326
|
+
async cleanupLambdaEnis(functionName) {
|
|
11293
11327
|
const start = Date.now();
|
|
11294
11328
|
let delay = this.eniWaitInitialDelayMs;
|
|
11295
11329
|
let attempt = 0;
|
|
11296
11330
|
this.logger.debug(
|
|
11297
|
-
`
|
|
11331
|
+
`Cleaning up Lambda VPC ENIs for function ${functionName} (timeout ${this.eniWaitTimeoutMs}ms)`
|
|
11298
11332
|
);
|
|
11299
|
-
const descriptionNeedle = `AWS Lambda VPC ENI`;
|
|
11300
|
-
const functionNamePattern = new RegExp(`(^|-)${escapeRegExp(functionName)}(-|$)`);
|
|
11301
11333
|
for (; ; ) {
|
|
11302
11334
|
attempt++;
|
|
11303
|
-
let
|
|
11335
|
+
let enis = [];
|
|
11336
|
+
let listFailed = false;
|
|
11304
11337
|
try {
|
|
11305
|
-
|
|
11338
|
+
enis = await this.listLambdaEnis(functionName);
|
|
11306
11339
|
} catch (error) {
|
|
11307
11340
|
this.logger.warn(
|
|
11308
|
-
`DescribeNetworkInterfaces failed while
|
|
11341
|
+
`DescribeNetworkInterfaces failed while cleaning up Lambda ENIs of ${functionName}: ${error instanceof Error ? error.message : String(error)}`
|
|
11309
11342
|
);
|
|
11310
|
-
|
|
11343
|
+
listFailed = true;
|
|
11311
11344
|
}
|
|
11312
|
-
if (
|
|
11345
|
+
if (!listFailed && enis.length === 0) {
|
|
11313
11346
|
this.logger.debug(
|
|
11314
|
-
`Lambda ENIs for ${functionName} fully
|
|
11347
|
+
`Lambda ENIs for ${functionName} fully cleaned up after ${attempt} attempt(s) / ${Date.now() - start}ms`
|
|
11315
11348
|
);
|
|
11316
11349
|
return;
|
|
11317
11350
|
}
|
|
11351
|
+
if (enis.length > 0) {
|
|
11352
|
+
await Promise.all(
|
|
11353
|
+
enis.map(async (eni) => {
|
|
11354
|
+
try {
|
|
11355
|
+
await this.ec2Client.send(
|
|
11356
|
+
new DeleteNetworkInterfaceCommand({ NetworkInterfaceId: eni.id })
|
|
11357
|
+
);
|
|
11358
|
+
this.logger.debug(`Deleted Lambda ENI ${eni.id} for ${functionName}`);
|
|
11359
|
+
} catch (error) {
|
|
11360
|
+
this.logger.debug(
|
|
11361
|
+
`ENI ${eni.id} (status=${eni.status}) not yet deletable: ${error instanceof Error ? error.message : String(error)}`
|
|
11362
|
+
);
|
|
11363
|
+
}
|
|
11364
|
+
})
|
|
11365
|
+
);
|
|
11366
|
+
}
|
|
11318
11367
|
const elapsed = Date.now() - start;
|
|
11319
11368
|
if (elapsed >= this.eniWaitTimeoutMs) {
|
|
11320
11369
|
this.logger.warn(
|
|
11321
|
-
`Timeout (${this.eniWaitTimeoutMs}ms)
|
|
11370
|
+
`Timeout (${this.eniWaitTimeoutMs}ms) cleaning up Lambda VPC ENIs of ${functionName} (${enis.length} remaining). Continuing \u2014 downstream Subnet/SG deletion will retry as needed.`
|
|
11322
11371
|
);
|
|
11323
11372
|
return;
|
|
11324
11373
|
}
|
|
@@ -11329,15 +11378,16 @@ var LambdaFunctionProvider = class {
|
|
|
11329
11378
|
}
|
|
11330
11379
|
}
|
|
11331
11380
|
/**
|
|
11332
|
-
*
|
|
11333
|
-
*
|
|
11381
|
+
* List Lambda-managed ENIs for the given function, paginating through
|
|
11382
|
+
* DescribeNetworkInterfaces and filtering on Description substring.
|
|
11334
11383
|
*
|
|
11335
|
-
* Server-side filter (`description`) does not support wildcards
|
|
11336
|
-
* so we
|
|
11384
|
+
* Server-side filter (`description`) does not support wildcards on this
|
|
11385
|
+
* API, so we narrow with `requester-id` + match Description client-side.
|
|
11337
11386
|
*/
|
|
11338
|
-
async
|
|
11387
|
+
async listLambdaEnis(functionName) {
|
|
11388
|
+
const enis = [];
|
|
11389
|
+
const descriptionPrefix = "AWS Lambda VPC ENI-";
|
|
11339
11390
|
let nextToken;
|
|
11340
|
-
let count = 0;
|
|
11341
11391
|
do {
|
|
11342
11392
|
const resp = await this.ec2Client.send(
|
|
11343
11393
|
new DescribeNetworkInterfacesCommand({
|
|
@@ -11350,13 +11400,17 @@ var LambdaFunctionProvider = class {
|
|
|
11350
11400
|
);
|
|
11351
11401
|
for (const ni of resp.NetworkInterfaces ?? []) {
|
|
11352
11402
|
const desc = ni.Description ?? "";
|
|
11353
|
-
if (
|
|
11354
|
-
|
|
11403
|
+
if (!ni.NetworkInterfaceId || !desc.startsWith(descriptionPrefix)) {
|
|
11404
|
+
continue;
|
|
11405
|
+
}
|
|
11406
|
+
const token = desc.slice(descriptionPrefix.length);
|
|
11407
|
+
if (functionName === token || functionName.startsWith(`${token}-`)) {
|
|
11408
|
+
enis.push({ id: ni.NetworkInterfaceId, status: ni.Status ?? "unknown" });
|
|
11355
11409
|
}
|
|
11356
11410
|
}
|
|
11357
11411
|
nextToken = resp.NextToken;
|
|
11358
11412
|
} while (nextToken);
|
|
11359
|
-
return
|
|
11413
|
+
return enis;
|
|
11360
11414
|
}
|
|
11361
11415
|
sleep(ms) {
|
|
11362
11416
|
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
@@ -11446,9 +11500,6 @@ var LambdaFunctionProvider = class {
|
|
|
11446
11500
|
return (crc ^ 4294967295) >>> 0;
|
|
11447
11501
|
}
|
|
11448
11502
|
};
|
|
11449
|
-
function escapeRegExp(input) {
|
|
11450
|
-
return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11451
|
-
}
|
|
11452
11503
|
|
|
11453
11504
|
// src/provisioning/providers/lambda-permission-provider.ts
|
|
11454
11505
|
import {
|
|
@@ -27554,7 +27605,7 @@ function reorderArgs(argv) {
|
|
|
27554
27605
|
}
|
|
27555
27606
|
async function main() {
|
|
27556
27607
|
const program = new Command8();
|
|
27557
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.3.
|
|
27608
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.3.2");
|
|
27558
27609
|
program.addCommand(createBootstrapCommand());
|
|
27559
27610
|
program.addCommand(createSynthCommand());
|
|
27560
27611
|
program.addCommand(createDeployCommand());
|