mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
This way the necessary variables which are taken from the options are always set because they are always used.
177 lines
5.3 KiB
JavaScript
177 lines
5.3 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
|
|
|
|
this.hooks = {
|
|
'before:resources:resources': 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;
|
|
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.options.stage}-lambda`;
|
|
coreCFTemplate
|
|
.Resources
|
|
.IamPolicyLambda
|
|
.Properties
|
|
.PolicyDocument
|
|
.Statement[0]
|
|
.Resource = `arn:aws:logs:${this.options.region}:*:*`;
|
|
|
|
const iamRoleLambda = coreCFTemplate.Resources.IamRoleLambda;
|
|
const iamPolicyLambda = coreCFTemplate.Resources.IamPolicyLambda;
|
|
|
|
if (serviceResources) {
|
|
this.functionResources.forEach((functionResource) => {
|
|
merge(serviceResources.Resources, functionResource);
|
|
});
|
|
|
|
merge(serviceResources.Resources, { IamRoleLambda: iamRoleLambda });
|
|
merge(serviceResources.Resources, { IamPolicyLambda: iamPolicyLambda });
|
|
|
|
this.serverless.service.resources.aws = serviceResources;
|
|
} else {
|
|
this.functionResources.forEach((functionResource) => {
|
|
merge(coreCFTemplate.Resources, functionResource);
|
|
});
|
|
|
|
this.serverless.service.resources.aws = coreCFTemplate;
|
|
}
|
|
|
|
return BbPromise.resolve();
|
|
}
|
|
}
|
|
|
|
module.exports = AwsCompileFunctionsToResources;
|