From 132bf794dfe7a2fb6aa2316319b0cc6c91c792cf Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Fri, 27 May 2016 14:42:47 +0200 Subject: [PATCH] Add attach CloudForamtion result to service resources object --- .../awsCompileFunctionsToResources.js | 163 +++++++----------- .../tests/awsCompileFunctionsToResources.js | 4 - lib/templates/core-cf.json | 64 +++++++ 3 files changed, 125 insertions(+), 106 deletions(-) create mode 100644 lib/templates/core-cf.json diff --git a/lib/plugins/awsCompileFunctionsToResources/awsCompileFunctionsToResources.js b/lib/plugins/awsCompileFunctionsToResources/awsCompileFunctionsToResources.js index 76cf3284b..ad8fe41f8 100644 --- a/lib/plugins/awsCompileFunctionsToResources/awsCompileFunctionsToResources.js +++ b/lib/plugins/awsCompileFunctionsToResources/awsCompileFunctionsToResources.js @@ -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(); } diff --git a/lib/plugins/awsCompileFunctionsToResources/tests/awsCompileFunctionsToResources.js b/lib/plugins/awsCompileFunctionsToResources/tests/awsCompileFunctionsToResources.js index 96bf92083..0dc2b0028 100644 --- a/lib/plugins/awsCompileFunctionsToResources/tests/awsCompileFunctionsToResources.js +++ b/lib/plugins/awsCompileFunctionsToResources/tests/awsCompileFunctionsToResources.js @@ -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({}); }); diff --git a/lib/templates/core-cf.json b/lib/templates/core-cf.json new file mode 100644 index 000000000..e2561d7a5 --- /dev/null +++ b/lib/templates/core-cf.json @@ -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" + ] + } + } + } +}