lambda-live-debugger
Version:
Debug Lambda functions locally like it is running in the cloud
137 lines (136 loc) • 4.93 kB
JavaScript
import { AwsCredentials } from './awsCredentials.mjs';
import { Logger } from './logger.mjs';
import * as yaml from 'yaml';
let cloudFormationClient;
const originalConsoleError = console.error;
/**
* Get CloudFormation stack template
* @param stackName
* @param awsConfiguration
* @returns
*/
async function getCloudFormationStackTemplate(stackName, awsConfiguration) {
const { GetTemplateCommand } = await import('@aws-sdk/client-cloudformation');
const command = new GetTemplateCommand({ StackName: stackName });
const cloudFormationClient = await getCloudFormationClient(awsConfiguration);
try {
const response = await cloudFormationClient.send(command);
if (!response.TemplateBody) {
throw new Error(`No template found for stack ${stackName}`);
}
let cfTemplate;
try {
cfTemplate = JSON.parse(response.TemplateBody);
}
catch (parseError) {
if (parseError.message.includes('is not valid JSON')) {
// If the template is not JSON, try parsing it as YAML
cfTemplate = yaml.parse(response.TemplateBody);
}
else {
throw parseError;
}
}
return cfTemplate;
}
catch (error) {
if (error.name === 'ValidationError') {
Logger.error(`Stack ${stackName} not found. Try specifying a region. Error: ${error.message}`, error);
return undefined;
}
else {
throw error;
}
}
}
/**
* Get CloudFormation client
* @param awsConfiguration
* @returns
*/
async function getCloudFormationClient(awsConfiguration) {
if (!cloudFormationClient) {
const { CloudFormationClient } = await import('@aws-sdk/client-cloudformation');
cloudFormationClient = new CloudFormationClient({
region: awsConfiguration.region,
credentials: AwsCredentials.getCredentialsProvider(awsConfiguration),
});
}
return cloudFormationClient;
}
/**
* Get CloudFormation resources
* @param stackName
* @param awsConfiguration
* @returns
*/
async function getCloudFormationResources(stackName, awsConfiguration) {
let ListStackResourcesCommand;
// temporary disable console.error because SAM framework outputs useless errors
try {
console.error = function () { };
const clientCloudFormation = await import('@aws-sdk/client-cloudformation');
ListStackResourcesCommand = clientCloudFormation.ListStackResourcesCommand;
}
finally {
console.error = originalConsoleError;
}
const cloudFormationClient = await getCloudFormationClient(awsConfiguration);
try {
let nextToken = undefined;
const items = [];
do {
const command = new ListStackResourcesCommand({
StackName: stackName,
NextToken: nextToken,
});
const response = await cloudFormationClient.send(command);
if (response.StackResourceSummaries) {
items.push(...response.StackResourceSummaries);
}
nextToken = response.NextToken;
} while (nextToken);
return items;
}
catch (error) {
if (error.name === 'ValidationError') {
Logger.error(`Stack ${stackName} not found. Try specifying a region. Error: ${error.message}`, error);
return undefined;
}
else {
throw error;
}
}
}
/**
* Get Lambdas in stack
* @param stackName
* @param awsConfiguration
* @returns
*/
async function getLambdasInStack(stackName, awsConfiguration, stackLogicalId) {
const response = await getCloudFormationResources(stackName, awsConfiguration);
const lambdaResources = response?.filter((resource) => resource.ResourceType === 'AWS::Lambda::Function');
const nestedStacks = response?.filter((resource) => resource.ResourceType === 'AWS::CloudFormation::Stack');
const lambdas = lambdaResources?.map((resource) => {
return {
lambdaName: resource.PhysicalResourceId,
logicalId: resource.LogicalResourceId,
stackName: stackName,
stackLogicalId: stackLogicalId ?? stackName,
};
}) ?? [];
const lambdasInNestedStacks = await Promise.all((nestedStacks ?? []).map(async (nestedStack) => {
if (!nestedStack.PhysicalResourceId)
return [];
const lambdasInNestedStack = await getLambdasInStack(nestedStack.PhysicalResourceId, awsConfiguration, nestedStack.LogicalResourceId);
return lambdasInNestedStack;
}));
const flattenedLambdasInNestedStacks = lambdasInNestedStacks.flat();
const allLambdas = [...lambdas, ...flattenedLambdasInNestedStacks];
return allLambdas;
}
export const CloudFormation = {
getCloudFormationStackTemplate,
getLambdasInStack,
};