Add attach CloudForamtion result to service resources object

This commit is contained in:
Philipp Muens 2016-05-27 14:42:47 +02:00
parent 86b3a175f1
commit 132bf794df
3 changed files with 125 additions and 106 deletions

View File

@ -1,6 +1,7 @@
'use strict';
const BbPromise = require('bluebird');
const path = require('path');
const forEach = require('lodash').forEach;
const merge = require('lodash').merge;
@ -8,14 +9,10 @@ class AwsCompileFunctionsToResources {
constructor(serverless) {
this.serverless = serverless;
// TODO pass in the right stage and region
this.stage = 'dev';
this.region = 'aws_useast1';
// 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.cloudFormationResult = {};
// TODO: remove because it relies on awsResourcesDeploy hooks
this.commands = {
@ -32,19 +29,34 @@ class AwsCompileFunctionsToResources {
};
this.hooks = {
'compile:functions:compile': (options) => {
this.options = options;
return BbPromise.bind(this)
.then(this.extractFunctions)
.then(this.createFunctionResources)
.then(this.addFunctionResourcesToCFMainTemplate)
.catch((exception) => {
throw new this.serverless.classes.Error(exception);
});
},
'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;
@ -81,7 +93,10 @@ class AwsCompileFunctionsToResources {
const newFunction = JSON.parse(functionTemplate);
const functionName = Object.keys(func)[0];
const role = this.serverless.service.getVariables(this.stage, this.region).iamRoleArnLambda;
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.');
@ -126,96 +141,40 @@ class AwsCompileFunctionsToResources {
return BbPromise.resolve();
}
addFunctionResourcesToCFMainTemplate() {
let CFMainTemplate = `
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "AWS CloudFormation template",
"Resources": {
"IamRoleLambda": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/"
}
},
"IamPolicyLambda": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "stage-lambda",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:region:*:*"
}
]
},
"Roles": [
{
"Ref": "IamRoleLambda"
}
]
}
}
},
"Outputs": {
"IamRoleArnLambda": {
"Description": "ARN of the lambda IAM role",
"Value": {
"Fn::GetAtt": [
"IamRoleLambda",
"Arn"
]
}
}
}
}
`;
CFMainTemplate = JSON.parse(CFMainTemplate);
addFunctionResourcesToServiceResourcesObject() {
const serviceResources = this.serverless.service.resources.aws;
// set the necessary variables before adding the function resources
CFMainTemplate
.Resources
.IamPolicyLambda
.Properties
.PolicyName = `${this.stage}-lambda`;
CFMainTemplate.Resources
.IamPolicyLambda
.Properties
.PolicyDocument
.Statement[0]
.Resource = `arn:aws:logs:${this.region}:*:*`;
if (serviceResources) {
this.functionResources.forEach((functionResource) => {
merge(serviceResources.Resources, functionResource);
});
this.functionResources.forEach((functionResource) => {
merge(CFMainTemplate.Resources, functionResource);
});
this.serverless.service.resources.aws = serviceResources;
} else {
const coreCFTemplate = this.serverless.utils.readFileSync(
path.join(__dirname, '..', '..', 'templates', 'core-cf.json')
);
this.cloudFormationResult = CFMainTemplate;
// 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}:*:*`;
// TODO pass the result to awsResourcesDeploy plugin
console.log(JSON.stringify(this.cloudFormationResult, null, 2));
this.functionResources.forEach((functionResource) => {
merge(coreCFTemplate.Resources, functionResource);
});
this.serverless.service.resources.aws = coreCFTemplate;
}
return BbPromise.resolve();
}

View File

@ -60,10 +60,6 @@ describe('CompileFunctionsToResources', () => {
expect(awsCompileFunctionsToResources.functionResources.length).to.equal(0);
});
it('should have an empty cloudFormationResult object', () => {
expect(awsCompileFunctionsToResources.cloudFormationResult).to.deep.equal({});
});
it('should have a hook', () => {
expect(awsCompileFunctionsToResources.hooks).to.not.deep.equal({});
});

View File

@ -0,0 +1,64 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application's resources outside of Lambdas and Api Gateway",
"Resources": {
"IamRoleLambda": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/"
}
},
"IamPolicyLambda": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "${stage}-${project}-lambda",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:${region}:*:*"
}
]
},
"Roles": [
{
"Ref": "IamRoleLambda"
}
]
}
}
},
"Outputs": {
"IamRoleArnLambda": {
"Description": "ARN of the lambda IAM role",
"Value": {
"Fn::GetAtt": [
"IamRoleLambda",
"Arn"
]
}
}
}
}