Comparing version 0.0.11 to 0.0.12
@@ -16,5 +16,8 @@ const { program } = require("commander"); | ||
.option("--lambda-kill-warm-instances", "kill warm lambda instances by doing a silent redeployment") | ||
.option("--lambda-update-publish-s3", "update and publish new lambda version from s3 object") | ||
.option("--ecr-ecs-ephemeral-create", "creates an ephemeral ecr/ecs combination") | ||
.option("--ecr-ecs-ephemeral-destroy", "destroys an ephemeral ecr/ecs combination") | ||
// .option("--version-based-lambda-deploy", "deploy a version-based lambda function") | ||
.option("--api-gateway-lambda-deploy-sub", "deploy a sub lambda function with api gateway") | ||
.option("--api-gateway-deploy-lambda-proxy-sub-route", "adds a lambda proxy sub route based off default") | ||
.option("--api-gateway-add-lambda-permission", "add api gateway lambda permission") | ||
.option("--task-definition <task-definition>", "ecs task definition") | ||
@@ -26,3 +29,6 @@ .option("--task-arn <task-arn>", "ecs task arn") | ||
.option("--local-image-name <local-image-name>", "local image name") | ||
.option("--s3-bucket <s3-bucket>", "s3 bucket") | ||
.option("--s3-key <s3-key>", "s3 key") | ||
.option("--lambda-function <lambda-function>", "lambda function") | ||
.option("--lambda-function-version <lambda-function-version>", "lambda function version") | ||
.option("--lambda-edge-type <lambda-edge-type>", "lambda edge type") | ||
@@ -35,5 +41,10 @@ .option("--cloudfront-id <cloudfront-id>", "cloudfront id") | ||
.option("--memory-units <memory-units>", "memory-units", "512") | ||
.option("--rest-api-id <rest-api-id>", "api gateway rest api id") | ||
.option("--stage-name <stage-name>", "api gateway stage-name", "production") | ||
.option("--api-gateway-base-path <base path>", "api gateway base path", "/{proxy+}") | ||
.option("--api-gateway-sub-path <sub path>", "api gateway sub path") | ||
.option("--ephemeral-id <ephemeral-id>", "ephemeral id"); | ||
program.parse(process.argv); | ||
@@ -77,2 +88,5 @@ const options = program.opts(); | ||
if (options["lambdaUpdatePublishS3"]) | ||
Lib.lambdaUpdatePublishS3(options["lambdaFunction"], options["s3Bucket"], options["s3Key"], resultFunc); | ||
if (options["ecrEcsEphemeralCreate"]) | ||
@@ -82,2 +96,11 @@ Lib.ecrEcsEphemeralCreate(options["executionRoleArn"], options["taskRoleArn"], options["cpuUnits"], options["memoryUnits"], resultFunc); | ||
if (options["ecrEcsEphemeralDestroy"]) | ||
Lib.ecrEcsEphemeralDestroy(options["ephemeralId"], resultFunc); | ||
Lib.ecrEcsEphemeralDestroy(options["ephemeralId"], resultFunc); | ||
if (options["apiGatewayDeployLambdaProxySubRoute"]) | ||
Lib.apiGatewayDeployLambdaProxySubRoute(options["restApiId"], options["stageName"], options["apiGatewayBasePath"], options["apiGatewaySubPath"], options["lambdaFunction"], options["lambdaFunctionVersion"], resultFunc); | ||
if (options["apiGatewayAddLambdaPermission"]) | ||
Lib.apiGatewayAddLambdaPermission(options["restApiId"], options["apiGatewaySubPath"], options["lambdaFunction"], options["lambdaFunctionVersion"], resultFunc); | ||
if (options["apiGatewayLambdaDeploySub"]) | ||
Lib.apiGatewayLambdaDeploySub(options["restApiId"], options["stageName"], options["apiGatewayBasePath"], options["apiGatewaySubPath"], options["lambdaFunction"], options["s3Bucket"], options["s3Key"], resultFunc); |
{ | ||
"name": "awsass", | ||
"description": "AWSASS is an assistant to AWS, mostly for running better scripts.", | ||
"version": "0.0.11", | ||
"version": "0.0.12", | ||
"author": "Jsonize", | ||
@@ -6,0 +6,0 @@ "repository": "https://github.com/jsonize/awsass", |
231
src/lib.js
@@ -199,50 +199,45 @@ const AWS = require("aws-sdk"); | ||
edgeLambdaKillWarmInstances: function (lambdaFunction, cloudfrontId, lambdaEdgeType, callback) { | ||
resilientPublishLambdaVersion: function (lambdaFunction, callback, baseDelay, maxExponent) { | ||
const lambda = new AWS.Lambda({apiVersion: '2015-03-31'}); | ||
const cloudfront = new AWS.CloudFront({apiVersion: '2020-05-31'}); | ||
lambda.updateFunctionConfiguration({ | ||
FunctionName: lambdaFunction, | ||
Description: "AWSASS:" + (new Date()).getTime() | ||
}, function (err) { | ||
baseDelay = baseDelay || 1000; | ||
maxExponent = maxExponent || 5; | ||
if (maxExponent <= 0) | ||
callback("Exceeded publish timeout"); | ||
lambda.publishVersion({ | ||
FunctionName: lambdaFunction | ||
}, function (err, result) { | ||
if (err) { | ||
Module.resilientPublishLambdaVersion(lambdaFunction, callback, baseDelay * 2, maxExponent - 1); | ||
return; | ||
} | ||
callback(undefined, result); | ||
}); | ||
}, | ||
resilientUpdateConfigurationPublishLambdaVersion: function (lambdaFunction, configurationUpdate, callback, baseDelay, maxExponent) { | ||
const lambda = new AWS.Lambda({apiVersion: '2015-03-31'}); | ||
configurationUpdate.FunctionName = lambdaFunction; | ||
lambda.updateFunctionConfiguration(configurationUpdate, function (err) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
setTimeout(function () { | ||
lambda.publishVersion({ | ||
FunctionName: lambdaFunction | ||
}, function (err, publishResult) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
cloudfront.getDistributionConfig({ | ||
Id: cloudfrontId | ||
}, function (err, distributionConfig) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
const lambdaItems = distributionConfig.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.Items; | ||
let lambdaItem = null; | ||
lambdaItems.forEach(function (candidate) { | ||
if (candidate.EventType === lambdaEdgeType) | ||
lambdaItem = candidate; | ||
}); | ||
let s = lambdaItem.LambdaFunctionARN.split(":"); | ||
s[s.length - 1] = publishResult.Version; | ||
lambdaItem.LambdaFunctionARN = s.join(":"); | ||
cloudfront.updateDistribution({ | ||
Id: cloudfrontId, | ||
IfMatch: distributionConfig.ETag, | ||
DistributionConfig: distributionConfig.DistributionConfig | ||
}, callback); | ||
}); | ||
}); | ||
}, 5000); | ||
Module.resilientPublishLambdaVersion(lambdaFunction, callback, baseDelay, maxExponent); | ||
}); | ||
}, | ||
lambdaKillWarmInstances: function (lambdaFunction, callback) { | ||
resilientUpdateFunctionCodePublishLambdaVersion: function (lambdaFunction, functionCodeUpdate, callback, baseDelay, maxExponent) { | ||
const lambda = new AWS.Lambda({apiVersion: '2015-03-31'}); | ||
functionCodeUpdate.FunctionName = lambdaFunction; | ||
lambda.updateFunctionCode(functionCodeUpdate, function (err) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
Module.resilientPublishLambdaVersion(lambdaFunction, callback, baseDelay, maxExponent); | ||
}); | ||
}, | ||
resilientMapConfigurationPublishLambdaVersion: function (lambdaFunction, configurationUpdateFunction, callback, baseDelay, maxExponent) { | ||
const lambda = new AWS.Lambda({apiVersion: '2015-03-31'}); | ||
lambda.getFunctionConfiguration({ | ||
@@ -255,7 +250,18 @@ FunctionName: lambdaFunction, | ||
} | ||
functionConfiguration.Environment.Variables.AWSASS = "" + (new Date()).getTime(); | ||
lambda.updateFunctionConfiguration({ | ||
FunctionName: lambdaFunction, | ||
Environment: functionConfiguration.Environment | ||
}, function (err) { | ||
Module.resilientUpdateConfigurationPublishLambdaVersion(lambdaFunction, configurationUpdateFunction(functionConfiguration), callback, baseDelay, maxExponent); | ||
}); | ||
}, | ||
edgeLambdaKillWarmInstances: function (lambdaFunction, cloudfrontId, lambdaEdgeType, callback) { | ||
const cloudfront = new AWS.CloudFront({apiVersion: '2020-05-31'}); | ||
Module.resilientUpdateConfigurationPublishLambdaVersion(lambdaFunction, { | ||
Description: "AWSASS:" + (new Date()).getTime() | ||
}, function (err, publishResult) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
cloudfront.getDistributionConfig({ | ||
Id: cloudfrontId | ||
}, function (err, distributionConfig) { | ||
if (err) { | ||
@@ -265,7 +271,16 @@ callback(err); | ||
} | ||
setTimeout(function () { | ||
lambda.publishVersion({ | ||
FunctionName: lambdaFunction | ||
}, callback); | ||
}, 5000); | ||
const lambdaItems = distributionConfig.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.Items; | ||
let lambdaItem = null; | ||
lambdaItems.forEach(function (candidate) { | ||
if (candidate.EventType === lambdaEdgeType) | ||
lambdaItem = candidate; | ||
}); | ||
let s = lambdaItem.LambdaFunctionARN.split(":"); | ||
s[s.length - 1] = publishResult.Version; | ||
lambdaItem.LambdaFunctionARN = s.join(":"); | ||
cloudfront.updateDistribution({ | ||
Id: cloudfrontId, | ||
IfMatch: distributionConfig.ETag, | ||
DistributionConfig: distributionConfig.DistributionConfig | ||
}, callback); | ||
}); | ||
@@ -275,2 +290,11 @@ }); | ||
lambdaKillWarmInstances: function (lambdaFunction, callback) { | ||
Module.resilientMapConfigurationPublishLambdaVersion(lambdaFunction, function (functionConfiguration) { | ||
functionConfiguration.Environment.Variables.AWSASS = "" + (new Date()).getTime(); | ||
return { | ||
Environment: functionConfiguration.Environment | ||
}; | ||
}, callback); | ||
}, | ||
ecrEcsEphemeralCreate: function (executionRoleArn, taskRoleArn, cpuUnits, memoryUnits, callback) { | ||
@@ -367,2 +391,111 @@ const ecr = new AWS.ECR({apiVersion: '2015-09-21'}); | ||
}); | ||
}, | ||
lambdaUpdatePublishS3: function (lambdaFunction, s3Bucket, s3Key, callback) { | ||
Module.resilientUpdateFunctionCodePublishLambdaVersion(lambdaFunction, { | ||
S3Bucket: s3Bucket, | ||
S3Key: s3Key | ||
}, callback); | ||
}, | ||
apiGatewayAddLambdaPermission: function (restApiId, apiGatewaySubPath, lambdaFunction, lambdaFunctionVersion, callback) { | ||
const sts = new AWS.STS({apiVersion: "2011-06-15"});; | ||
const lambda = new AWS.Lambda({apiVersion: '2015-03-31'}); | ||
sts.getCallerIdentity({}, function(err, callerId) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
lambda.addPermission({ | ||
FunctionName: lambdaFunction + (lambdaFunctionVersion ? ":" + lambdaFunctionVersion : ""), | ||
StatementId: "apigateway" + (lambdaFunctionVersion ? "-" + lambdaFunctionVersion : "") + "-" + (new Date()).getTime(), | ||
Action: "lambda:InvokeFunction", | ||
Principal: "apigateway.amazonaws.com", | ||
SourceArn: ["arn:aws:execute-api", AWS.config.region, callerId.Account, [restApiId, "*", "*", apiGatewaySubPath].join("/")].join(":") | ||
}, callback); | ||
}); | ||
}, | ||
apiGatewayDeployLambdaProxySubRoute: function (restApiId, stageName, apiGatewayBasePath, apiGatewaySubPath, lambdaFunction, lambdaFunctionVersion, callback) { | ||
const apigateway = new AWS.APIGateway({apiVersion: "2015-07-09"}); | ||
apigateway.getExport({ | ||
restApiId: restApiId, | ||
stageName: stageName, | ||
exportType: "swagger", | ||
parameters: { | ||
extensions: "apigateway" | ||
} | ||
}, function (err, exportResponse) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
let swaggerSub; | ||
try { | ||
const swaggerBase = JSON.parse(exportResponse.body); | ||
console.log(swaggerBase); | ||
const subIntegration = swaggerBase.paths[apiGatewayBasePath]["x-amazon-apigateway-any-method"]["x-amazon-apigateway-integration"]; | ||
delete subIntegration.cacheNamespace; | ||
if (lambdaFunction) { | ||
let splt = subIntegration.uri.split("/"); | ||
let splt2 = splt[splt.length - 2].split(":"); | ||
splt2[6] = lambdaFunction; | ||
splt[splt.length - 2] = splt2.join(":"); | ||
subIntegration.uri = splt.join("/"); | ||
} | ||
if (lambdaFunctionVersion) { | ||
let splt = subIntegration.uri.split("/"); | ||
let splt2 = splt[splt.length - 2].split(":"); | ||
splt2[7] = lambdaFunctionVersion; | ||
splt[splt.length - 2] = splt2.join(":"); | ||
subIntegration.uri = splt.join("/"); | ||
} | ||
swaggerSub = { | ||
swagger: swaggerBase.swagger, | ||
info: swaggerBase.info, | ||
paths: {} | ||
}; | ||
swaggerSub.paths[apiGatewaySubPath] = swaggerBase.paths[apiGatewayBasePath]; | ||
} catch (e) { | ||
callback("Malformed swagger"); | ||
return; | ||
} | ||
apigateway.putRestApi({ | ||
restApiId: restApiId, | ||
mode: "merge", | ||
parameters: { | ||
ignore: "documentation" | ||
}, | ||
body: JSON.stringify(swaggerSub) | ||
}, function (err) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
apigateway.createDeployment({ | ||
restApiId: restApiId, | ||
stageName: stageName | ||
}, callback); | ||
}) | ||
}); | ||
}, | ||
apiGatewayLambdaDeploySub: function (restApiId, stageName, apiGatewayBasePath, apiGatewaySubPath, lambdaFunction, s3Bucket, s3Key, callback) { | ||
Module.lambdaUpdatePublishS3(lambdaFunction, s3Bucket, s3Key, function (err, lambdaResult) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
const lambdaFunctionVersion = lambdaResult.Version; | ||
const splt = apiGatewaySubPath.split("/"); | ||
splt[splt.length - 1] = "*"; | ||
const apiGatewaySubPathMapping = splt.join("/");; | ||
Module.apiGatewayAddLambdaPermission(restApiId, apiGatewaySubPathMapping, lambdaFunction, lambdaFunctionVersion, function (err) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
Module.apiGatewayDeployLambdaProxySubRoute(restApiId, stageName, apiGatewayBasePath, apiGatewaySubPath, lambdaFunction, lambdaFunctionVersion, callback); | ||
}); | ||
}); | ||
} | ||
@@ -369,0 +502,0 @@ |
27767
569