Skip to content

Commit 2d1af95

Browse files
Merge pull request #142 from ServerlessLife/feat/support-lambdas-in-nested-stacks-in-cdk
feat: Support nested stacks in aws-cdk #139
2 parents 7d28806 + ef679da commit 2d1af95

32 files changed

+842
-21
lines changed

.vscode/launch.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,26 @@
6969
"type": "node",
7070
"cwd": "${workspaceRoot}/test/cdk-esm"
7171
},
72+
{
73+
"name": "LLDebugger - CDK nested",
74+
"program": "${workspaceRoot}/node_modules/tsx/dist/cli.mjs",
75+
"args": ["../../src/lldebugger.ts", "-c environment=test"],
76+
"request": "launch",
77+
"skipFiles": ["<node_internals>/**"],
78+
"console": "integratedTerminal",
79+
"type": "node",
80+
"cwd": "${workspaceRoot}/test/cdk-nested"
81+
},
82+
{
83+
"name": "LLDebugger - CDK nested - observability",
84+
"program": "${workspaceRoot}/node_modules/tsx/dist/cli.mjs",
85+
"args": ["../../src/lldebugger.ts", "-c environment=test", "-o"],
86+
"request": "launch",
87+
"skipFiles": ["<node_internals>/**"],
88+
"console": "integratedTerminal",
89+
"type": "node",
90+
"cwd": "${workspaceRoot}/test/cdk-nested"
91+
},
7292
{
7393
"name": "LLDebugger - SLS basic",
7494
"program": "${workspaceRoot}/node_modules/tsx/dist/cli.mjs",

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ If you have a new feature idea, please create and issue.
353353

354354
- [Ben Moses](https://github.com/benjymoses)
355355
- [Kristian Dreher](https://www.linkedin.com/in/kristiandreher)
356+
- [Hugo Lewenhaupt](https://www.linkedin.com/in/hugo-lewenhaupt-84751289)
356357
- [Roger Chi](https://rogerchi.com/)
357358
- [Sebastian / avocadomaster](https://github.com/avocadomaster)
358359
- [Sebastian Bille](https://blog.sebastianbille.com)

package-lock.json

Lines changed: 30 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
"test": "npm run build && RUN_TEST_FROM_CLI=true vitest run && RUN_TEST_FROM_CLI=true OBSERVABLE_MODE=true vitest run",
5353
"test-cdk-basic": "npm run build && RUN_TEST_FROM_CLI=true vitest run test/cdk-basic.test.ts",
5454
"test-cdk-basic-observable": "npm run build && RUN_TEST_FROM_CLI=true OBSERVABLE_MODE=true vitest run test/cdk-basic.test.ts",
55+
"test-cdk-nested": "npm run build && RUN_TEST_FROM_CLI=true vitest run test/cdk-nested.test.ts",
56+
"test-cdk-nested-observable": "npm run build && RUN_TEST_FROM_CLI=true OBSERVABLE_MODE=true vitest run test/cdk-nested.test.ts",
5557
"test-cdk-esm": "npm run build && RUN_TEST_FROM_CLI=true vitest run test/cdk-esm.test.ts",
5658
"test-cdk-esm-observable": "npm run build && RUN_TEST_FROM_CLI=true OBSERVABLE_MODE=true vitest run test/cdk-esm.test.ts",
5759
"test-sls-basic": "npm run build && RUN_TEST_FROM_CLI=true vitest run test/sls-basic.test.ts",
@@ -148,6 +150,7 @@
148150
"src/extension/*",
149151
"test",
150152
"test/cdk-basic",
153+
"test/cdk-nested",
151154
"test/cdk-esm",
152155
"test/cdk-config",
153156
"test/sls-basic",

src/cloudFormation.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,24 +139,48 @@ async function getLambdasInStack(
139139
Array<{
140140
lambdaName: string;
141141
logicalId: string;
142+
stackName: string;
142143
}>
143144
> {
144145
const response = await getCloudFormationResources(
145146
stackName,
146147
awsConfiguration,
147148
);
149+
148150
const lambdaResources = response?.filter(
149151
(resource) => resource.ResourceType === 'AWS::Lambda::Function',
150152
);
151153

152-
return (
154+
const nestedStacks = response?.filter(
155+
(resource) => resource.ResourceType === 'AWS::CloudFormation::Stack',
156+
);
157+
158+
const lambdas =
153159
lambdaResources?.map((resource) => {
154160
return {
155161
lambdaName: resource.PhysicalResourceId!,
156162
logicalId: resource.LogicalResourceId!,
163+
stackName: stackName,
157164
};
158-
}) ?? []
165+
}) ?? [];
166+
167+
const lambdasInNestedStacks = await Promise.all(
168+
(nestedStacks ?? []).map(async (nestedStack) => {
169+
if (!nestedStack.PhysicalResourceId) return [];
170+
171+
const lambdasInNestedStack = await getLambdasInStack(
172+
nestedStack.PhysicalResourceId,
173+
awsConfiguration,
174+
);
175+
176+
return lambdasInNestedStack;
177+
}),
159178
);
179+
180+
const flattenedLambdasInNestedStacks = lambdasInNestedStacks.flat();
181+
182+
const allLambdas = [...lambdas, ...flattenedLambdasInNestedStacks];
183+
return allLambdas;
160184
}
161185

162186
export const CloudFormation = {

src/frameworks/cdkFramework.ts

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,50 +70,67 @@ export class CdkFramework implements IFramework {
7070
JSON.stringify(lambdasInCdk, null, 2),
7171
);
7272

73-
//get all stack names
74-
const stackNames = [
75-
...new Set( // unique
76-
lambdasInCdk.map((lambda) => {
77-
return lambda.stackName;
78-
}),
79-
),
80-
];
73+
const cdkTokenRegex = /^\${Token\[TOKEN\.\d+\]}$/;
74+
75+
const stackNamesDuplicated = lambdasInCdk.map((lambda) => {
76+
if (cdkTokenRegex.test(lambda.stackName)) {
77+
return lambda.rootStackName;
78+
} else {
79+
return lambda.stackName;
80+
}
81+
});
82+
83+
const stackNames = [...new Set(stackNamesDuplicated)];
84+
8185
Logger.verbose(
8286
`[CDK] Found the following stacks in CDK: ${stackNames.join(', ')}`,
8387
);
8488

8589
const lambdasDeployed = (
8690
await Promise.all(
8791
stackNames.map(async (stackName) => {
88-
const lambdasInStackPromise = CloudFormation.getLambdasInStack(
92+
const lambdasInStack = await CloudFormation.getLambdasInStack(
8993
stackName,
9094
awsConfiguration,
9195
);
92-
const lambdasMetadataPromise =
93-
this.getLambdaCdkPathFromTemplateMetadata(
94-
stackName,
95-
awsConfiguration,
96-
);
9796

98-
const lambdasInStack = await lambdasInStackPromise;
97+
const stackAndNestedStackNames = [
98+
...new Set(lambdasInStack.map((l) => l.stackName)),
99+
];
100+
101+
const lambdasMetadata = (
102+
await Promise.all(
103+
stackAndNestedStackNames.map((stackOrNestedStackName) =>
104+
this.getLambdaCdkPathFromTemplateMetadata(
105+
stackOrNestedStackName,
106+
awsConfiguration,
107+
),
108+
),
109+
)
110+
).flat();
111+
99112
Logger.verbose(
100113
`[CDK] Found Lambda functions in the stack ${stackName}:`,
101114
JSON.stringify(lambdasInStack, null, 2),
102115
);
103-
const lambdasMetadata = await lambdasMetadataPromise;
116+
104117
Logger.verbose(
105118
`[CDK] Found Lambda functions in the stack ${stackName} in the template metadata:`,
106119
JSON.stringify(lambdasMetadata, null, 2),
107120
);
108121

109-
return lambdasInStack.map((lambda) => {
122+
const lambdasPhysicalResourceIds = lambdasInStack.map((lambda) => {
110123
return {
111124
lambdaName: lambda.lambdaName,
112125
cdkPath: lambdasMetadata.find(
113-
(lm) => lm.logicalId === lambda.logicalId,
126+
(lm) =>
127+
lm.logicalId === lambda.logicalId &&
128+
lm.stackName === lambda.stackName,
114129
)?.cdkPath,
115130
};
116131
});
132+
133+
return lambdasPhysicalResourceIds;
117134
}),
118135
)
119136
).flat();
@@ -183,6 +200,7 @@ export class CdkFramework implements IFramework {
183200
Array<{
184201
logicalId: string;
185202
cdkPath: string;
203+
stackName: string;
186204
}>
187205
> {
188206
const cfTemplate = await CloudFormation.getCloudFormationStackTemplate(
@@ -200,8 +218,10 @@ export class CdkFramework implements IFramework {
200218
return {
201219
logicalId: key,
202220
cdkPath: resource.Metadata['aws:cdk:path'],
221+
stackName: stackName,
203222
};
204223
});
224+
205225
return lambdas;
206226
}
207227

@@ -308,9 +328,14 @@ export class CdkFramework implements IFramework {
308328
`;
309329
global.lambdas = global.lambdas ?? [];
310330
331+
let rootStack = this.stack;
332+
while (rootStack.nestedStackParent) {
333+
rootStack = rootStack.nestedStackParent;
334+
}
311335
const lambdaInfo = {
312336
//cdkPath: this.node.defaultChild?.node.path ?? this.node.path,
313337
stackName: this.stack.stackName,
338+
rootStackName: rootStack.stackName,
314339
codePath: props.entry,
315340
code: props.code,
316341
node: this.node,
@@ -320,6 +345,7 @@ export class CdkFramework implements IFramework {
320345
321346
// console.log("CDK INFRA: ", {
322347
// stackName: lambdaInfo.stackName,
348+
// rootStackName: lambdaInfo.rootStackName,
323349
// codePath: lambdaInfo.codePath,
324350
// code: lambdaInfo.code,
325351
// handler: lambdaInfo.handler,
@@ -487,6 +513,7 @@ export class CdkFramework implements IFramework {
487513
return {
488514
cdkPath: lambda.cdkPath,
489515
stackName: lambda.stackName,
516+
rootStackName: lambda.rootStackName,
490517
packageJsonPath,
491518
codePath: codePath,
492519
handler,
@@ -583,6 +610,7 @@ export class CdkFramework implements IFramework {
583610
return lambdas as {
584611
cdkPath: string;
585612
stackName: string;
613+
rootStackName: string;
586614
codePath?: string;
587615
code: {
588616
path?: string;

src/frameworks/cdkFrameworkWorker.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ parentPort.on('message', async (data) => {
2525
handler: lambda.handler,
2626
stackName: lambda.stackName,
2727
codePath: lambda.codePath,
28+
rootStackName: lambda.rootStackName,
2829
code: {
2930
path: lambda.code?.path,
3031
},

0 commit comments

Comments
 (0)