@incdevco/framework
Version:
node.js lambda framework
314 lines (179 loc) • 6.88 kB
JavaScript
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;
});
};