├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── lib └── deployWithParameters.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Trek10 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serverless-cloudformation-parameter-setter 2 | [![serverless](http://public.serverless.com/badges/v3.svg)](http://www.serverless.com) 3 | 4 | Serverless framework plugin to set CloudFormation Parameters when deploying 5 | 6 | ## Installation 7 | 8 | Install the plugin from npm 9 | 10 | ```bash 11 | $ npm install --save serverless-cloudformation-parameter-setter 12 | ``` 13 | 14 | Add the plugin to your `serverless.yml` file: 15 | 16 | ```yaml 17 | plugins: 18 | - serverless-cloudformation-parameter-setter 19 | ``` 20 | 21 | ## Usage 22 | #### CLI options 23 | None 24 | 25 | #### YAML settings 26 | ```yaml 27 | custom: 28 | cf-parameters: 29 | secretPassword: whatever # this could be serverless ssm variable or s3 variable or plaintext or whatever, do what you want 30 | 31 | resources: 32 | # define the cloudformation parameters here 33 | Parameters: 34 | secretPassword: 35 | Type: string 36 | Description: database password 37 | NoEcho: true # keep it secret, keep it safe 38 | # use the parameters here 39 | Resources: 40 | TheDatabase: 41 | Type: AWS::RDS::DBInstance 42 | Properties: 43 | Engine: MySQL 44 | DBInstanceIdentifier: MySQL 45 | DBName: MySQL 46 | MultiAZ: true 47 | PubliclyAccessible: true 48 | MasterUsername: root 49 | MasterUserPassword: { Ref: secretPassword } # you can also send this to a lambda's env var 50 | DBInstanceClass: db.t2.large 51 | AllocatedStorage: 100 52 | DBSubnetGroupName: 53 | Ref: DBSubnetGroup # not included in this example 54 | VPCSecurityGroups: 55 | - Ref: DBSecurityGroup # not included in this example 56 | ``` 57 | 58 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const deployWithParameters = require('./lib/deployWithParameters') 4 | 5 | class ServerlessCloudFormationParameterSetter { 6 | constructor (serverless, options) { 7 | try { 8 | this.serverless = serverless 9 | this.provider = this.serverless.getProvider('aws') 10 | 11 | let awsDeploy = serverless.pluginManager.plugins.find(p => p.constructor.name === 'AwsDeploy') 12 | awsDeploy.options.cfParameters = serverless.service && serverless.service.custom && serverless.service.custom['cf-parameters'] 13 | awsDeploy.createParameters = deployWithParameters.createParameters 14 | awsDeploy.createFallback = Function(awsDeploy.createFallback.toString().replace('Parameters: [],', 'Parameters: this.createParameters(this.options.cfParameters, this.serverless.service.provider.compiledCloudFormationTemplate, false),').slice(18,-1)) 15 | awsDeploy.update = Function( 16 | awsDeploy.update.toString() 17 | .replace('Parameters: [],', 'Parameters: this.createParameters(this.options.cfParameters, this.serverless.service.provider.compiledCloudFormationTemplate, true),') 18 | .replace('NO_UPDATE_MESSAGE', '"No updates are to be performed."') 19 | .slice(10,-1)) 20 | } catch (e) { 21 | console.log('Error initializing serverless-cloudformation-parameters', e) 22 | throw e 23 | } 24 | } 25 | } 26 | 27 | module.exports = ServerlessCloudFormationParameterSetter 28 | -------------------------------------------------------------------------------- /lib/deployWithParameters.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // const _ = require('lodash'); 4 | // const BbPromise = require('bluebird'); 5 | 6 | // const NO_UPDATE_MESSAGE = 'No updates are to be performed.'; 7 | 8 | module.exports = { 9 | createParameters(paramsObject, template, allowPreviousValues) { 10 | this.serverless.cli.log('Determining cloudformation parameters...') 11 | let params = [] 12 | if (template.Parameters) { 13 | Object.keys(template.Parameters).forEach(k => { 14 | if (allowPreviousValues && (paramsObject[k] === null || paramsObject[k] === undefined)) { 15 | params.push({ 16 | ParameterKey: k, 17 | UsePreviousValue: true 18 | }) 19 | } else { 20 | params.push({ 21 | ParameterKey: k, 22 | ParameterValue: paramsObject[k] 23 | }) 24 | } 25 | }) 26 | } 27 | return params 28 | }, 29 | // the following functions are unused they are just copied from the AWS deploy plugin for reference 30 | createFallback() { 31 | this.createLater = false; 32 | this.serverless.cli.log('Creating Stack...'); 33 | 34 | const stackName = this.provider.naming.getStackName(); 35 | let stackTags = { STAGE: this.options.stage }; 36 | const compiledTemplateFileName = 'compiled-cloudformation-template.json'; 37 | const templateUrl = `https://s3.amazonaws.com/${this.bucketName}/${this.serverless.service.package.artifactDirectoryName}/${compiledTemplateFileName}`; 38 | 39 | // Merge additional stack tags 40 | if (typeof this.serverless.service.provider.stackTags === 'object') { 41 | stackTags = _.extend(stackTags, this.serverless.service.provider.stackTags); 42 | } 43 | 44 | const params = { 45 | StackName: stackName, 46 | OnFailure: 'ROLLBACK', 47 | Capabilities: [ 48 | 'CAPABILITY_IAM', 49 | 'CAPABILITY_NAMED_IAM', 50 | ], 51 | Parameters: this.createParameters(this.options.cfParameters, this.serverless.service.provider.compiledCloudFormationTemplate, false), 52 | TemplateURL: templateUrl, 53 | Tags: Object.keys(stackTags).map((key) => ({ Key: key, Value: stackTags[key] })), 54 | }; 55 | 56 | if (this.serverless.service.provider.cfnRole) { 57 | params.RoleARN = this.serverless.service.provider.cfnRole; 58 | } 59 | 60 | return this.provider.request('CloudFormation', 61 | 'createStack', 62 | params, 63 | this.options.stage, 64 | this.options.region) 65 | .then((cfData) => this.monitorStack('create', cfData)); 66 | }, 67 | 68 | update() { 69 | const compiledTemplateFileName = 'compiled-cloudformation-template.json'; 70 | const templateUrl = `https://s3.amazonaws.com/${this.bucketName}/${this.serverless.service.package.artifactDirectoryName}/${compiledTemplateFileName}`; 71 | this.serverless.cli.log('Updating Stack...'); 72 | const stackName = this.provider.naming.getStackName(); 73 | let stackTags = { STAGE: this.options.stage }; 74 | 75 | // Merge additional stack tags 76 | if (typeof this.serverless.service.provider.stackTags === 'object') { 77 | stackTags = _.extend(stackTags, this.serverless.service.provider.stackTags); 78 | } 79 | 80 | const params = { 81 | StackName: stackName, 82 | Capabilities: [ 83 | 'CAPABILITY_IAM', 84 | 'CAPABILITY_NAMED_IAM', 85 | ], 86 | Parameters: this.createParameters(this.options.cfParameters, this.serverless.service.provider.compiledCloudFormationTemplate, true), 87 | TemplateURL: templateUrl, 88 | Tags: Object.keys(stackTags).map((key) => ({ Key: key, Value: stackTags[key] })), 89 | }; 90 | 91 | if (this.serverless.service.provider.cfnRole) { 92 | params.RoleARN = this.serverless.service.provider.cfnRole; 93 | } 94 | 95 | // Policy must have at least one statement, otherwise no updates would be possible at all 96 | if (this.serverless.service.provider.stackPolicy && 97 | this.serverless.service.provider.stackPolicy.length) { 98 | params.StackPolicyBody = JSON.stringify({ 99 | Statement: this.serverless.service.provider.stackPolicy, 100 | }); 101 | } 102 | 103 | return this.provider.request('CloudFormation', 104 | 'updateStack', 105 | params, 106 | this.options.stage, 107 | this.options.region) 108 | .then((cfData) => this.monitorStack('update', cfData)) 109 | .catch((e) => { 110 | if (e.message === NO_UPDATE_MESSAGE) { 111 | return; 112 | } 113 | throw e; 114 | }); 115 | }, 116 | 117 | updateStack() { 118 | console.log('us') 119 | return BbPromise.bind(this) 120 | .then(() => { 121 | if (this.createLater) { 122 | console.log('us cl') 123 | return BbPromise.bind(this) 124 | .then(this.createFallback); 125 | } 126 | console.log('us cn') 127 | return BbPromise.bind(this) 128 | .then(this.update); 129 | }); 130 | }, 131 | }; 132 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-cloudformation-parameter-setter", 3 | "version": "0.0.1", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Trek10, Inc", 3 | "bugs": { 4 | "url": "https://github.com/trek10inc/serverless-cloudformation-parameter-setter/issues" 5 | }, 6 | "dependencies": {}, 7 | "description": "A serverless plugin for creating setting CloudFormation Parameters", 8 | "devDependencies": {}, 9 | "engines": { 10 | "node": ">=6.0" 11 | }, 12 | "homepage": "https://github.com/trek10inc/serverless-cloudformation-parameter-setter", 13 | "keywords": [ 14 | "serverless", 15 | "serverless plugin", 16 | "serverless cloudformation parameters", 17 | "cloudformation parameters", 18 | "aws" 19 | ], 20 | "license": "MIT", 21 | "main": "index.js", 22 | "name": "serverless-cloudformation-parameter-setter", 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/trek10inc/serverless-cloudformation-parameter-setter" 26 | }, 27 | "scripts": {}, 28 | "version": "0.0.1" 29 | } 30 | --------------------------------------------------------------------------------