deploy resources: complete command

This commit is contained in:
Austen Collins 2015-09-24 12:03:21 -07:00
parent 54f4e5a6b6
commit a2dce9c8be
7 changed files with 209 additions and 41 deletions

View File

@ -288,7 +288,7 @@ Deployer.prototype.deploy = Promise.method(function() {
})
.then(function() {
spinner.stop(true);
})
});
}
})
.then(function() {

View File

@ -2,10 +2,9 @@
/**
* JAWS Command: deploy resources <stage> <region>
* - Deploys project's API Gateway REST API to the specified stage and one or all regions
* - Deploys project's resources-cf.json
*/
var JawsError = require('../jaws-error'),
JawsCli = require('../utils/cli'),
Promise = require('bluebird'),
@ -27,8 +26,8 @@ Promise.promisifyAll(fs);
* @returns {*}
*/
module.exports.run = function(JAWS, stage, region, allTagged) {
var command = new CMD(JAWS, stage, region, allTagged);
module.exports.run = function(JAWS, stage, region) {
var command = new CMD(JAWS, stage, region);
return command.run();
};
@ -37,18 +36,13 @@ module.exports.run = function(JAWS, stage, region, allTagged) {
* @param JAWS
* @param stage
* @param region
* @param allTagged
* @constructor
*/
function CMD(JAWS, stage, region, allTagged) {
function CMD(JAWS, stage, region) {
var _this = this;
_this._stage = stage;
_this._allTagged = allTagged;
_this._JAWS = JAWS;
_this._prjJson = JAWS._meta.projectJson;
_this._prjRootPath = JAWS._meta.projectRootPath;
_this._prjCreds = JAWS._meta.credentials;
if (region && stage) {
_this._regions = _this._JAWS._meta.projectJson.stages[_this._stage].filter(function(r) {
@ -70,43 +64,34 @@ CMD.prototype.run = Promise.method(function() {
// Flow
return _this._JAWS.validateProject()
.bind(_this)
.then(function() {
// If !allTagged, tag current directory
if (!_this._allTagged) {
return CMDtag.tag('endpoint', null, false);
.then(_this._promptStage)
.then(function(answer) {
if (answer) _this._stage = answer[0].value;
})
.then(_this._promptRegions)
.then(function(answer) {
if (answer) {
_this._regions = [utils.getProjRegionConfigForStage(_this._JAWS, _this._stage, answer[0].value)];
}
})
.then(_this._promptStage)
.then(_this._promptRegions)
.then(function() {
return _this._regions;
})
.each(function(regionJson) {
JawsCli.log('Endpoint Deployer: Deploying endpoint(s) to region "' + regionJson.region + '"...');
JawsCli.log('Resources Deployer "'
+ _this._stage
+ '": Deploying resources to region "'
+ regionJson.region
+ '"...');
var deployer = new ApiDeployer(
var deployer = new ResourceDeployer(
_this._JAWS,
_this._stage,
regionJson,
_this._prjRootPath,
_this._prjJson,
_this._prjCreds
regionJson
);
return deployer.deploy()
.then(function(url) {
JawsCli.log('Endpoint Deployer: Endpoints for stage "'
+ _this._stage
+ '" successfully deployed to API Gateway in the region "'
+ regionJson.region
+ '". Access them @ '
+ url);
});
})
.then(function() {
// Untag All tagged endpoints
return _this._allTagged ? CMDtag.tagAll(_this._JAWS, 'endpoint', true) : CMDtag.tag('endpoint', null, true);
return deployer.deploy();
});
});
@ -121,7 +106,7 @@ CMD.prototype._promptStage = Promise.method(function() {
// If stage, skip
if (_this._stage) return;
var stages = Object.keys(_this._prjJson.stages);
var stages = Object.keys(_this._JAWS._meta.projectJson.stages);
if (!stages.length) {
throw new JawsError('You have no stages in this project');
}
@ -175,3 +160,76 @@ CMD.prototype._promptRegions = Promise.method(function() {
return JawsCli.select('Select a region in this stage to deploy to: ', choices, false);
});
/**
* Resource Deployer
* @param JAWS
* @param stage
* @param region
* @constructor
*/
function ResourceDeployer(JAWS, stage, region) {
var _this = this;
_this._JAWS = JAWS;
_this._stage = stage;
_this._regionJson = region;
}
/**
* Resource Deployer: Deploy
*/
ResourceDeployer.prototype.deploy = Promise.method(function() {
var _this = this;
JawsCli.log('Resources Deployer "'
+ _this._stage
+ ' - '
+ _this._regionJson.region
+ '": Performing Cloudformation stack update. '
+ 'This could take a while depending on how many resources you are updating...');
var spinner = JawsCli.spinner();
spinner.start();
return _this._updateStack()
.bind(_this)
.then(function(cfData) {
return AWSUtils.monitorCf(cfData, _this._JAWS._meta.profile, _this._regionJson.region, 'update');
})
.then(function(data) {
spinner.stop(true);
JawsCli.log('Resources Deployer "'
+ _this._stage
+ ' - '
+ _this._regionJson.region
+ '": Cloudformation stack update completed successfully!');
})
.catch(function(error) {
spinner.stop(true);
JawsCli.log('Resources Deployer "'
+ _this._stage
+ ' - '
+ _this._regionJson.region
+ '": Cloudformation stack update failed because of the following error...');
console.log(error);
});
});
/**
* Resource Deployer: Update Stack
*/
ResourceDeployer.prototype._updateStack = Promise.method(function() {
var _this = this;
// Fetch Cloudformation template
return AWSUtils.cfUpdateResourcesStack(
_this._JAWS,
_this._stage,
_this._regionJson.region);
});

View File

@ -144,6 +144,19 @@ CMD.prototype._prompt = Promise.method(function() {
},
};
// Prompt: notification email - for AWS alerts
_this.Prompter.override.notificationEmail = _this._notificationEmail;
_this._prompts.properties.notificationEmail = {
description: 'Enter an email to use for AWS alarms: '.yellow,
required: true,
message: 'Please enter a valid email',
default: 'you@yourapp.com',
conform: function(email) {
if (!email) return false;
return true;
},
};
// Prompt: s3 bucket - holds env vars for this project
_this.Prompter.override.s3Bucket = _this._s3Bucket;
_this._prompts.properties.s3Bucket = {

View File

@ -215,7 +215,7 @@ CMD.prototype._validate = Promise.method(function() {
// Make sure region is not already defined
if (_this._JAWS._meta.projectJson.stages[_this._stage].some(function(r) {
return r.region == _this._region
return r.region == _this._region;
})) {
throw new JawsError('Region "' + _this._region + '" is already defined in the stage "' + _this._stage + '"');
}

View File

@ -19,7 +19,7 @@ exports.validLambdaRegions = [
'us-east-1',
'us-west-2', //oregon
'eu-west-1', //Ireland
'ap-northeast-1' //Tokyo
'ap-northeast-1', //Tokyo
];
/**
@ -456,7 +456,7 @@ exports.cfUpdateLambdasStack = function(JAWS, stage, region, lambdaRoleArn) {
};
/**
* CloudFormation: Create Stack
* CloudFormation: Create Resources Stack
* @param awsProfile
* @param awsRegion
* @param projRootPath
@ -520,6 +520,45 @@ exports.cfCreateResourcesStack = function(awsProfile, awsRegion, projRootPath, p
});
};
/**
* CloudFormation: Update Resources Stack
* @param JAWS
* @param stage
* @param region
* @returns {*}
*/
exports.cfUpdateResourcesStack = function(JAWS, stage, region) {
var _this = this,
awsProfile = JAWS._meta.profile,
projRootPath = JAWS._meta.projectRootPath,
bucketName = JAWS._meta.projectJson.jawsBuckets[region],
projName = JAWS._meta.projectJson.name;
_this.configAWS(awsProfile, region);
var CF = Promise.promisifyAll(new AWS.CloudFormation({
apiVersion: '2010-05-15',
})),
stackName = _this.cfGetResourcesStackName(stage, projName);
var params = {
StackName: stackName,
Capabilities: [
'CAPABILITY_IAM',
],
UsePreviousTemplate: false,
Parameters: []
};
return _this.putCfFile(awsProfile, projRootPath, region, bucketName, projName, stage, 'resources')
.then(function(templateUrl) {
params.TemplateURL = templateUrl;
return CF.updateStackAsync(params);
});
};
/**
* CloudFormation: Monitor CF Stack Status (Create/Update)
* @param cfData
@ -878,7 +917,7 @@ exports.lambdaRemovePermission = function(awsProfile, awsRegion, functionName, s
var params = {
FunctionName: functionName, /* required */
StatementId: statementId /* required */
StatementId: statementId, /* required */
};
return new Promise(function(resolve, reject) {

View File

@ -26,6 +26,7 @@ describe('AllTests', function() {
*/
//require('./cli/dash');
//require('./cli/deploy_lambda');
//require('./cli/deploy_resources');
//require('./cli/deploy_endpoint');
//require('./cli/new_stage_region');
//require('./cli/new_project');

View File

@ -0,0 +1,57 @@
'use strict';
/**
* JAWS Test: Deploy Resources
*/
var Jaws = require('../../lib/index.js'),
CmdDeployResources = require('../../lib/commands/deploy_resources'),
CmdTag = require('../../lib/commands/tag'),
JawsError = require('../../lib/jaws-error'),
testUtils = require('../test_utils'),
Promise = require('bluebird'),
path = require('path'),
assert = require('chai').assert,
config = require('../config'),
lambdaPaths = {},
projPath,
JAWS;
describe('Test deploy resources command', function() {
before(function(done) {
testUtils.createTestProject(
config.name,
config.region,
config.stage,
config.iamRoleArnLambda,
config.iamRoleArnApiGateway,
config.usEast1Bucket)
.then(function(pp) {
projPath = pp;
process.chdir(path.join(projPath));
JAWS = new Jaws();
})
.then(done);
});
describe('Positive tests', function() {
it('Deploy Resources', function(done) {
this.timeout(0);
CmdDeployResources.run(JAWS, config.stage, config.region)
.then(function() {
done();
})
.catch(JawsError, function(e) {
done(e);
})
.error(function(e) {
console.log(e);
done(e);
});
});
});
});