mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
184 lines
5.4 KiB
JavaScript
184 lines
5.4 KiB
JavaScript
'use strict';
|
|
|
|
const BbPromise = require('bluebird');
|
|
const path = require('path');
|
|
const forEach = require('lodash').forEach;
|
|
const merge = require('lodash').merge;
|
|
|
|
class AwsCompileFunctionsToResources {
|
|
constructor(serverless) {
|
|
this.serverless = serverless;
|
|
|
|
// default properties
|
|
this.options = {};
|
|
this.functions = []; // extracted functions from the serverless.yaml file as JS objects
|
|
this.functionResources = []; // AWS resource definitions for the functions
|
|
|
|
// TODO: remove because it relies on awsResourcesDeploy hooks
|
|
this.commands = {
|
|
compile: {
|
|
commands: {
|
|
functions: {
|
|
usage: 'Compiles the function definition in serverless.yaml to a CloudFormation stack',
|
|
lifecycleEvents: [
|
|
'compile',
|
|
],
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
this.hooks = {
|
|
'compile:functions:compile': this.run.bind(this),
|
|
};
|
|
}
|
|
|
|
run(options) {
|
|
this.options = options;
|
|
return BbPromise.bind(this)
|
|
.then(this.validateOptions)
|
|
.then(this.extractFunctions)
|
|
.then(this.createFunctionResources)
|
|
.then(this.addFunctionResourcesToServiceResourcesObject)
|
|
.catch((exception) => {
|
|
throw new this.serverless.classes.Error(exception);
|
|
});
|
|
}
|
|
|
|
validateOptions() {
|
|
if (!this.options.stage) {
|
|
throw new this.serverless.classes.Error('Please pass in a valid stage.');
|
|
}
|
|
|
|
if (!this.options.region) {
|
|
throw new this.serverless.classes.Error('Please pass in a valid region');
|
|
}
|
|
|
|
BbPromise.resolve();
|
|
}
|
|
|
|
extractFunctions() {
|
|
const functions = this.serverless.service.functions;
|
|
|
|
forEach(functions, (value, key) => {
|
|
// check if it's the function and not the name_template property
|
|
if (key !== 'name_template') {
|
|
const functionObject = {
|
|
[key]: value,
|
|
};
|
|
|
|
this.functions.push(functionObject);
|
|
}
|
|
});
|
|
return BbPromise.resolve();
|
|
}
|
|
|
|
createFunctionResources() {
|
|
const functionTemplate = `
|
|
{
|
|
"Type": "AWS::Lambda::Function",
|
|
"Properties": {
|
|
"Code": "Code",
|
|
"FunctionName": "FunctionName",
|
|
"Handler": "Handler",
|
|
"MemorySize": "MemorySize",
|
|
"Role": "Role",
|
|
"Runtime": "Runtime",
|
|
"Timeout": "Timeout"
|
|
}
|
|
}
|
|
`;
|
|
|
|
this.functions.forEach((func) => {
|
|
const newFunction = JSON.parse(functionTemplate);
|
|
const functionName = Object.keys(func)[0];
|
|
|
|
const role = this.serverless.service.getVariables(
|
|
this.options.stage,
|
|
this.options.region
|
|
).iamRoleArnLambda;
|
|
|
|
if (!functionName) {
|
|
throw new this.serverless.classes.Error('Please define a name for your function.');
|
|
}
|
|
|
|
if (!func[functionName].handler) {
|
|
throw new this.serverless.classes.Error('Please define a handler for your function.');
|
|
}
|
|
|
|
if (!func[functionName].provider.aws_lambda.memorySize) {
|
|
throw new this.serverless.classes.Error('Please define a memory size for your function.');
|
|
}
|
|
|
|
if (!role) {
|
|
throw new this.serverless.classes.Error('Please define a IAM ARN role for your function.');
|
|
}
|
|
|
|
if (!func[functionName].provider.aws_lambda.runtime) {
|
|
throw new this.serverless.classes.Error('Please define a runtime for your function.');
|
|
}
|
|
|
|
if (!func[functionName].provider.aws_lambda.timeout) {
|
|
throw new this.serverless.classes.Error('Please define a timeout for your function.');
|
|
}
|
|
|
|
newFunction.Properties.Code = ''; // Code will be added later on!
|
|
newFunction.Properties.FunctionName = functionName;
|
|
newFunction.Properties.Handler = func[functionName].handler;
|
|
newFunction.Properties.MemorySize = func[functionName].provider.aws_lambda.memorySize;
|
|
newFunction.Properties.Role = role;
|
|
newFunction.Properties.Runtime = func[functionName].provider.aws_lambda.runtime;
|
|
newFunction.Properties.Timeout = func[functionName].provider.aws_lambda.timeout;
|
|
|
|
const functionResourceKey = `${functionName}Lambda`;
|
|
|
|
const newFunctionObject = {
|
|
[functionResourceKey]: newFunction,
|
|
};
|
|
|
|
this.functionResources.push(newFunctionObject);
|
|
});
|
|
return BbPromise.resolve();
|
|
}
|
|
|
|
addFunctionResourcesToServiceResourcesObject() {
|
|
const serviceResources = this.serverless.service.resources.aws;
|
|
|
|
if (serviceResources) {
|
|
this.functionResources.forEach((functionResource) => {
|
|
merge(serviceResources.Resources, functionResource);
|
|
});
|
|
|
|
this.serverless.service.resources.aws = serviceResources;
|
|
} else {
|
|
const coreCFTemplate = this.serverless.utils.readFileSync(
|
|
path.join(__dirname, '..', '..', 'templates', 'core-cf.json')
|
|
);
|
|
|
|
// set the necessary variables before adding the function resources
|
|
coreCFTemplate
|
|
.Resources
|
|
.IamPolicyLambda
|
|
.Properties
|
|
.PolicyName = `${this.stage}-lambda`;
|
|
coreCFTemplate
|
|
.Resources
|
|
.IamPolicyLambda
|
|
.Properties
|
|
.PolicyDocument
|
|
.Statement[0]
|
|
.Resource = `arn:aws:logs:${this.region}:*:*`;
|
|
|
|
this.functionResources.forEach((functionResource) => {
|
|
merge(coreCFTemplate.Resources, functionResource);
|
|
});
|
|
|
|
this.serverless.service.resources.aws = coreCFTemplate;
|
|
}
|
|
|
|
return BbPromise.resolve();
|
|
}
|
|
}
|
|
|
|
module.exports = AwsCompileFunctionsToResources;
|