Skip to content

Instantly share code, notes, and snippets.

@olivoil
Created May 4, 2017 22:58
Show Gist options
  • Select an option

  • Save olivoil/7e42d1e7941c24a7872d8c0ecf296be8 to your computer and use it in GitHub Desktop.

Select an option

Save olivoil/7e42d1e7941c24a7872d8c0ecf296be8 to your computer and use it in GitHub Desktop.
prune lambda functions from serverless file
#!/usr/bin/env node
const AWS = require("aws-sdk");
const YAML = require("yamljs");
const ENV = process.env.NODE_ENV || "dev";
// it assumes you have AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in your environment
const lambda = new AWS.Lambda({
region: process.env.AWS_REGION || "us-east-1",
});
function exit(err) {
if (err) console.log(err);
process.exit(err ? 1 : 0);
}
async function prune() {
const serverless = YAML.load("serverless.yml");
const functionNames = Object.keys(serverless.functions).map((n) => `${serverless.service}-${ENV}-${n}`);
return series(functionNames.map((n) => pruneFunction(n)));
}
async function listVersions(name, marker, versions) {
const prev = versions || [];
const params = { FunctionName: name, MaxItems: 10000 };
if (marker) params.Marker = marker;
let list = {Versions: [], NextMarker: ""};
try {
list = await lambda.listVersionsByFunction(params).promise();
} catch(e) {
console.log(`error fetching versions for ${name}: ${e.message}`);
}
const curr = prev.concat(list.Versions);
if (list.NextMarker) {
return listVersions(name, list.NextMarker, curr);
}
return curr;
}
async function pruneFunction(name, keep) {
let keepLast = keep || 5;
const versions = await listVersions(name);
const sorted = versions.sort((v1, v2) => {
if (v1.LastModified < v2.LastModified) {
return 1;
} else {
if( v1.LastModified > v2.LastModified ) {
return -1;
} else {
return 0;
}
}
});
let listAliases = { Aliases: [] };
try {
listAliases = await lambda.listAliases({ FunctionName: name, MaxItems: 10000 }).promise();
} catch (e) {
console.log(`error fetching aliases for ${name}: ${e.message}`);
}
// keep any version that is pointed to by an alias
const keepVersions = listAliases.Aliases.map((a) => a.FunctionVersion);
const keeping = [];
sorted.forEach((v) => {
if ((v.Version == "$LATEST") || (keepVersions.includes(v.Version)) ) {
keeping.push(v.Version);
}
else if (keepLast > 0) {
keeping.push(v.Version);
keepLast--;
}
});
const deleting = sorted.map((v) => v && keeping.includes(v.Version) ? null : v).filter((v) => v).reverse();
console.log(`${name}:`);
console.log(`- keeping ${keeping.length} versions: ${keeping.join(", ")}`);
console.log(`- deleting ${deleting.length} versions: ${deleting.map((v) => v.Version).join(", ")}`);
return series(deleting.map((v) => {
return lambda.deleteFunction({ FunctionName: v.FunctionName, Qualifier: v.Version }).promise();
}));
}
function series(arrayOfPromises) {
const results = [];
return arrayOfPromises.reduce((seriesPromise, promise) => {
return seriesPromise.then(() => {
return promise.then((result) => {
results.push(result);
});
});
}, Promise.resolve())
.then(() => {
return results;
});
}
module.exports = exports.default = exports.prune = prune;
if (require.main === module) {
prune().then(() => exit()).catch(exit);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment