Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update Buffer call to use Buffer.from for nodejs upgrade to lambda #14

Open
wants to merge 15 commits into
base: development
Choose a base branch
from
4 changes: 3 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.git
.git
tester/
test/
11 changes: 7 additions & 4 deletions factory.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use strict';

const config = require('leo-config');
const AWS = require('aws-sdk');
const { fromIni } = require("@aws-sdk/credential-providers");
const merge = require('lodash.merge');
const requireFn = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;


const leoaws = {
cloudformation: require('./lib/cloudformation'),
Expand All @@ -12,10 +14,10 @@ const leoaws = {
sqs: require('./lib/sqs'),
};

function factory (service, options) {
function factory(service, options) {
const configuration = config.leoaws;
if (configuration && configuration.profile && !configuration.credentials) {
configuration.credentials = new AWS.SharedIniFileCredentials({
configuration.credentials = fromIni({
profile: configuration.profile,
role: configuration.role,
});
Expand All @@ -30,8 +32,9 @@ function factory (service, options) {
return leoaws[lowerService](configuration);
} else {
// return a configured AWS service
let serviceLib = requireFn("@aws-sdk/client-" + service.replace(/[A-Z]/g, (a) => "-" + a.toLowerCase()).replace(/^-/, ""));
return {
_service: new AWS[service](configuration),
_service: new serviceLib[service](configuration),
};
}
}
Expand Down
6 changes: 3 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const dynamodb = require("./lib/dynamodb");
const kms = require("./lib/kms");
const secrets = require("./lib/secretsmanager");
const sqs = require("./lib/sqs");
const AWS = require('aws-sdk');
const { fromIni } = require("@aws-sdk/credential-providers");

/**
*
Expand All @@ -15,12 +15,12 @@ const AWS = require('aws-sdk');
*/
function build(configuration) {
if (configuration.profile && !configuration.credentials) {
configuration.credentials = new AWS.SharedIniFileCredentials({
configuration.credentials = fromIni({
profile: configuration.profile,
role: configuration.role
});
}

return Object.assign((config) => {
return new build(config)
}, {
Expand Down
177 changes: 117 additions & 60 deletions lib/cloudformation.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,51 @@
"use strict";
const aws = require('aws-sdk');
const { CloudFormation, waitUntilChangeSetCreateComplete, GetTemplateCommand, ListStackResourcesCommand, DescribeStackEventsCommand, DescribeStacksCommand, DescribeChangeSetCommand, waitUntilStackCreateComplete, waitUntilStackUpdateComplete, ExecuteChangeSetCommand } = require('@aws-sdk/client-cloudformation');
const readline = require('readline');

module.exports = function(configuration) {
let service = new aws.CloudFormation(configuration);
let service = new CloudFormation(configuration);
return {
_service: service,
getStackResources: function(stack) {
return service.listStackResources({
const command = new ListStackResourcesCommand({
StackName: stack
}).promise().then((data) => {
});
return service.send(command)
.then((data) => {
if (data.NextToken) {
console.log("We need to deal with next token");
}
var resources = {};
data.StackResourceSummaries.map((resource) => {
resources[resource.LogicalResourceId] = {
type: resource.ResourceType,
id: resource.PhysicalResourceId,
name: resource.LogicalResourceId
Type: resource.ResourceType,
Id: resource.PhysicalResourceId,
Name: resource.LogicalResourceId
};
});

return resources;
});
},
get: function(stack, opts) {
return service.getTemplate(Object.assign({
const command = new GetTemplateCommand(Object.assign({
StackName: stack,
}, opts)).promise().then(data => JSON.parse(data.TemplateBody));
}, opts));

return service.send(command)
.then((data) => {
return JSON.parse(data.TemplateBody);
})
},
/**
* Create a run a changeset
* @param stack
* @param file
* @param filen
* @param opts (Goes directly to AWS. Options must match AWS documentation)
* @param options (Options for this function)
* @returns {Promise<PromiseResult<CloudFormation.CreateChangeSetOutput, AWSError>>}
*/
runChangeSet: function(stack, file, opts, options = {}) {
runChangeSet: async function(stack, file, opts, options = {}) {
let updateOpts = Object.assign({}, opts);
if (updateOpts.Parameters) {
updateOpts.Parameters = updateOpts.Parameters.map(param => ({
Expand All @@ -58,23 +65,49 @@ module.exports = function(configuration) {
"CAPABILITY_IAM",
]
}, updateOpts);
return service.createChangeSet(params).promise().then(data => {
changeSetId = data.Id;
service.api.waiters["changeSetCreateComplete"].delay = 5;
return this.waitFor("changeSetCreateComplete", {
ChangeSetName: changeSetId
});
return service.createChangeSet(params)
.then(async data => {
const changeSetId = data.Id;
const stackId = data.StackId;

const waitConfig = {
minDelay: 5, // Minimum delay in seconds between checks
maxDelay: 30, // Maximum delay in seconds between checks
maxWaitTime: 300 // Maximum time in seconds to wait for the operation to complete
};

try {
const result = await waitUntilChangeSetCreateComplete(
{
client: service, // Pass the CloudFormation client here
maxWaitTime: waitConfig.maxWaitTime,
minDelay: waitConfig.minDelay,
maxDelay: waitConfig.maxDelay
},
{
ChangeSetName: changeSetId, // Use the ChangeSet ID
StackName: stackId, // Use the Stack ID
IncludeNestedStacks: true // Optional, if you want nested stack details
}
);

console.log("--- ChangeSet creation complete ---");
return result;
} catch (err) {
console.error("Error waiting for ChangeSet creation to complete", err);
throw err; // Re-throw the error to handle it later if needed
}
}).then(data => {
data = data.reason
changeSetId = data.ChangeSetId;
console.log(changeSetId);

function rightPad(val, count) {
return (val + " ".repeat(count)).slice(0, count) + " ";
}
console.log(`${rightPad("Action",30)}${rightPad("Logical ID",30)}${rightPad("Physical ID",30)}${rightPad("Resource Type",30)}${rightPad("Replacement",30)}`);
console.log(`${rightPad("Action", 30)}${rightPad("Logical ID", 30)}${rightPad("Physical ID", 30)}${rightPad("Resource Type", 30)}${rightPad("Replacement", 30)}`);
data.Changes.map(change => {
change = change.ResourceChange;
console.log(`${rightPad(change.Action,30)}${rightPad(change.LogicalResourceId,30)}${rightPad(change.PhysicalResourceId,30)}${rightPad(change.ResourceType,30)}${rightPad(change.Replacement,30)}`);
console.log(`${rightPad(change.Action, 30)}${rightPad(change.LogicalResourceId, 30)}${rightPad(change.PhysicalResourceId, 30)}${rightPad(change.ResourceType, 30)}${rightPad(change.Replacement, 30)}`);
});
const rl = readline.createInterface({
input: process.stdin,
Expand Down Expand Up @@ -105,10 +138,12 @@ module.exports = function(configuration) {
} else if (err.StatusReason) {
throw new Error(err.StatusReason);
} else {
return service.describeChangeSet({
const command = new DescribeChangeSetCommand({
ChangeSetName: changeSetId,
StackName: stack
}).promise().then(cs => {
});
return service.send(command)
.then(cs => {
throw cs;
}).catch((err2) => {
if (err2.StatusReason) {
Expand All @@ -133,17 +168,27 @@ module.exports = function(configuration) {
rl.close();
let start = Date.now();
console.log("Executing Change Set");
resolve(service.executeChangeSet({
ChangeSetName: changeSetId
}).promise().then(data => {
service.api.waiters["stackUpdateComplete"].delay = 10;
return this.waitFor("stackUpdateComplete", {
StackName: stack
});
const input = {
ChangeSetName: changeSetId,
StackName: stack
};
const command = new ExecuteChangeSetCommand(input);
resolve(service.send(command)
.then(data => {
const waitConfig = {
minDelay: 5, // Minimum delay in seconds between checks
maxDelay: 30, // Maximum delay in seconds between checks
maxWaitTime: 900 // Maximum time in seconds to wait for the operation to complete
};
return waitUntilStackUpdateComplete(
{ client: service, maxWaitTime: waitConfig.maxWaitTime }, // Waiter configuration
{ StackName: stack } // Command input
);

}).catch(err => {
return service.describeStackEvents({
StackName: stack
}).promise().then(data => {
}).then(data => {
let messages = [];
let addLinkMessage = false;
for (let i = 0; i < data.StackEvents.length; i++) {
Expand All @@ -156,9 +201,6 @@ module.exports = function(configuration) {
if (addLinkMessage) {
messages.push("Linked Stack(s) are missing export values. Are your stack names correct?")
}
if (messages.length == 0) {
message.push("Unknown Error")
}

throw {
StatusReason: messages.join(". ")
Expand All @@ -170,7 +212,7 @@ module.exports = function(configuration) {
getStackErrorStatus: function(stack, start) {
return service.describeStackEvents({
StackName: stack
}).promise().then(data => {
}).then(data => {
let messages = [];
let addLinkMessage = false;
for (let i = 0; i < data.StackEvents.length; i++) {
Expand All @@ -183,9 +225,6 @@ module.exports = function(configuration) {
if (addLinkMessage) {
messages.push("Linked Stack(s) are missing export values. Are your stack names correct?")
}
if (messages.length == 0) {
messages.push("Unknown Error")
}

throw {
StatusReason: messages.join(". ")
Expand All @@ -201,26 +240,33 @@ module.exports = function(configuration) {
ParameterValue: param.ParameterValue
}));
}
console.log(updateOpts);
// console.log(updateOpts);
let start = Date.now();
return service.updateStack(Object.assign({
StackName: stack,
TemplateURL: file,
Capabilities: [
"CAPABILITY_IAM",
]
}, updateOpts)).promise().then(data => {
service.api.waiters["stackUpdateComplete"].delay = 10;
return this.waitFor("stackUpdateComplete", {
StackName: stack
});
}, updateOpts))
.then(data => {
const waitConfig = {
minDelay: 5, // Minimum delay in seconds between checks
maxDelay: 30, // Maximum delay in seconds between checks
maxWaitTime: 900 // Maximum time in seconds to wait for the operation to complete
};
return waitUntilStackUpdateComplete(
{ client: service, maxWaitTime: waitConfig.maxWaitTime }, // Waiter configuration
{ StackName: stack } // Command input
);

}).catch(err => {
if (err.message.match(/^Stack.*does not exist/)) {
return this.createStack(stack, file, updateOpts.Parameters, opts, true, true);
} else {
return service.describeStackEvents({
StackName: stack
}).promise().then(data => {
}).then(data => {
let messages = [];
let addLinkMessage = false;
for (let i = 0; i < data.StackEvents.length; i++) {
Expand All @@ -233,9 +279,7 @@ module.exports = function(configuration) {
if (addLinkMessage) {
messages.push("Linked Stack(s) are missing export values. Are your stack names correct?")
}
if (messages.length == 0) {
messages.push("Unknown Error")
}

throw {
StatusReason: messages.join(", ")
};
Expand All @@ -252,10 +296,10 @@ module.exports = function(configuration) {
describeStackResources: function(stack) {
return service.describeStackResources({
StackName: stack
}).promise().then(data => data.StackResources);
}).then(data => data.StackResources);
},
waitFor: function(action, params) {
return service.waitFor(action, params).promise();
return service.waitFor(action, params);
},
createStack: async function createStack(name, template, paramaters = [], waitFor = true, describeStack = true) {
let templateBody;
Expand All @@ -276,21 +320,33 @@ module.exports = function(configuration) {
OnFailure: "DELETE",
[templateBody]: template,
Parameters: paramaters
}).promise().then(stackInfo => {
}).then(stackInfo => {
createInfo = stackInfo;
return stackInfo;
});
if (waitFor || describeStack) {
service.api.waiters["stackCreateComplete"].delay = 10;
promise = promise.then(() => this.waitFor("stackCreateComplete", {
StackName: name
})).then(waitdata => ({
stack: name,
region: configuration.region,
details: waitdata.Stacks[0]
}));
promise = promise
.then(() => {
const waitConfig = {
minDelay: 5, // Minimum delay in seconds between checks
maxDelay: 30, // Maximum delay in seconds between checks
maxWaitTime: 300 // Maximum time in seconds to wait for the operation to complete
};
return waitUntilStackCreateComplete(
{ client: service, maxWaitTime: waitConfig.maxWaitTime }, // Waiter configuration
{ StackName: name } // Command input
);

}).then(waitdata => {
return {
stack: name,
region: configuration.region,
details: waitdata.reason.Stacks[0]
}
});
} else if (describeStack) {
promise = promise.then(() => this.describeStackResources(name)).then(data => ({
promise = promise.then(() => this.describeStackResources(name))
.then(data => ({
stack: name,
region: configuration.region,
details: {
Expand All @@ -299,11 +355,12 @@ module.exports = function(configuration) {
}));
}
return promise.catch((waitErr) => this.getStackErrorStatus(createInfo.StackId || name, createStart).catch(err => {
console.log("Error creating stack", err);
if (err.StatusReason)
throw new Error(err.StatusReason);
else
throw waitErr;
}));
}
};
};
};
Loading