UNPKG

@incdevco/framework

Version:
314 lines (179 loc) 6.88 kB
var fs = require('fs'); var AWS = require('aws-sdk'); var gutil = require('gulp-util'); var mkdirp = require('mkdirp'); var Promise = require('bluebird'); var Prompt = require('../../prompt'); var Utilities = require('../../utilities'); var pluginName = 'cloud-formation-stack'; module.exports = function (stackName, params, config) { 'use strict'; var action = 'CREATE'; var cf; var changeSetName; var stack; config = config || {}; config.cf = config.cf || new AWS.CloudFormation(); config.temp = config.temp || 'dist/cf'; cf = config.cf; changeSetName = config.changeSetName || stackName + '-' + Utilities.getMoment().format('MM-DD-YYYY-HH-mm-ss'); params.StackName = stackName; params.ChangeSetName = changeSetName; mkdirp.sync(config.temp); function cfCall(fn, params) { return cf[fn](params).promise() .catch(function (exception) { //console.log('cf', fn, params, exception); if (exception.code === 'Throttling') { return Promise.delay(1000) .then(function() { return cfCall(fn, params); }); } throw exception; }); } return cfCall('describeStacks', { StackName: stackName }) .then(function (result) { result.Stacks.forEach(function (resultStack) { if (stackName === resultStack.StackName) { action = 'UPDATE'; stack = resultStack; } }); return true; }, function (exception) { if (exception.message === 'Stack with id ' + stackName + ' does not exist') { return false; } throw exception; }) .then(function () { params.ChangeSetType = action; //console.log('cf.createChangeSet', JSON.stringify(params, null, 2)); return cfCall('createChangeSet', params); }) .then(function () { var changeSet; var nextToken; function describeChangeSet(params) { params.NextToken = nextToken; return cfCall('describeChangeSet', params) .then(function (result) { if (!changeSet) { changeSet = result; } else { changeSet.Changes = changeSet.Changes.concat(result.Changes); } if (result.Status === 'CREATE_PENDING' || result.Status === 'CREATE_IN_PROGRESS') { changeSet = undefined; return Promise.delay(1000) .then(function () { return describeChangeSet(params); }); } if (result.NextToken) { nextToken = result.NextToken; return Promise.delay(100) .then(function () { return describeChangeSet(params); }); } else { return changeSet; } }); } return describeChangeSet({ ChangeSetName: changeSetName, StackName: stackName }); }) .then(function (changeSet) { var fileName = config.temp + '/' + changeSetName + '.json'; fs.writeFileSync(fileName, JSON.stringify(changeSet, null, 2), 'utf8'); if (changeSet.Status === 'FAILED' && changeSet.ExecutionStatus === 'UNAVAILABLE' && changeSet.Changes.length === 0) { gutil.log('No Changes Available'); return stack; } else { return Promise.try(function () { if (gutil.env.yes) { return true; } else { return Prompt.get({ properties: { execute_change_set: { message: 'Do you want to execute this change set? y/n' } } }) .then(function (result) { if (result.execute_change_set.indexOf('y') === 0) { return true; } else { return false; } }); } }) .then(function (executeChangeSet) { if (executeChangeSet) { return cfCall('executeChangeSet', { ChangeSetName: changeSetName, StackName: stackName }) .then(function () { function describeStacksUntilComplete(params) { return cfCall('describeStacks', params) .then(function (result) { var stack; result.Stacks.forEach(function (result) { if (result.StackName === stackName) { stack = result; } }); if (stack) { if (stack.StackStatus === action + '_COMPLETE') { return stack; } else if (stack.StackStatus === 'ROLLBACK_COMPLETE' || stack.StackStatus === 'UPDATE_ROLLBACK_COMPLETE') { throw new gutil.PluginError(pluginName, new Error(action + ' Stack Failed')); } else { return Promise.delay(1000) .then(function () { return describeStacksUntilComplete(params); }); } } else { return Promise.delay(1000) .then(function () { return describeStacksUntilComplete(params); }); } }); } return describeStacksUntilComplete({ StackName: stackName }); }); } else { return stack; } }); } }) .then(function (stack) { if (stack && stack.Outputs) { stack.Output = {}; stack.Outputs.forEach(function (output) { stack.Output[output.OutputKey] = output.OutputValue; }); } return stack; }); };