Skip to content

Commit

Permalink
[samp-local] - cherry pick functions to debug
Browse files Browse the repository at this point in the history
  • Loading branch information
ljacobsson committed Jul 28, 2023
1 parent 4cfa952 commit a67b924
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 37 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "samp-cli",
"version": "1.0.26",
"version": "1.0.27",
"description": "CLI tool for extended productivity with AWS Serverless Application Model (SAM)",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/commands/local/lib/cleanup.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ if (fs.existsSync(process.cwd() + "/.samp-out")) {
console.log("Removing .samp-out directory");
fs.rmSync(process.cwd() + "/.samp-out", { recursive: true, force: true });
}
if (!conf.envConfig) process.exit(0);
if (!conf || !conf.envConfig) process.exit(0);
const stackName = conf.envConfig.stack_name;
const region = conf.envConfig.region;
const profile = conf.envConfig.profile;
Expand Down
34 changes: 15 additions & 19 deletions src/commands/local/lib/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,32 @@ import getMac from 'getmac';
import archiver from 'archiver';
import { fileURLToPath } from 'url';
import { fork, spawnSync } from 'child_process';
import samConfigParser from '../../../shared/samConfigParser.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const mac = getMac();
let envConfig = {};
let config = {};
let configEnv = 'default';
let targetConfig = {};
if (fs.existsSync(`samconfig.toml`)) {
config = ini.parse(fs.readFileSync(`samconfig.toml`, 'utf-8'));
configEnv = process.env.configEnv || 'default';
envConfig = config[configEnv].deploy.parameters;
envConfig.stack_name = envConfig.stack_name || config[configEnv].global.parameters.stack_name
targetConfig = samConfigParser.parse();
console.log(targetConfig);
} else {
envConfig = {
targetConfig = {
stack_name: process.env.SAMP_STACKNAME,
region: process.env.SAMP_REGION,
profile: process.env.SAMP_PROFILE
}
}
console.log(`Using profile: ${envConfig.profile || 'default'}`);
console.log(`Using profile: ${targetConfig.profile || 'default'}`);

let credentials;
try {
credentials = await fromSSO({ profile: envConfig.profile || 'default' })();
credentials = await fromSSO({ profile: targetConfig.profile || 'default' })();
} catch (e) {
}

const stsClient = new STSClient({ region: envConfig.region, credentials });
const stsClient = new STSClient({ region: targetConfig.region, credentials });
const accountId = (await stsClient.send(new GetCallerIdentityCommand({}))).Account;
const iotClient = new IoTClient({ region: envConfig.region, credentials });
const iotClient = new IoTClient({ region: targetConfig.region, credentials });
const timer = new Date().getTime();
let certData, endpoint, stack, functions, template;
const policyName = "lambda-debug-policy";
Expand Down Expand Up @@ -135,13 +132,13 @@ if (!fs.existsSync(".lambda-debug")) {
// Load your AWS IoT certificates
certData.ca = fs.readFileSync(path.join(__dirname, 'AmazonRootCA1.pem')).toString(); // Download this from Amazon's website
const cfnClient = new CloudFormationClient({
region: envConfig.region,
region: targetConfig.region,
credentials: credentials
});

console.log(`Loading necessary resources...`);

const stackName = envConfig.stack_name;
const stackName = targetConfig.stack_name;

template = yamlParse(fs.readFileSync(findSAMTemplateFile('.')).toString());
stack = await cfnClient.send(new ListStackResourcesCommand({ StackName: stackName }));
Expand All @@ -162,11 +159,11 @@ if (!fs.existsSync(".lambda-debug")) {
const excludeFunctions = process.env.excludeFunctions.split(',').map(f => f.trim());
functions = functions.filter(f => !excludeFunctions.includes(f));
}
fs.writeFileSync(".lambda-debug", JSON.stringify({ functions, template, configEnv, envConfig, accountId }));
fs.writeFileSync(".lambda-debug", JSON.stringify({ functions, template, envConfig: targetConfig, accountId }));

// replace function code with stub-local.js
const lambdaClient = new LambdaClient({
region: envConfig.region,
region: targetConfig.region,
credentials
});
if (!fs.existsSync(zipFilePath)) {
Expand Down Expand Up @@ -263,7 +260,6 @@ const connectOptions = {
keepalive: 60,
client_id: 'mqtt-client-' + Math.floor((Math.random() * 1000000) + 1),
protocol: 'mqtt',
reconnectPeriod: 1000,
clean: true,
host: endpoint,
debug: true,
Expand All @@ -277,7 +273,7 @@ client.on('error', function (err) {

client.on('connect', async function () {
console.log('Ready for requests...')
fs.writeFileSync(".lambda-debug", JSON.stringify({ stack, endpoint, certData, functions, template, configEnv, envConfig, accountId }));
fs.writeFileSync(".lambda-debug", JSON.stringify({ stack, endpoint, certData, functions, template, envConfig: targetConfig, accountId }));
client.subscribe('lambda-debug/event/' + mac);
});

Expand Down Expand Up @@ -313,7 +309,7 @@ client.on('close', function () {
console.log('Disconnected from live debug session');
});

if (!envConfig.childProcess) {
if (!targetConfig.childProcess) {
process.on('SIGINT', async function () {
console.log("Caught interrupt signal");
process.exit();
Expand Down
86 changes: 70 additions & 16 deletions src/commands/local/local.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ const settingsUtil = require('../../shared/settingsUtil');
const glob = require('glob');
const { findConstructs } = require('./cdk-construct-finder');
const commentJson = require('comment-json')
const { fromSSO } = require('@aws-sdk/credential-provider-sso');
const { CloudFormationClient, ListStackResourcesCommand } = require('@aws-sdk/client-cloudformation');
const samConfigParser = require('../../shared/samConfigParser');

function setEnvVars(cmd) {
process.env.SAMP_PROFILE = cmd.profile || process.env.AWS_PROFILE;
process.env.SAMP_REGION = cmd.region || process.env.AWS_REGION;
Expand All @@ -32,8 +36,7 @@ async function run(cmd) {
}

if (cmd.debug) {
await setupDebug();
console.log("Debug setup complete. You can now hit F5 to start debugging");
await setupDebug(cmd);
return;
}

Expand Down Expand Up @@ -121,9 +124,14 @@ function print(data) {
}
}

async function setupDebug() {
async function setupDebug(cmd) {
let credentials;
let targetConfig = samConfigParser.parse();
let args = ["local"];
let stack = null;
let stack = cmd.stackName || targetConfig.stack_name;
let region = cmd.region || targetConfig.region;
let profile = cmd.profile || targetConfig.profile;
const pwd = process.cwd();
if (fs.existsSync(`cdk.json`)) {
const constructs = findConstructs();
constructs.push("Enter manually");
Expand All @@ -136,17 +144,60 @@ async function setupDebug() {
stacks.push("Enter manually");
stack = await inputUtil.autocomplete("What's the name of the deployed stack?", stacks);
if (stack === "Enter manually") {
stack = await inputUtil.autocomplete("What's the name of the deployed stack?");
stack = await inputUtil.text("What's the name of the deployed stack?");
}
const region = await inputUtil.text("What's the region of the deployed stack?", process.env.AWS_REGION || process.env.DEFAULT_AWS_REGION || "us-east-1");
const profile = await inputUtil.text("AWS profile", process.env.AWS_PROFILE || "default");
const regions = [
"ap-south-1",
"eu-north-1",
"eu-west-3",
"eu-west-2",
"eu-west-1",
"ap-northeast-3",
"ap-northeast-2",
"ap-northeast-1",
"ca-central-1",
"sa-east-1",
"ap-southeast-1",
"ap-southeast-2",
"eu-central-1",
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2"
];
region = region || await inputUtil.autocomplete("What's the region of the deployed stack?", regions);
profile = profile || await inputUtil.text("AWS profile", process.env.AWS_PROFILE || "default");
args.push("-s", stack, "--region", region, "--profile", profile, "--construct", construct);
}

const pwd = process.cwd();
try {
credentials = await fromSSO({ profile: profile || 'default' })();
} catch (e) {
}

const cloudFormation = new CloudFormationClient({ credentials, region });

const functions = [];
let token;
do {
try {
const response = await cloudFormation.send(new ListStackResourcesCommand({ StackName: stack, NextToken: token }));
functions.push(...response.StackResourceSummaries.filter(r => r.ResourceType === "AWS::Lambda::Function"));
token = response.NextToken;
} catch (e) {
console.log(`Failed to list stack resources for stack '${stack}' in '${region}' using profile '${profile}'.`, e.message);
process.exit(1);
}
} while (token);

const functionNames = functions.map(f => f.LogicalResourceId);
const selectedFunctions = await inputUtil.checkbox("Select functions to debug", functionNames);
const selectedFunctionsText = selectedFunctions.length === functionNames.length ? "all functions" : selectedFunctions.join(",");
const name = await inputUtil.text("Enter a name for the configuration", "Debug " + selectedFunctionsText);
args.push("--functions", selectedFunctions.join(","));

let launchJson;
if (fs.existsSync(`${pwd}/.vscode/launch.json`)) {
console.log("launch.json already exists");
let fileContent = fs.readFileSync(`${pwd}/.vscode/launch.json`, "utf8");
launchJson = commentJson.parse(fileContent);
} else {
Expand All @@ -155,16 +206,15 @@ async function setupDebug() {
"configurations": []
};
}
const suffix = stack ? `-${stack}` : "";
const existingConfig = launchJson.configurations.find(c => c.name === "Debug Lambda Functions" + suffix);
const existingConfig = launchJson.configurations.find(c => c.name === name);
if (existingConfig) {
console.log("Debug config already exists");
} else {

launchJson.configurations.push({
type: "node",
request: "launch",
name: "Debug Lambda Functions" + suffix,
name,
runtimeExecutable: "samp",
args,
env: {
Expand All @@ -184,12 +234,9 @@ async function setupDebug() {
}
let tasksJson;
if (fs.existsSync(`${pwd}/.vscode/tasks.json`)) {
console.log("tasks.json already exists");
tasksJson = commentJson.parse(fs.readFileSync(`${pwd}/.vscode/tasks.json`, "utf8"));
const existingTask = tasksJson.tasks.find(t => t.label === "samp-local-cleanup");
if (existingTask) {
console.log("Task already exists");
} else {
if (!existingTask) {
tasksJson.tasks.push(task);
}
} else {
Expand All @@ -203,6 +250,13 @@ async function setupDebug() {
}
fs.writeFileSync(`${pwd}/.vscode/launch.json`, commentJson.stringify(launchJson, null, 2));
fs.writeFileSync(`${pwd}/.vscode/tasks.json`, commentJson.stringify(tasksJson, null, 2));

if (launchJson.configurations.length === 1) {
console.log("Debug setup complete. You can now hit F5 to start debugging");
} else {
console.log("Debug setup complete. You can now select the debug configuration from the dropdown and hit F5 to start debugging");
}

}

async function warn() {
Expand Down

0 comments on commit a67b924

Please sign in to comment.