Skip to content

Commit

Permalink
Command line parameters, AWS credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
ServerlessLife committed May 4, 2024
1 parent 6ef9748 commit 686c21d
Show file tree
Hide file tree
Showing 8 changed files with 1,423 additions and 339 deletions.
1,606 changes: 1,304 additions & 302 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
"@aws-sdk/client-iot-data-plane": "^3.523.0",
"@aws-sdk/client-lambda": "^3.518.0",
"@aws-sdk/client-s3": "^3.515.0",
"@aws-sdk/credential-providers": "^3.515.0",
"chokidar": "^3.6.0",
"esbuild": "^0.20.1",
"@types/aws-iot-device-sdk": "^2.2.8",
"aws-iot-device-sdk": "^2.2.13",
"node-machine-id": "^1.1.12"
"node-machine-id": "^1.1.12",
"commander": "^12.0.0"
},
"peerDependencies": {
"aws-cdk": "^2",
Expand Down
12 changes: 12 additions & 0 deletions src/awsCredentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export * as AwsCredentials from "./awsCredentials.js";
import { fromNodeProviderChain } from "@aws-sdk/credential-providers";
import * as LlDebugger from "./lldebugger.js";
import type { AwsCredentialIdentityProvider } from "@smithy/types";

export function getCredentialsProvider(): AwsCredentialIdentityProvider {
return fromNodeProviderChain({
clientConfig: { region: LlDebugger.argOptions.region },
profile: LlDebugger.argOptions.profile,
roleArn: LlDebugger.argOptions.role,
});
}
6 changes: 5 additions & 1 deletion src/cdkResourcesDiscovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { outputFolder } from "./constants.js";
import type { BundlingOptions } from "aws-cdk-lib/aws-lambda-nodejs";
import { BundlingType } from "./functionProps.js";
import { findAboveFolderWithAFile } from "./findAboveFolderWithAFile.js";
import { LlDebugger } from "./lldebugger.js";

// this is global variable to store the data from the CDK code once it is executed
declare global {
Expand Down Expand Up @@ -342,18 +343,21 @@ async function getLambdasDataFromCdkByCompilingAndRunning(
async function getCdkContext(cdkConfigPath: string) {
// get CDK context from the command line
// get all "-c" and "--context" arguments from the command line

const contextArgs = process.argv.filter(
(arg) => arg.startsWith("-c") ?? arg.startsWith("--context")
);

//const contextArgs = LlDebugger.argOptions.context;

//parameter can be like:
// -c key=value
// -c=key=value
// --context key=value
// --context=key=value
// extract the key and value from the parameter
// take into account that first seperator can be "=" or " "
const contextFromCli = contextArgs.reduce((acc, arg) => {
const contextFromCli = contextArgs?.reduce((acc, arg) => {
const [key, value] = arg.split(/=| /).slice(1);
(acc as any)[key] = value;
return acc;
Expand Down
15 changes: 0 additions & 15 deletions src/getIoTEndpoint.ts

This file was deleted.

46 changes: 32 additions & 14 deletions src/infraDeploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,27 @@ import { getDebuggerId, getVersion, moduleDirname } from "./lldebugger.js";
import * as Functions from "./functions.js";
import fs from "fs/promises";
import * as path from "path";
import * as AwsCredentials from "./awsCredentials.js";

const lambdaClient = new LambdaClient({});
const iamClient = new IAMClient({});
let lambdaClient: LambdaClient | undefined;
function getLambdaClient(): LambdaClient {
if (!lambdaClient) {
lambdaClient = new LambdaClient({
credentials: AwsCredentials.getCredentialsProvider(),
});
}
return lambdaClient;
}

let iamClient: IAMClient | undefined;
function getIAMClient(): IAMClient {
if (!iamClient) {
iamClient = new IAMClient({
credentials: AwsCredentials.getCredentialsProvider(),
});
}
return iamClient;
}

const inlinePolicyName = "LambdaLiveDebuggerPolicy";
const layerName = "LambdaLiveDebugger"; // Replace with your layer name
Expand All @@ -39,7 +57,7 @@ async function findExistingLayer(layerName: string) {
LayerName: layerName,
});

const response = await lambdaClient.send(listLayerVersionsCommand);
const response = await getLambdaClient().send(listLayerVersionsCommand);
if (response.LayerVersions && response.LayerVersions.length > 0) {
return response.LayerVersions[0];
}
Expand Down Expand Up @@ -84,7 +102,7 @@ async function deployLayer() {
LayerName: layerName,
VersionNumber: existingLayer.Version,
});
await lambdaClient.send(deleteLayerVersionCommand);
await getLambdaClient().send(deleteLayerVersionCommand);
// console.log("Layer already deployed.");
// return existingLayer.LayerVersionArn;
}
Expand All @@ -103,7 +121,7 @@ async function deployLayer() {
CompatibleRuntimes: ["nodejs18.x", "nodejs20.x"],
});

const response = await lambdaClient.send(publishLayerVersionCommand);
const response = await getLambdaClient().send(publishLayerVersionCommand);

if (!response.LayerVersionArn) {
throw new Error("Failed to retrieve the layer version ARN");
Expand All @@ -116,7 +134,7 @@ async function deployLayer() {
async function deleteLayer() {
let nextMarker: string | undefined;
do {
const layers = await lambdaClient.send(
const layers = await getLambdaClient().send(
new ListLayersCommand({
Marker: nextMarker,
MaxItems: 10,
Expand All @@ -138,7 +156,7 @@ async function deleteLayer() {
async function deleteAllVersionsOfLayer(layerArn: string): Promise<void> {
let nextMarker: string | undefined;
do {
const versions = await lambdaClient.send(
const versions = await getLambdaClient().send(
new ListLayerVersionsCommand({
LayerName: layerArn,
Marker: nextMarker,
Expand All @@ -159,7 +177,7 @@ async function deleteLayerVersion(
versionNumber: number
): Promise<void> {
try {
await lambdaClient.send(
await getLambdaClient().send(
new DeleteLayerVersionCommand({
LayerName: layerArn,
VersionNumber: versionNumber,
Expand Down Expand Up @@ -217,7 +235,7 @@ async function removeLayerFromFunction(functionName: string) {
Timeout: initialTimeout,
});

lambdaClient.send(updateFunctionConfigurationCommand);
getLambdaClient().send(updateFunctionConfigurationCommand);

console.log(`Function configuration cleared ${functionName}`);
} else {
Expand All @@ -226,7 +244,7 @@ async function removeLayerFromFunction(functionName: string) {
}

async function getFunctionCongfiguration(functionName: string) {
const getFunctionResponse = await lambdaClient.send(
const getFunctionResponse = await getLambdaClient().send(
new GetFunctionCommand({
FunctionName: functionName,
})
Expand Down Expand Up @@ -313,7 +331,7 @@ async function attachLayerToFunction(
Timeout: 300, // Increase the timeout to 5 minutes
});

lambdaClient.send(updateFunctionConfigurationCommand);
getLambdaClient().send(updateFunctionConfigurationCommand);

console.log(`Function configuration updated for ${functionName}`);
} else {
Expand All @@ -336,7 +354,7 @@ function getDdlEnvironmentVarables(

async function addPolicyToLambdaRole(functionName: string) {
// Retrieve the Lambda function's execution role ARN
const getFunctionResponse = await lambdaClient.send(
const getFunctionResponse = await getLambdaClient().send(
new GetFunctionCommand({
FunctionName: functionName,
})
Expand Down Expand Up @@ -373,7 +391,7 @@ async function addPolicyToLambdaRole(functionName: string) {

if (addPolicy) {
// add inline policy to the role using PutRolePolicyCommand
await iamClient.send(
await getIAMClient().send(
new PutRolePolicyCommand({
RoleName: roleName,
PolicyName: inlinePolicyName,
Expand All @@ -385,7 +403,7 @@ async function addPolicyToLambdaRole(functionName: string) {

async function getPolicyDocument(roleName: string) {
try {
const policy = await iamClient.send(
const policy = await getIAMClient().send(
new GetRolePolicyCommand({
RoleName: roleName,
PolicyName: inlinePolicyName,
Expand Down
35 changes: 33 additions & 2 deletions src/ioTService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
export * as IoTService from "./ioTService.js";
import * as iot from "aws-iot-device-sdk";
import { splitMessageToChunks, MessageChunk } from "./splitIoTMessage.js";
import { getIoTEndpoint } from "./getIoTEndpoint.js";
import { IoTClient, DescribeEndpointCommand } from "@aws-sdk/client-iot";
import type {
AwsCredentialIdentityProvider,
AwsCredentialIdentity,
} from "@smithy/types";

let device: iot.device;

Expand Down Expand Up @@ -54,18 +58,45 @@ export type IoTMessage =

export type IoTMessageTypes = IoTMessage["type"];

export async function getIoTEndpoint({
credentials,
}: {
credentials?: AwsCredentialIdentity;
}) {
const iot = new IoTClient({ credentials });
const response = await iot.send(
new DescribeEndpointCommand({
endpointType: "iot:Data-ATS",
})
);

if (!response.endpointAddress)
throw new Error("IoT Endpoint address not found");

return response.endpointAddress;
}

export async function connect(props: {
onMessage: (message: IoTMessage) => void;
topic: string;
credentialsProvider?: AwsCredentialIdentityProvider;
}): Promise<{
publish: (payload: IoTMessage, topic: string) => Promise<void>;
}> {
const endpoint = await getIoTEndpoint();
const credentials = props.credentialsProvider
? await props.credentialsProvider()
: undefined;

const endpoint = await getIoTEndpoint({ credentials });

device = new iot.device({
protocol: "wss",
host: endpoint,
reconnectPeriod: 1,
keepalive: 60,
accessKeyId: credentials?.accessKeyId,
secretKey: credentials?.secretAccessKey,
sessionToken: credentials?.sessionToken,
});

device.subscribe(props.topic, { qos: 1 });
Expand Down
38 changes: 34 additions & 4 deletions src/lldebugger.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// ****** support require in for CJS modules ******
export * as LlDebugger from "./lldebugger.js";
import { createRequire } from "module";
// @ts-ignore
const require = createRequire(import.meta.url);
Expand All @@ -17,17 +18,44 @@ import * as FileWatcher from "./fileWatcher.js";
import * as fs from "fs";
import { fileURLToPath } from "url";
import * as path from "path";
import { Command } from "commander";
import * as AwsCredentials from "./awsCredentials.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

export let resources: ResourcesToDebug;
let debuggerId: string;

export let argOptions: {
destroy?: boolean;
verbose?: boolean;
context?: string;
profile?: string;
region?: string;
role?: string;
};

async function run() {
const version = await getVersion();
const program = new Command();

program.name("lld").description("Lambda Live Debugger").version(version);

program.option("-d, --destroy", "Destroy the infrastructure");
program.option("-v, --verbose", "Verbose logs");
program.option("-c, --context <context>", "AWS CDK context");
program.option("--profile <profile>", "AWS profile to use");
program.option("--region <region>", "AWS region to use");
program.option("--role <role>", "AWS role to use");

program.parse(process.argv);

argOptions = program.opts();

debuggerId = await generateDebuggerId();
console.log(
`Welcome to Lambda Live Debugger version: ${await getVersion()}! Starting the debugger (ID ${debuggerId})...`
`Welcome to Lambda Live Debugger version: ${version}! Starting the debugger (ID ${debuggerId})...`
);
resources = await CdkResourcesDiscovery.resourcesDiscovery();

Expand All @@ -44,9 +72,10 @@ async function run() {
.join("\n - ")}`
);

// await InfraDeploy.destroyInfrastructure();

// return;
if (argOptions.destroy) {
await InfraDeploy.destroyInfrastructure();
return;
}
await InfraDeploy.deployInfrastructure();

const topic = `${debuggerId}/events`;
Expand Down Expand Up @@ -104,6 +133,7 @@ async function run() {
}
},
topic,
credentialsProvider: AwsCredentials.getCredentialsProvider(),
});
console.log("Debugger started!");
}
Expand Down

0 comments on commit 686c21d

Please sign in to comment.