@go-to-k/cdkd 0.73.0 → 0.74.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 +13 -0
- package/dist/cli.js +292 -128
- package/dist/cli.js.map +3 -3
- package/dist/go-to-k-cdkd-0.74.0.tgz +0 -0
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.73.0.tgz +0 -0
package/README.md
CHANGED
|
@@ -634,6 +634,19 @@ cdkd local invoke MyStack/Handler --debug-port 9229
|
|
|
634
634
|
cdkd local invoke MyStack/Handler --from-state
|
|
635
635
|
```
|
|
636
636
|
|
|
637
|
+
**Lambda Layers (PR 6 of #224, issue #232)** — same-stack
|
|
638
|
+
`AWS::Lambda::LayerVersion` references in `Properties.Layers` are
|
|
639
|
+
resolved automatically and bind-mounted at `/opt` (read-only) inside
|
|
640
|
+
the container. Each layer's unzipped asset directory under `cdk.out/`
|
|
641
|
+
becomes one `-v <layerAssetPath>:/opt:ro` mount; multiple layers
|
|
642
|
+
stack via Docker overlay layering, and AWS's "last layer wins on
|
|
643
|
+
file collision" rule is preserved by keeping the template's input
|
|
644
|
+
order. Cross-stack / cross-account / cross-region layer ARNs (literal
|
|
645
|
+
ARN strings in `Properties.Layers`) are out of scope for v1 — cdkd
|
|
646
|
+
hard-errors with a clear pointer at the offending entry. Container
|
|
647
|
+
Lambdas (`Code.ImageUri`) silently ignore `Layers` (matches AWS:
|
|
648
|
+
container images bake layers at build time).
|
|
649
|
+
|
|
637
650
|
See [docs/cli-reference.md](docs/cli-reference.md#local-invoke-run-lambda-functions-locally)
|
|
638
651
|
for the full surface, target-resolution rules, and v1 scope notes.
|
|
639
652
|
|
package/dist/cli.js
CHANGED
|
@@ -70034,7 +70034,7 @@ async function captureObservedForImportedResources(stackState, providerRegistry,
|
|
|
70034
70034
|
}
|
|
70035
70035
|
|
|
70036
70036
|
// src/cli/commands/local-invoke.ts
|
|
70037
|
-
import { mkdtempSync as mkdtempSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
70037
|
+
import { cpSync as cpSync2, mkdtempSync as mkdtempSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
70038
70038
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
70039
70039
|
import { dirname as dirname3 } from "node:path";
|
|
70040
70040
|
import * as path2 from "node:path";
|
|
@@ -70169,6 +70169,7 @@ function extractLambdaProperties(stack, logicalId, resource) {
|
|
|
70169
70169
|
if (!inlineCode) {
|
|
70170
70170
|
codePath = resolveAssetCodePath(stack, logicalId, resource);
|
|
70171
70171
|
}
|
|
70172
|
+
const layers = resolveLambdaLayers(stack, logicalId, props);
|
|
70172
70173
|
return {
|
|
70173
70174
|
kind: "zip",
|
|
70174
70175
|
stack,
|
|
@@ -70179,6 +70180,7 @@ function extractLambdaProperties(stack, logicalId, resource) {
|
|
|
70179
70180
|
memoryMb,
|
|
70180
70181
|
timeoutSec,
|
|
70181
70182
|
codePath,
|
|
70183
|
+
layers,
|
|
70182
70184
|
...inlineCode !== void 0 && { inlineCode }
|
|
70183
70185
|
};
|
|
70184
70186
|
}
|
|
@@ -70235,7 +70237,8 @@ function extractImageLambdaProperties(args) {
|
|
|
70235
70237
|
timeoutSec,
|
|
70236
70238
|
imageUri,
|
|
70237
70239
|
imageConfig,
|
|
70238
|
-
architecture
|
|
70240
|
+
architecture,
|
|
70241
|
+
layers: []
|
|
70239
70242
|
};
|
|
70240
70243
|
}
|
|
70241
70244
|
function resolveAssetCodePath(stack, logicalId, resource) {
|
|
@@ -70255,6 +70258,72 @@ function resolveAssetCodePath(stack, logicalId, resource) {
|
|
|
70255
70258
|
}
|
|
70256
70259
|
return abs;
|
|
70257
70260
|
}
|
|
70261
|
+
function resolveLambdaLayers(stack, logicalId, props) {
|
|
70262
|
+
const layers = props["Layers"];
|
|
70263
|
+
if (layers === void 0)
|
|
70264
|
+
return [];
|
|
70265
|
+
if (!Array.isArray(layers)) {
|
|
70266
|
+
throw new LocalInvokeResolutionError(
|
|
70267
|
+
`Lambda '${logicalId}' has a non-array Layers property. Expected an array of LayerVersion references.`
|
|
70268
|
+
);
|
|
70269
|
+
}
|
|
70270
|
+
if (layers.length === 0)
|
|
70271
|
+
return [];
|
|
70272
|
+
const resources = stack.template.Resources ?? {};
|
|
70273
|
+
const out = [];
|
|
70274
|
+
for (let i = 0; i < layers.length; i++) {
|
|
70275
|
+
const entry = layers[i];
|
|
70276
|
+
const layerLogicalId = pickLayerLogicalId(entry);
|
|
70277
|
+
if (!layerLogicalId) {
|
|
70278
|
+
throw new LocalInvokeResolutionError(
|
|
70279
|
+
`Lambda '${logicalId}' has a Layers entry [${i}] cdkd cannot resolve locally: ${describeLayerEntry(entry)}. Only same-stack Ref / Fn::GetAtt to an AWS::Lambda::LayerVersion are supported in v1; cross-account / cross-region / pre-existing-ARN layers are deferred to a follow-up PR.`
|
|
70280
|
+
);
|
|
70281
|
+
}
|
|
70282
|
+
const layerResource = resources[layerLogicalId];
|
|
70283
|
+
if (!layerResource) {
|
|
70284
|
+
throw new LocalInvokeResolutionError(
|
|
70285
|
+
`Lambda '${logicalId}' Layers entry [${i}] references '${layerLogicalId}', but no resource with that logical ID exists in stack '${stack.stackName}'.`
|
|
70286
|
+
);
|
|
70287
|
+
}
|
|
70288
|
+
if (layerResource.Type !== "AWS::Lambda::LayerVersion") {
|
|
70289
|
+
throw new LocalInvokeResolutionError(
|
|
70290
|
+
`Lambda '${logicalId}' Layers entry [${i}] references '${layerLogicalId}' (${layerResource.Type}), which is not an AWS::Lambda::LayerVersion.`
|
|
70291
|
+
);
|
|
70292
|
+
}
|
|
70293
|
+
const assetPath = resolveAssetCodePath(stack, layerLogicalId, layerResource);
|
|
70294
|
+
out.push({ logicalId: layerLogicalId, assetPath });
|
|
70295
|
+
}
|
|
70296
|
+
return out;
|
|
70297
|
+
}
|
|
70298
|
+
function pickLayerLogicalId(entry) {
|
|
70299
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry))
|
|
70300
|
+
return void 0;
|
|
70301
|
+
const obj = entry;
|
|
70302
|
+
if (typeof obj["Ref"] === "string")
|
|
70303
|
+
return obj["Ref"];
|
|
70304
|
+
if ("Fn::GetAtt" in obj) {
|
|
70305
|
+
const arg = obj["Fn::GetAtt"];
|
|
70306
|
+
if (Array.isArray(arg) && typeof arg[0] === "string")
|
|
70307
|
+
return arg[0];
|
|
70308
|
+
if (typeof arg === "string")
|
|
70309
|
+
return arg.split(".")[0];
|
|
70310
|
+
}
|
|
70311
|
+
return void 0;
|
|
70312
|
+
}
|
|
70313
|
+
function describeLayerEntry(entry) {
|
|
70314
|
+
if (typeof entry === "string")
|
|
70315
|
+
return `literal ARN '${entry}'`;
|
|
70316
|
+
if (entry === null)
|
|
70317
|
+
return "null";
|
|
70318
|
+
if (typeof entry !== "object")
|
|
70319
|
+
return String(entry);
|
|
70320
|
+
try {
|
|
70321
|
+
const json = JSON.stringify(entry);
|
|
70322
|
+
return json.length > 120 ? json.substring(0, 117) + "..." : json;
|
|
70323
|
+
} catch {
|
|
70324
|
+
return Object.prototype.toString.call(entry);
|
|
70325
|
+
}
|
|
70326
|
+
}
|
|
70258
70327
|
function notFoundError(target, stack, resources) {
|
|
70259
70328
|
const lambdas = [];
|
|
70260
70329
|
for (const [logicalId, resource] of Object.entries(resources)) {
|
|
@@ -70578,6 +70647,12 @@ async function runDetached(opts) {
|
|
|
70578
70647
|
const ro = mount.readOnly ? ":ro" : "";
|
|
70579
70648
|
args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
|
|
70580
70649
|
}
|
|
70650
|
+
if (opts.extraMounts) {
|
|
70651
|
+
for (const mount of opts.extraMounts) {
|
|
70652
|
+
const ro = mount.readOnly ? ":ro" : "";
|
|
70653
|
+
args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
|
|
70654
|
+
}
|
|
70655
|
+
}
|
|
70581
70656
|
for (const [k, v] of Object.entries(opts.env)) {
|
|
70582
70657
|
args.push("-e", `${k}=${v}`);
|
|
70583
70658
|
}
|
|
@@ -71089,7 +71164,7 @@ function extractHashFromImageUri(imageUri) {
|
|
|
71089
71164
|
init_aws_clients();
|
|
71090
71165
|
|
|
71091
71166
|
// src/cli/commands/local-start-api.ts
|
|
71092
|
-
import { mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
71167
|
+
import { cpSync, mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
71093
71168
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
71094
71169
|
import * as path from "node:path";
|
|
71095
71170
|
import { Command as Command14, Option as Option7 } from "commander";
|
|
@@ -71480,9 +71555,11 @@ function createContainerPool(specs, options) {
|
|
|
71480
71555
|
logger.debug(
|
|
71481
71556
|
`Starting container ${name} for ${spec.lambda.logicalId} on ${spec.containerHost}:${hostPort}`
|
|
71482
71557
|
);
|
|
71558
|
+
const optMount = spec.optDir ? [{ hostPath: spec.optDir, containerPath: "/opt", readOnly: true }] : [];
|
|
71483
71559
|
const containerId = await runDetached({
|
|
71484
71560
|
image,
|
|
71485
71561
|
mounts: [{ hostPath: spec.codeDir, containerPath: "/var/task", readOnly: true }],
|
|
71562
|
+
extraMounts: optMount,
|
|
71486
71563
|
env: spec.env,
|
|
71487
71564
|
cmd: [spec.lambda.handler],
|
|
71488
71565
|
hostPort,
|
|
@@ -73465,6 +73542,7 @@ async function localStartApiCommand(options) {
|
|
|
73465
73542
|
const debugPortBase = options.debugPortBase ? parseDebugPort(options.debugPortBase) : void 0;
|
|
73466
73543
|
const specs = /* @__PURE__ */ new Map();
|
|
73467
73544
|
const inlineTmpDirs = /* @__PURE__ */ new Set();
|
|
73545
|
+
const layerTmpDirs = /* @__PURE__ */ new Set();
|
|
73468
73546
|
for (let i = 0; i < lambdaIds.length; i++) {
|
|
73469
73547
|
const logicalId = lambdaIds[i];
|
|
73470
73548
|
const spec = await buildContainerSpec({
|
|
@@ -73475,7 +73553,8 @@ async function localStartApiCommand(options) {
|
|
|
73475
73553
|
containerHost: options.containerHost,
|
|
73476
73554
|
...debugPortBase !== void 0 && { debugPort: debugPortBase + i },
|
|
73477
73555
|
stsRegion: options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"],
|
|
73478
|
-
inlineTmpDirs
|
|
73556
|
+
inlineTmpDirs,
|
|
73557
|
+
layerTmpDirs
|
|
73479
73558
|
});
|
|
73480
73559
|
specs.set(logicalId, spec);
|
|
73481
73560
|
}
|
|
@@ -73570,6 +73649,15 @@ async function localStartApiCommand(options) {
|
|
|
73570
73649
|
);
|
|
73571
73650
|
}
|
|
73572
73651
|
}
|
|
73652
|
+
for (const dir of layerTmpDirs) {
|
|
73653
|
+
try {
|
|
73654
|
+
rmSync2(dir, { recursive: true, force: true });
|
|
73655
|
+
} catch (err) {
|
|
73656
|
+
logger.warn(
|
|
73657
|
+
`Failed to remove merged-layers tmpdir ${dir}: ${err instanceof Error ? err.message : String(err)}`
|
|
73658
|
+
);
|
|
73659
|
+
}
|
|
73660
|
+
}
|
|
73573
73661
|
process.exit(exitCode);
|
|
73574
73662
|
};
|
|
73575
73663
|
process.on("SIGINT", () => {
|
|
@@ -73683,7 +73771,8 @@ async function buildContainerSpec(args) {
|
|
|
73683
73771
|
containerHost,
|
|
73684
73772
|
debugPort,
|
|
73685
73773
|
stsRegion,
|
|
73686
|
-
inlineTmpDirs
|
|
73774
|
+
inlineTmpDirs,
|
|
73775
|
+
layerTmpDirs
|
|
73687
73776
|
} = args;
|
|
73688
73777
|
const lambda = resolveLambdaByLogicalId(logicalId, stacks);
|
|
73689
73778
|
const codeDir = lambda.codePath ?? materializeInlineCode(
|
|
@@ -73692,6 +73781,7 @@ async function buildContainerSpec(args) {
|
|
|
73692
73781
|
resolveRuntimeFileExtension(lambda.runtime),
|
|
73693
73782
|
inlineTmpDirs
|
|
73694
73783
|
);
|
|
73784
|
+
const optDir = materializeLambdaLayers(lambda.layers, layerTmpDirs);
|
|
73695
73785
|
const templateEnv = getTemplateEnv(lambda.resource);
|
|
73696
73786
|
const envResult = resolveEnvVars(logicalId, templateEnv, overrides);
|
|
73697
73787
|
for (const key of envResult.unresolved) {
|
|
@@ -73727,10 +73817,23 @@ async function buildContainerSpec(args) {
|
|
|
73727
73817
|
codeDir,
|
|
73728
73818
|
env: dockerEnv,
|
|
73729
73819
|
containerHost,
|
|
73820
|
+
...optDir !== void 0 && { optDir },
|
|
73730
73821
|
...debugPort !== void 0 && { debugPort }
|
|
73731
73822
|
};
|
|
73732
73823
|
return spec;
|
|
73733
73824
|
}
|
|
73825
|
+
function materializeLambdaLayers(layers, layerTmpDirs) {
|
|
73826
|
+
if (layers.length === 0)
|
|
73827
|
+
return void 0;
|
|
73828
|
+
if (layers.length === 1)
|
|
73829
|
+
return layers[0].assetPath;
|
|
73830
|
+
const dir = mkdtempSync2(path.join(tmpdir2(), "cdkd-local-start-api-layers-"));
|
|
73831
|
+
for (const layer of layers) {
|
|
73832
|
+
cpSync(layer.assetPath, dir, { recursive: true, force: true });
|
|
73833
|
+
}
|
|
73834
|
+
layerTmpDirs.add(dir);
|
|
73835
|
+
return dir;
|
|
73836
|
+
}
|
|
73734
73837
|
function resolveLambdaByLogicalId(logicalId, stacks) {
|
|
73735
73838
|
for (const stack of stacks) {
|
|
73736
73839
|
const resource = stack.template.Resources?.[logicalId];
|
|
@@ -73761,6 +73864,7 @@ function resolveLambdaByLogicalId(logicalId, stacks) {
|
|
|
73761
73864
|
if (!inlineCode) {
|
|
73762
73865
|
codePath = resolveAssetCodePath2(stack, logicalId, resource);
|
|
73763
73866
|
}
|
|
73867
|
+
const layers = resolveLambdaLayers(stack, logicalId, props);
|
|
73764
73868
|
return {
|
|
73765
73869
|
kind: "zip",
|
|
73766
73870
|
stack,
|
|
@@ -73771,6 +73875,7 @@ function resolveLambdaByLogicalId(logicalId, stacks) {
|
|
|
73771
73875
|
memoryMb,
|
|
73772
73876
|
timeoutSec,
|
|
73773
73877
|
codePath,
|
|
73878
|
+
layers,
|
|
73774
73879
|
...inlineCode !== void 0 && { inlineCode }
|
|
73775
73880
|
};
|
|
73776
73881
|
}
|
|
@@ -73957,123 +74062,170 @@ async function localInvokeCommand(target, options) {
|
|
|
73957
74062
|
logger.setLevel("debug");
|
|
73958
74063
|
}
|
|
73959
74064
|
warnIfDeprecatedRegion(options);
|
|
73960
|
-
|
|
73961
|
-
|
|
73962
|
-
|
|
73963
|
-
|
|
73964
|
-
|
|
73965
|
-
|
|
73966
|
-
|
|
73967
|
-
|
|
73968
|
-
|
|
73969
|
-
|
|
73970
|
-
|
|
73971
|
-
|
|
73972
|
-
|
|
73973
|
-
|
|
73974
|
-
|
|
73975
|
-
|
|
73976
|
-
|
|
73977
|
-
|
|
73978
|
-
|
|
73979
|
-
|
|
73980
|
-
|
|
73981
|
-
|
|
73982
|
-
|
|
73983
|
-
|
|
73984
|
-
|
|
73985
|
-
|
|
73986
|
-
|
|
73987
|
-
|
|
73988
|
-
|
|
73989
|
-
|
|
73990
|
-
|
|
73991
|
-
}
|
|
73992
|
-
if (
|
|
73993
|
-
|
|
73994
|
-
|
|
73995
|
-
|
|
73996
|
-
|
|
73997
|
-
|
|
73998
|
-
logger.debug(`--from-state: substituted env var ${key} from cdkd state`);
|
|
73999
|
-
}
|
|
74000
|
-
for (const { key, reason } of audit.unresolved) {
|
|
74001
|
-
logger.warn(
|
|
74002
|
-
`--from-state: could not substitute env var ${key} (${reason}). Override it via --env-vars or it will be dropped.`
|
|
74065
|
+
let imagePlan;
|
|
74066
|
+
let containerId;
|
|
74067
|
+
let stopLogs;
|
|
74068
|
+
let sigintHandler;
|
|
74069
|
+
const cleanup = async () => {
|
|
74070
|
+
if (stopLogs) {
|
|
74071
|
+
try {
|
|
74072
|
+
stopLogs();
|
|
74073
|
+
} catch (err) {
|
|
74074
|
+
getLogger().debug(
|
|
74075
|
+
`streamLogs stop failed: ${err instanceof Error ? err.message : String(err)}`
|
|
74076
|
+
);
|
|
74077
|
+
}
|
|
74078
|
+
}
|
|
74079
|
+
if (containerId) {
|
|
74080
|
+
try {
|
|
74081
|
+
await removeContainer(containerId);
|
|
74082
|
+
} catch (err) {
|
|
74083
|
+
getLogger().debug(
|
|
74084
|
+
`removeContainer(${containerId}) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
74085
|
+
);
|
|
74086
|
+
}
|
|
74087
|
+
}
|
|
74088
|
+
if (imagePlan?.inlineTmpDir) {
|
|
74089
|
+
try {
|
|
74090
|
+
rmSync3(imagePlan.inlineTmpDir, { recursive: true, force: true });
|
|
74091
|
+
} catch (err) {
|
|
74092
|
+
getLogger().debug(
|
|
74093
|
+
`Failed to remove inline-code tmpdir ${imagePlan.inlineTmpDir}: ${err instanceof Error ? err.message : String(err)}`
|
|
74094
|
+
);
|
|
74095
|
+
}
|
|
74096
|
+
}
|
|
74097
|
+
if (imagePlan?.layersTmpDir) {
|
|
74098
|
+
try {
|
|
74099
|
+
rmSync3(imagePlan.layersTmpDir, { recursive: true, force: true });
|
|
74100
|
+
} catch (err) {
|
|
74101
|
+
getLogger().debug(
|
|
74102
|
+
`Failed to remove merged-layers tmpdir ${imagePlan.layersTmpDir}: ${err instanceof Error ? err.message : String(err)}`
|
|
74003
74103
|
);
|
|
74004
74104
|
}
|
|
74005
74105
|
}
|
|
74006
|
-
}
|
|
74007
|
-
const overrides = readEnvOverridesFile2(options.envVars);
|
|
74008
|
-
const envResult = resolveEnvVars(lambda.logicalId, templateEnv, overrides);
|
|
74009
|
-
for (const key of envResult.unresolved) {
|
|
74010
|
-
if (stateAudit && stateAudit.unresolved.some((u) => u.key === key))
|
|
74011
|
-
continue;
|
|
74012
|
-
logger.warn(
|
|
74013
|
-
`Environment variable ${key} contains a CloudFormation intrinsic and was dropped. Override it with --env-vars (e.g. {"${lambda.logicalId}":{"${key}":"<literal>"}}) or pass --from-state to recover deployed values.`
|
|
74014
|
-
);
|
|
74015
|
-
}
|
|
74016
|
-
if (options.fromState && !options.assumeRole && stateForRoleHint) {
|
|
74017
|
-
suggestAssumeRoleFromState(stateForRoleHint, lambda.logicalId);
|
|
74018
|
-
}
|
|
74019
|
-
const event = await readEvent(options);
|
|
74020
|
-
const dockerEnv = {
|
|
74021
|
-
AWS_LAMBDA_FUNCTION_NAME: lambda.logicalId,
|
|
74022
|
-
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: String(lambda.memoryMb),
|
|
74023
|
-
AWS_LAMBDA_FUNCTION_TIMEOUT: String(lambda.timeoutSec),
|
|
74024
|
-
AWS_LAMBDA_FUNCTION_VERSION: "$LATEST",
|
|
74025
|
-
AWS_LAMBDA_LOG_GROUP_NAME: `/aws/lambda/${lambda.logicalId}`,
|
|
74026
|
-
AWS_LAMBDA_LOG_STREAM_NAME: "local",
|
|
74027
|
-
...envResult.resolved
|
|
74028
74106
|
};
|
|
74029
|
-
|
|
74030
|
-
|
|
74031
|
-
|
|
74032
|
-
|
|
74033
|
-
|
|
74034
|
-
|
|
74035
|
-
if (stsRegion)
|
|
74036
|
-
dockerEnv["AWS_REGION"] = stsRegion;
|
|
74037
|
-
} else {
|
|
74038
|
-
forwardAwsEnv2(dockerEnv);
|
|
74039
|
-
}
|
|
74040
|
-
let debugPort;
|
|
74041
|
-
if (options.debugPort) {
|
|
74042
|
-
debugPort = Number(options.debugPort);
|
|
74043
|
-
if (!Number.isInteger(debugPort) || debugPort <= 0 || debugPort > 65535) {
|
|
74044
|
-
throw new Error(`--debug-port must be an integer in 1..65535, got '${options.debugPort}'`);
|
|
74107
|
+
try {
|
|
74108
|
+
await applyRoleArnIfSet({ roleArn: options.roleArn, region: options.region });
|
|
74109
|
+
await ensureDockerAvailable();
|
|
74110
|
+
const appCmd = resolveApp(options.app);
|
|
74111
|
+
if (!appCmd) {
|
|
74112
|
+
throw new Error('No CDK app specified. Pass --app, set CDKD_APP, or add "app" to cdk.json.');
|
|
74045
74113
|
}
|
|
74046
|
-
|
|
74047
|
-
|
|
74114
|
+
logger.info("Synthesizing CDK app...");
|
|
74115
|
+
const synthesizer = new Synthesizer();
|
|
74116
|
+
const context = parseContextOptions(options.context);
|
|
74117
|
+
const synthOpts = {
|
|
74118
|
+
app: appCmd,
|
|
74119
|
+
output: options.output,
|
|
74120
|
+
...options.region && { region: options.region },
|
|
74121
|
+
...options.profile && { profile: options.profile },
|
|
74122
|
+
...Object.keys(context).length > 0 && { context }
|
|
74123
|
+
};
|
|
74124
|
+
const { stacks } = await synthesizer.synthesize(synthOpts);
|
|
74125
|
+
const lambda = resolveLambdaTarget(target, stacks);
|
|
74126
|
+
const targetLabel = lambda.kind === "zip" ? lambda.runtime : "container image";
|
|
74127
|
+
logger.info(`Target: ${lambda.stack.stackName}/${lambda.logicalId} (${targetLabel})`);
|
|
74128
|
+
imagePlan = await resolveImagePlan(lambda, options);
|
|
74129
|
+
let stateAudit;
|
|
74130
|
+
let templateEnv = getTemplateEnv2(lambda.resource);
|
|
74131
|
+
let stateForRoleHint;
|
|
74132
|
+
if (options.fromState) {
|
|
74133
|
+
const loaded = await loadStateForStack(lambda.stack.stackName, lambda.stack.region, {
|
|
74134
|
+
...options.stackRegion !== void 0 && { stackRegion: options.stackRegion },
|
|
74135
|
+
...options.stateBucket !== void 0 && { stateBucket: options.stateBucket },
|
|
74136
|
+
statePrefix: options.statePrefix,
|
|
74137
|
+
...options.region !== void 0 && { region: options.region },
|
|
74138
|
+
...options.profile !== void 0 && { profile: options.profile }
|
|
74139
|
+
});
|
|
74140
|
+
if (loaded) {
|
|
74141
|
+
stateForRoleHint = loaded.state;
|
|
74142
|
+
const { env, audit } = substituteEnvVarsFromState(templateEnv, loaded.state.resources);
|
|
74143
|
+
templateEnv = env;
|
|
74144
|
+
stateAudit = audit;
|
|
74145
|
+
for (const key of audit.resolvedKeys) {
|
|
74146
|
+
logger.debug(`--from-state: substituted env var ${key} from cdkd state`);
|
|
74147
|
+
}
|
|
74148
|
+
for (const { key, reason } of audit.unresolved) {
|
|
74149
|
+
logger.warn(
|
|
74150
|
+
`--from-state: could not substitute env var ${key} (${reason}). Override it via --env-vars or it will be dropped.`
|
|
74151
|
+
);
|
|
74152
|
+
}
|
|
74153
|
+
}
|
|
74154
|
+
}
|
|
74155
|
+
const overrides = readEnvOverridesFile2(options.envVars);
|
|
74156
|
+
const envResult = resolveEnvVars(lambda.logicalId, templateEnv, overrides);
|
|
74157
|
+
for (const key of envResult.unresolved) {
|
|
74158
|
+
if (stateAudit && stateAudit.unresolved.some((u) => u.key === key))
|
|
74159
|
+
continue;
|
|
74048
74160
|
logger.warn(
|
|
74049
|
-
|
|
74161
|
+
`Environment variable ${key} contains a CloudFormation intrinsic and was dropped. Override it with --env-vars (e.g. {"${lambda.logicalId}":{"${key}":"<literal>"}}) or pass --from-state to recover deployed values.`
|
|
74050
74162
|
);
|
|
74051
74163
|
}
|
|
74052
|
-
|
|
74053
|
-
|
|
74054
|
-
|
|
74055
|
-
|
|
74056
|
-
|
|
74057
|
-
|
|
74058
|
-
|
|
74059
|
-
|
|
74060
|
-
|
|
74061
|
-
|
|
74062
|
-
|
|
74063
|
-
|
|
74064
|
-
|
|
74065
|
-
|
|
74066
|
-
|
|
74067
|
-
|
|
74068
|
-
|
|
74069
|
-
|
|
74070
|
-
|
|
74071
|
-
|
|
74072
|
-
|
|
74073
|
-
}
|
|
74074
|
-
|
|
74075
|
-
|
|
74076
|
-
|
|
74164
|
+
if (options.fromState && !options.assumeRole && stateForRoleHint) {
|
|
74165
|
+
suggestAssumeRoleFromState(stateForRoleHint, lambda.logicalId);
|
|
74166
|
+
}
|
|
74167
|
+
const event = await readEvent(options);
|
|
74168
|
+
const dockerEnv = {
|
|
74169
|
+
AWS_LAMBDA_FUNCTION_NAME: lambda.logicalId,
|
|
74170
|
+
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: String(lambda.memoryMb),
|
|
74171
|
+
AWS_LAMBDA_FUNCTION_TIMEOUT: String(lambda.timeoutSec),
|
|
74172
|
+
AWS_LAMBDA_FUNCTION_VERSION: "$LATEST",
|
|
74173
|
+
AWS_LAMBDA_LOG_GROUP_NAME: `/aws/lambda/${lambda.logicalId}`,
|
|
74174
|
+
AWS_LAMBDA_LOG_STREAM_NAME: "local",
|
|
74175
|
+
...envResult.resolved
|
|
74176
|
+
};
|
|
74177
|
+
if (options.assumeRole) {
|
|
74178
|
+
const stsRegion = options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"];
|
|
74179
|
+
const creds = await assumeLambdaExecutionRole2(options.assumeRole, stsRegion);
|
|
74180
|
+
dockerEnv["AWS_ACCESS_KEY_ID"] = creds.accessKeyId;
|
|
74181
|
+
dockerEnv["AWS_SECRET_ACCESS_KEY"] = creds.secretAccessKey;
|
|
74182
|
+
dockerEnv["AWS_SESSION_TOKEN"] = creds.sessionToken;
|
|
74183
|
+
if (stsRegion)
|
|
74184
|
+
dockerEnv["AWS_REGION"] = stsRegion;
|
|
74185
|
+
} else {
|
|
74186
|
+
forwardAwsEnv2(dockerEnv);
|
|
74187
|
+
}
|
|
74188
|
+
let debugPort;
|
|
74189
|
+
if (options.debugPort) {
|
|
74190
|
+
debugPort = Number(options.debugPort);
|
|
74191
|
+
if (!Number.isInteger(debugPort) || debugPort <= 0 || debugPort > 65535) {
|
|
74192
|
+
throw new Error(`--debug-port must be an integer in 1..65535, got '${options.debugPort}'`);
|
|
74193
|
+
}
|
|
74194
|
+
dockerEnv["NODE_OPTIONS"] = `--inspect-brk=0.0.0.0:${debugPort}`;
|
|
74195
|
+
if (lambda.kind === "image") {
|
|
74196
|
+
logger.warn(
|
|
74197
|
+
"--debug-port sets NODE_OPTIONS unconditionally on container Lambdas. If the image's runtime is not Node.js, this flag is a no-op."
|
|
74198
|
+
);
|
|
74199
|
+
}
|
|
74200
|
+
}
|
|
74201
|
+
const hostPort = await pickFreePort();
|
|
74202
|
+
const containerHost = options.containerHost;
|
|
74203
|
+
if (lambda.layers.length > 0) {
|
|
74204
|
+
logger.info(
|
|
74205
|
+
`Mounting ${lambda.layers.length} Lambda layer${lambda.layers.length === 1 ? "" : "s"} at /opt`
|
|
74206
|
+
);
|
|
74207
|
+
}
|
|
74208
|
+
logger.info(`Starting container (image=${imagePlan.image}, port=${hostPort})...`);
|
|
74209
|
+
containerId = await runDetached({
|
|
74210
|
+
image: imagePlan.image,
|
|
74211
|
+
mounts: imagePlan.mounts,
|
|
74212
|
+
extraMounts: imagePlan.extraMounts,
|
|
74213
|
+
env: dockerEnv,
|
|
74214
|
+
cmd: imagePlan.cmd,
|
|
74215
|
+
hostPort,
|
|
74216
|
+
host: containerHost,
|
|
74217
|
+
...debugPort !== void 0 && { debugPort },
|
|
74218
|
+
...imagePlan.platform !== void 0 && { platform: imagePlan.platform },
|
|
74219
|
+
...imagePlan.entryPoint !== void 0 && { entryPoint: imagePlan.entryPoint },
|
|
74220
|
+
...imagePlan.workingDir !== void 0 && { workingDir: imagePlan.workingDir }
|
|
74221
|
+
});
|
|
74222
|
+
stopLogs = streamLogs(containerId);
|
|
74223
|
+
sigintHandler = () => {
|
|
74224
|
+
void cleanup().then(() => {
|
|
74225
|
+
process.exit(130);
|
|
74226
|
+
});
|
|
74227
|
+
};
|
|
74228
|
+
process.on("SIGINT", sigintHandler);
|
|
74077
74229
|
await waitForRieReady(containerHost, hostPort, 5e3);
|
|
74078
74230
|
const invokeTimeoutMs = Math.max(3e4, lambda.timeoutSec * 2 * 1e3);
|
|
74079
74231
|
const result = await invokeRie(containerHost, hostPort, event, invokeTimeoutMs);
|
|
@@ -74081,18 +74233,9 @@ async function localInvokeCommand(target, options) {
|
|
|
74081
74233
|
process.stdout.write(`${result.raw}
|
|
74082
74234
|
`);
|
|
74083
74235
|
} finally {
|
|
74084
|
-
|
|
74085
|
-
|
|
74086
|
-
await
|
|
74087
|
-
if (imagePlan.inlineTmpDir) {
|
|
74088
|
-
try {
|
|
74089
|
-
rmSync3(imagePlan.inlineTmpDir, { recursive: true, force: true });
|
|
74090
|
-
} catch (err) {
|
|
74091
|
-
getLogger().debug(
|
|
74092
|
-
`Failed to remove inline-code tmpdir ${imagePlan.inlineTmpDir}: ${err instanceof Error ? err.message : String(err)}`
|
|
74093
|
-
);
|
|
74094
|
-
}
|
|
74095
|
-
}
|
|
74236
|
+
if (sigintHandler)
|
|
74237
|
+
process.off("SIGINT", sigintHandler);
|
|
74238
|
+
await cleanup();
|
|
74096
74239
|
}
|
|
74097
74240
|
}
|
|
74098
74241
|
async function resolveImagePlan(lambda, options) {
|
|
@@ -74114,11 +74257,31 @@ async function resolveZipImagePlan(lambda, options) {
|
|
|
74114
74257
|
}
|
|
74115
74258
|
const image = resolveRuntimeImage(lambda.runtime);
|
|
74116
74259
|
await pullImage(image, options.pull === false);
|
|
74260
|
+
const layerPlan = materializeLambdaLayers2(lambda.layers);
|
|
74117
74261
|
return {
|
|
74118
74262
|
image,
|
|
74119
74263
|
mounts: [{ hostPath: codeDir, containerPath: "/var/task", readOnly: true }],
|
|
74264
|
+
extraMounts: layerPlan.mount ? [layerPlan.mount] : [],
|
|
74120
74265
|
cmd: [lambda.handler],
|
|
74121
|
-
...inlineTmpDir !== void 0 && { inlineTmpDir }
|
|
74266
|
+
...inlineTmpDir !== void 0 && { inlineTmpDir },
|
|
74267
|
+
...layerPlan.tmpDir !== void 0 && { layersTmpDir: layerPlan.tmpDir }
|
|
74268
|
+
};
|
|
74269
|
+
}
|
|
74270
|
+
function materializeLambdaLayers2(layers) {
|
|
74271
|
+
if (layers.length === 0)
|
|
74272
|
+
return {};
|
|
74273
|
+
if (layers.length === 1) {
|
|
74274
|
+
return {
|
|
74275
|
+
mount: { hostPath: layers[0].assetPath, containerPath: "/opt", readOnly: true }
|
|
74276
|
+
};
|
|
74277
|
+
}
|
|
74278
|
+
const tmpDir = mkdtempSync3(path2.join(tmpdir3(), "cdkd-local-invoke-layers-"));
|
|
74279
|
+
for (const layer of layers) {
|
|
74280
|
+
cpSync2(layer.assetPath, tmpDir, { recursive: true, force: true });
|
|
74281
|
+
}
|
|
74282
|
+
return {
|
|
74283
|
+
mount: { hostPath: tmpDir, containerPath: "/opt", readOnly: true },
|
|
74284
|
+
tmpDir
|
|
74122
74285
|
};
|
|
74123
74286
|
}
|
|
74124
74287
|
async function resolveContainerImagePlan(lambda, options) {
|
|
@@ -74151,6 +74314,7 @@ async function resolveContainerImagePlan(lambda, options) {
|
|
|
74151
74314
|
return {
|
|
74152
74315
|
image: imageRef,
|
|
74153
74316
|
mounts: [],
|
|
74317
|
+
extraMounts: [],
|
|
74154
74318
|
cmd: lambda.imageConfig.command ?? [],
|
|
74155
74319
|
platform,
|
|
74156
74320
|
...lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && {
|
|
@@ -74469,7 +74633,7 @@ function reorderArgs(argv) {
|
|
|
74469
74633
|
}
|
|
74470
74634
|
async function main() {
|
|
74471
74635
|
const program = new Command16();
|
|
74472
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
74636
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.74.0");
|
|
74473
74637
|
program.addCommand(createBootstrapCommand());
|
|
74474
74638
|
program.addCommand(createSynthCommand());
|
|
74475
74639
|
program.addCommand(createListCommand());
|