mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
refactor
This commit is contained in:
parent
eedfd4421c
commit
69c5e53472
31
lib/Jaws.js
31
lib/Jaws.js
@ -40,8 +40,8 @@ class Jaws {
|
||||
silent: silent,
|
||||
path: path.join(this._projectRootPath, 'admin.env'),
|
||||
});
|
||||
this._profile = process.env.JAWS_ADMIN_AWS_PROFILE;
|
||||
this._credentials = AWSUtils.profilesGet(this._profile)[this._profile];
|
||||
this._awsProfile = process.env.JAWS_ADMIN_AWS_PROFILE;
|
||||
this._credentials = AWSUtils.profilesGet(this._awsProfile)[this._awsProfile];
|
||||
}
|
||||
|
||||
// TODO: Remove these eventually, keeping them for reference...
|
||||
@ -148,14 +148,14 @@ class Jaws {
|
||||
*/
|
||||
_executeQueue(queue) {
|
||||
return Promise.try(() => {
|
||||
return queue;
|
||||
})
|
||||
.each(function(p) {
|
||||
return p();
|
||||
})
|
||||
.catch(function(error) {
|
||||
throw new JawsError(error);
|
||||
});
|
||||
return queue;
|
||||
})
|
||||
.each(function(p) {
|
||||
return p();
|
||||
})
|
||||
.catch(function(error) {
|
||||
throw new JawsError(error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -192,6 +192,17 @@ class Jaws {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
command(argv) {
|
||||
JawsUtils.jawsDebug('command argv', argv);
|
||||
|
||||
if (argv.version) {
|
||||
console.log(this._version);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (argv.help) {
|
||||
//TODO: spit out cli help
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Check if command context and action are defined
|
||||
if (!this.commands[argv._[0]] || !this.commands[argv._[0]][argv._[1]]) {
|
||||
|
||||
@ -75,7 +75,7 @@ class JawsPlugin {
|
||||
//TODO: implement
|
||||
return Promise.reject(new JawsError('Not implemented', JawsError.errorCodes.UNKNOWN));
|
||||
} else {
|
||||
return Promise.reject(new JawsError('You must specify all necessary options when in a non-interactive mode', JawsError.errorCodes.UNKNOWN));
|
||||
return Promise.resolve(); //in non interactive mode. All options must be set programatically
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ class ApiDeployer {
|
||||
let _this = this;
|
||||
|
||||
return AWSUtils.cfGetLambdaResourceSummaries(
|
||||
_this._JAWS._profile,
|
||||
_this._JAWS._awsProfile,
|
||||
_this._regionJson.region,
|
||||
AWSUtils.cfGetLambdasStackName(_this._stage, _this._JAWS._projectJson.name)
|
||||
)
|
||||
@ -701,7 +701,7 @@ class ApiDeployer {
|
||||
let _this = this;
|
||||
|
||||
return AWSUtils.lambdaGetPolicy(
|
||||
_this._JAWS._meta.profile,
|
||||
_this._JAWS._awsProfile,
|
||||
_this._regionJson.region,
|
||||
endpoint.apiGateway.apig.lambda.PhysicalResourceId)
|
||||
.then(function(data) {
|
||||
@ -737,7 +737,7 @@ class ApiDeployer {
|
||||
if (!statement) return Promise.resolve(endpoint);
|
||||
|
||||
return AWSUtils.lambdaRemovePermission(
|
||||
_this._JAWS._meta.profile,
|
||||
_this._JAWS._awsProfile,
|
||||
_this._regionJson.region,
|
||||
endpoint.apiGateway.apig.lambda.PhysicalResourceId,
|
||||
'jaws-apigateway-access')
|
||||
@ -792,7 +792,7 @@ class ApiDeployer {
|
||||
+ endpoint.apiGateway.cloudFormation.Path;
|
||||
|
||||
return AWSUtils.lambdaAddPermission(
|
||||
_this._JAWS._meta.profile,
|
||||
_this._JAWS._awsProfile,
|
||||
_this._regionJson.region,
|
||||
statement)
|
||||
.then(function(data) {
|
||||
|
||||
@ -185,7 +185,7 @@ const ResourceDeployer = class ResourceDeployer extends ProjectCmd {
|
||||
return _this._updateStack()
|
||||
.bind(_this)
|
||||
.then(function(cfData) {
|
||||
return AWSUtils.monitorCf(cfData, _this._JAWS._meta.profile, _this._regionJson.region, 'update');
|
||||
return AWSUtils.monitorCf(cfData, _this._JAWS._awsProfile, _this._regionJson.region, 'update');
|
||||
})
|
||||
.then(function(data) {
|
||||
spinner.stop(true);
|
||||
|
||||
@ -32,7 +32,7 @@ let CMD = class JawsEnv extends ProjectCmd {
|
||||
let deferred;
|
||||
|
||||
if (_this._stage == 'local') {
|
||||
deferred = Promise.resolve(fs.readFileSync(path.join(_this._JAWS._meta.projectRootPath, '.env')));
|
||||
deferred = Promise.resolve(fs.readFileSync(path.join(_this._JAWS._projectRootPath, '.env')));
|
||||
} else {
|
||||
deferred = _this._JAWS.getEnvFile(_this._region, _this._stage)
|
||||
.then(function(s3ObjData) {
|
||||
@ -94,7 +94,7 @@ let CMD = class JawsEnv extends ProjectCmd {
|
||||
*/
|
||||
listEnv(showWhereUsed) {
|
||||
let _this = this,
|
||||
projRootDir = _this._JAWS._meta.projectRootPath,
|
||||
projRootDir = _this._JAWS._projectRootPath,
|
||||
stage = _this._stage;
|
||||
|
||||
return utils.findAllAwsmJsons(path.join(projRootDir, 'aws_modules'))
|
||||
@ -208,7 +208,7 @@ let CMD = class JawsEnv extends ProjectCmd {
|
||||
});
|
||||
|
||||
if (_this._stage == 'local') {
|
||||
putEnvQ.push(utils.writeFile(path.join(_this._JAWS._meta.projectRootPath, '.env'), contents));
|
||||
putEnvQ.push(utils.writeFile(path.join(_this._JAWS._projectRootPath, '.env'), contents));
|
||||
} else {
|
||||
putEnvQ.push(_this._JAWS.putEnvFile(mapForRegion.regionName, _this._stage, contents));
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ const CMD = class ModuleCreate extends ProjectCmd {
|
||||
if (_this._module.pkgMgr == 'npm') {
|
||||
|
||||
let modulePath = path.join(
|
||||
_this._JAWS._meta.projectRootPath, //TOOD: make this CWD if not in a JAWS project
|
||||
_this._JAWS._projectRootPath, //TOOD: make this CWD if not in a JAWS project
|
||||
'node_modules',
|
||||
_this._module.name);
|
||||
let templatesPath = path.join(__dirname, '..', 'templates');
|
||||
@ -207,7 +207,7 @@ const CMD = class ModuleCreate extends ProjectCmd {
|
||||
let templatesPath = path.join(__dirname, '..', 'templates');
|
||||
let actionTemplateJson = utils.readAndParseJsonSync(path.join(templatesPath, 'action.awsm.json'));
|
||||
let modulePath = path.join(
|
||||
_this._JAWS._meta.projectRootPath, //TOOD: make this CWD if not in a JAWS project
|
||||
_this._JAWS._projectRootPath, //TOOD: make this CWD if not in a JAWS project
|
||||
'aws_modules',
|
||||
_this._module.name);
|
||||
let actionPath = path.join(modulePath, _this._module.action);
|
||||
|
||||
@ -136,7 +136,7 @@ const CMD = class ModuleCreate extends ProjectCmd {
|
||||
_installFiles(tempDirPath) {
|
||||
let _this = this,
|
||||
srcAwsmJsonPath = path.join(tempDirPath, 'awsm.json'),
|
||||
awsModsPath = path.join(_this._JAWS._meta.projectRootPath, 'aws_modules');
|
||||
awsModsPath = path.join(_this._JAWS._projectRootPath, 'aws_modules');
|
||||
|
||||
if (!utils.fileExistsSync(srcAwsmJsonPath)) {
|
||||
return Promise.reject(new JawsError('Module missing awsm.json file in root of project', JawsError.errorCodes.UNKNOWN));
|
||||
|
||||
@ -1,553 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* JAWS Command: project create
|
||||
* - Asks the user for information about their new JAWS project
|
||||
* - Creates a new project in the current working directory
|
||||
* - Creates IAM resources via CloudFormation
|
||||
*/
|
||||
|
||||
const GlobalCmd = require('./GlobalCmd'),
|
||||
JawsError = require('../jaws-error'),
|
||||
JawsCLI = require('../utils/cli'),
|
||||
Promise = require('bluebird'),
|
||||
path = require('path'),
|
||||
os = require('os'),
|
||||
AWSUtils = require('../utils/aws'),
|
||||
utils = require('../utils'),
|
||||
shortid = require('shortid');
|
||||
|
||||
let fs = require('fs');
|
||||
Promise.promisifyAll(fs);
|
||||
|
||||
function generateShortId(maxLen) {
|
||||
return shortid.generate().replace(/\W+/g, '').substring(0, maxLen).replace(/[_-]/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* CMD Class
|
||||
* @param name
|
||||
* @param stage
|
||||
* @param domain
|
||||
* @param notificationEmail
|
||||
* @param region
|
||||
* @param profile
|
||||
* @param noCf
|
||||
* @param runtime
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
const CMD = class ProjectCreate extends GlobalCmd {
|
||||
constructor(name, stage, region, domain, notificationEmail, profile, noCf, runtime) {
|
||||
super();
|
||||
|
||||
// Defaults
|
||||
this._name = name ? name : null;
|
||||
this._domain = domain ? domain : null;
|
||||
this._stage = stage ? stage.toLowerCase().replace(/\W+/g, '').substring(0, 15) : null;
|
||||
this._notificationEmail = notificationEmail;
|
||||
this._region = region;
|
||||
this._profile = profile;
|
||||
this._runtime = runtime ? runtime : 'nodejs';
|
||||
this._noCf = noCf;
|
||||
this._prompts = {
|
||||
properties: {},
|
||||
};
|
||||
this.Prompter = JawsCLI.prompt();
|
||||
this.Prompter.override = {};
|
||||
this._spinner = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Run
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
run() {
|
||||
let _this = this;
|
||||
|
||||
return Promise.try(function() {
|
||||
|
||||
// ASCII Greeting
|
||||
JawsCLI.ascii();
|
||||
|
||||
})
|
||||
.bind(_this)
|
||||
.then(_this._prompt)
|
||||
.then(_this._prepareProjectData)
|
||||
.then(_this._createProjectDirectory)
|
||||
.then(function() {
|
||||
if (_this._noCf) {
|
||||
let stackResourcesName = AWSUtils.cfGetResourcesStackName(
|
||||
_this._stage,
|
||||
_this._name
|
||||
);
|
||||
|
||||
JawsCLI.log('Remember to run CloudFormation manually');
|
||||
JawsCLI.log(`MAKE SURE to create stack with name: ${stackResourcesName}`);
|
||||
JawsCLI.log('After creating CF stack, remember to put the IAM role outputs and jawsBucket in your '
|
||||
+ 'project jaws.json in the right stage/region.');
|
||||
return false;
|
||||
} else {
|
||||
return _this._createCfStack()
|
||||
.bind(_this)
|
||||
.then(function(cfData) {
|
||||
if (_this._spinner) {
|
||||
_this._spinner.stop(true);
|
||||
}
|
||||
_this._cfData = cfData;
|
||||
})
|
||||
.then(_this._putEnvFile)
|
||||
.then(_this._putCfFile);
|
||||
}
|
||||
})
|
||||
.then(_this._createProjectJson)
|
||||
.then(_this._initRuntime)
|
||||
.then(function() {
|
||||
JawsCLI.log('Your project "' + _this._name
|
||||
+ '" has been successfully created in the current directory.');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prompt
|
||||
* @private
|
||||
*/
|
||||
|
||||
_prompt() {
|
||||
|
||||
utils.jawsDebug('Prompting for new project information');
|
||||
let _this = this;
|
||||
|
||||
let nameDescription = 'Enter a project name: ';
|
||||
|
||||
// Prompt: name (project name)
|
||||
_this.Prompter.override.name = _this._name;
|
||||
_this._prompts.properties.name = {
|
||||
description: nameDescription.yellow,
|
||||
default: 'jaws-' + generateShortId(19),
|
||||
message: 'Name must be only letters, numbers or dashes',
|
||||
conform: function(name) {
|
||||
let re = /^[a-zA-Z0-9-_]+$/;
|
||||
return re.test(name);
|
||||
},
|
||||
};
|
||||
|
||||
// Prompt: domain - for AWS hosted zone and more
|
||||
_this.Prompter.override.domain = _this._domain;
|
||||
|
||||
let domainDescription = 'Enter a project domain (You can change this at any time: ';
|
||||
|
||||
_this._prompts.properties.domain = {
|
||||
description: domainDescription.yellow,
|
||||
default: 'myapp.com',
|
||||
message: 'Domain must only contain lowercase letters, numbers, periods and dashes',
|
||||
conform: function(bucket) {
|
||||
let re = /^[a-z0-9-.]+$/;
|
||||
return re.test(bucket);
|
||||
},
|
||||
};
|
||||
|
||||
// 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: 'me@myapp.com',
|
||||
conform: function(email) {
|
||||
if (!email) return false;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// Prompt: stage
|
||||
_this.Prompter.override.stage = _this._stage;
|
||||
|
||||
let stageDescription = 'Enter a stage for this project: ';
|
||||
|
||||
_this._prompts.properties.stage = {
|
||||
description: stageDescription.yellow,
|
||||
default: 'dev',
|
||||
message: 'Stage must be letters only',
|
||||
conform: function(stage) {
|
||||
let re = /^[a-zA-Z]+$/;
|
||||
return re.test(stage);
|
||||
},
|
||||
};
|
||||
|
||||
// Prompt: notification email - for AWS alerts
|
||||
_this.Prompter.override.notificationEmail = _this._notificationEmail;
|
||||
|
||||
let notificationEmailDescription = 'Enter an email to use for AWS alarms: ';
|
||||
|
||||
_this._prompts.properties.notificationEmail = {
|
||||
description: notificationEmailDescription.yellow,
|
||||
required: true,
|
||||
message: 'Please enter a valid email',
|
||||
default: 'you@yourapp.com',
|
||||
conform: function(email) {
|
||||
if (!email) return false;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// Prompt: API Keys - Create an AWS profile by entering API keys
|
||||
if (!utils.fileExistsSync(path.join(AWSUtils.getConfigDir(), 'credentials'))) {
|
||||
|
||||
_this.Prompter.override.awsAdminKeyId = _this._awsAdminKeyId;
|
||||
|
||||
let apiKeyDescription = 'Enter the ACCESS KEY ID for your Admin AWS IAM User: ';
|
||||
|
||||
_this._prompts.properties.awsAdminKeyId = {
|
||||
description: apiKeyDescription.yellow,
|
||||
required: true,
|
||||
message: 'Please enter a valid access key ID',
|
||||
conform: function(key) {
|
||||
if (!key) return false;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
_this.Prompter.override.awsAdminSecretKey = _this._awsAdminSecretKey;
|
||||
|
||||
let apiSecretDescription = 'Enter the SECRET ACCESS KEY for your Admin AWS IAM User: ';
|
||||
|
||||
_this._prompts.properties.awsAdminSecretKey = {
|
||||
description: apiSecretDescription.yellow,
|
||||
required: true,
|
||||
message: 'Please enter a valid secret access key',
|
||||
conform: function(key) {
|
||||
if (!key) return false;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Show Prompts
|
||||
return _this.Prompter.getAsync(_this._prompts)
|
||||
.then(function(answers) {
|
||||
_this._name = answers.name;
|
||||
_this._domain = answers.domain;
|
||||
_this._stage = answers.stage.toLowerCase();
|
||||
_this._notificationEmail = answers.notificationEmail;
|
||||
_this._awsAdminKeyId = answers.awsAdminKeyId;
|
||||
_this._awsAdminSecretKey = answers.awsAdminSecretKey;
|
||||
|
||||
// If region exists, skip select prompt
|
||||
if (_this._region) return;
|
||||
|
||||
// Prompt: region select
|
||||
let choices = [];
|
||||
AWSUtils.validLambdaRegions.forEach(function(r) {
|
||||
choices.push({
|
||||
key: '',
|
||||
value: r,
|
||||
label: r,
|
||||
});
|
||||
});
|
||||
|
||||
return JawsCLI.select('Select a region for your project: ', choices, false)
|
||||
.then(function(results) {
|
||||
_this._region = results[0].value;
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
|
||||
// If profile exists, skip select prompt
|
||||
if (_this._profile) return Promise.resolve();
|
||||
|
||||
// If aws credentials were passed, skip select prompt
|
||||
if (_this._awsAdminKeyId && _this._awsAdminSecretKey) return Promise.resolve();
|
||||
|
||||
// Prompt: profile select
|
||||
let profilesList = AWSUtils.profilesMap(),
|
||||
profiles = Object.keys(profilesList),
|
||||
choices = [];
|
||||
|
||||
for (let i = 0; i < profiles.length; i++) {
|
||||
choices.push({
|
||||
key: '',
|
||||
value: profiles[i],
|
||||
label: profiles[i],
|
||||
});
|
||||
}
|
||||
|
||||
return JawsCLI.select('Select an AWS profile for your project: ', choices, false)
|
||||
.then(function(results) {
|
||||
_this._profile = results[0].value;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Project Data
|
||||
* @private
|
||||
*/
|
||||
|
||||
_prepareProjectData() {
|
||||
|
||||
let _this = this;
|
||||
|
||||
// Validate: Ensure stage isn't "local"
|
||||
if (_this._stage.toLowerCase() == 'local') {
|
||||
throw new JawsError('Stage ' + _this._stage + ' is reserved');
|
||||
}
|
||||
|
||||
// Validate: AWS only allows Alphanumeric and - in name
|
||||
let nameOk = /^([a-zA-Z0-9-]+)$/.exec(_this._name);
|
||||
if (!nameOk) {
|
||||
throw new JawsError('Project names can only be alphanumeric and -');
|
||||
}
|
||||
|
||||
// Append unique id if name is in use
|
||||
if (utils.dirExistsSync(path.join(process.cwd(), _this._name))) {
|
||||
_this._name = _this._name + '-' + generateShortId(19);
|
||||
}
|
||||
|
||||
// Append unique id if domain is default
|
||||
if (_this._domain === 'myapp.com') {
|
||||
_this._domain = 'myapp-' + generateShortId(8) + '.com';
|
||||
}
|
||||
|
||||
// Set JAWS Bucket
|
||||
_this._jawsBucket = utils.generateJawsBucketName(_this._stage, _this._region, _this._domain);
|
||||
|
||||
// Validate: If no profile, ensure access keys, create profile
|
||||
if (!_this._profile) {
|
||||
|
||||
if (!_this._awsAdminKeyId) {
|
||||
throw new JawsError(
|
||||
'An AWS Access Key ID is required',
|
||||
JawsError.errorCodes.MISSING_AWS_CREDS);
|
||||
}
|
||||
|
||||
if (!_this._awsAdminSecretKey) {
|
||||
throw new JawsError(
|
||||
'An AWS Secret Key is required',
|
||||
JawsError.errorCodes.MISSING_AWS_CREDS);
|
||||
}
|
||||
|
||||
// Set profile
|
||||
AWSUtils.profilesSet('default', _this._region, _this._awsAdminKeyId, _this._awsAdminSecretKey);
|
||||
_this._profile = 'default';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create Project Directory
|
||||
* @private
|
||||
*/
|
||||
|
||||
_createProjectDirectory() {
|
||||
let _this = this;
|
||||
|
||||
_this._projectRootPath = path.resolve(path.join(path.dirname('.'), _this._name));
|
||||
|
||||
// Prepare admin.env
|
||||
let adminEnv = 'JAWS_ADMIN_AWS_PROFILE=' + _this._profile + os.EOL;
|
||||
|
||||
// Prepare README.md
|
||||
let readme = '#' + _this._name;
|
||||
|
||||
// Create Project Scaffolding
|
||||
return utils.writeFile(
|
||||
path.join(_this._projectRootPath, '.env'),
|
||||
'JAWS_STAGE=' + _this._stage
|
||||
+ '\nJAWS_DATA_MODEL_STAGE=' + _this._stage
|
||||
)
|
||||
.then(function() {
|
||||
return Promise.all([
|
||||
fs.mkdirAsync(path.join(_this._projectRootPath, 'tests')),
|
||||
fs.mkdirAsync(path.join(_this._projectRootPath, 'lib')),
|
||||
fs.mkdirAsync(path.join(_this._projectRootPath, 'aws_modules')),
|
||||
utils.writeFile(path.join(_this._projectRootPath, 'admin.env'), adminEnv),
|
||||
utils.writeFile(path.join(_this._projectRootPath, 'README.md'), readme),
|
||||
utils.generateResourcesCf(
|
||||
_this._projectRootPath,
|
||||
_this._name,
|
||||
_this._domain,
|
||||
_this._stage,
|
||||
_this._region,
|
||||
_this._notificationEmail,
|
||||
_this._jawsBucket
|
||||
),
|
||||
fs.writeFileAsync(path.join(_this._projectRootPath, '.gitignore'), fs.readFileSync(__dirname + '/../templates/gitignore')),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Put ENV File
|
||||
* - Creates ENV file in JAWS stage/region bucket
|
||||
* @private
|
||||
*/
|
||||
|
||||
_putEnvFile() {
|
||||
|
||||
let _this = this,
|
||||
stage = this.stage;
|
||||
|
||||
let envFileContents = `JAWS_STAGE=${stage}
|
||||
JAWS_DATA_MODEL_STAGE=${stage}`;
|
||||
|
||||
return AWSUtils.putEnvFile(
|
||||
_this._profile,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._name,
|
||||
_this._stage,
|
||||
envFileContents);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Put CF File
|
||||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
|
||||
_putCfFile() {
|
||||
|
||||
let _this = this;
|
||||
|
||||
return AWSUtils.putCfFile(
|
||||
_this._profile,
|
||||
_this._projectRootPath,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._name,
|
||||
_this._stage,
|
||||
'resources');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create CloudFormation Stack
|
||||
* @private
|
||||
*/
|
||||
|
||||
_createCfStack() {
|
||||
|
||||
let _this = this;
|
||||
|
||||
JawsCLI.log('Creating CloudFormation Stack for your new project (~5 mins)...');
|
||||
_this._spinner = JawsCLI.spinner();
|
||||
_this._spinner.start();
|
||||
|
||||
// Create CF stack
|
||||
return AWSUtils.cfCreateResourcesStack(
|
||||
_this._profile,
|
||||
_this._region,
|
||||
_this._projectRootPath,
|
||||
_this._name,
|
||||
_this._stage,
|
||||
_this._domain,
|
||||
_this._notificationEmail,
|
||||
_this._jawsBucket
|
||||
)
|
||||
.then(function(cfData) {
|
||||
return AWSUtils.monitorCf(cfData, _this._profile, _this._region, 'create');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Project JSON
|
||||
* @private
|
||||
*/
|
||||
|
||||
_createProjectJson() {
|
||||
|
||||
let _this = this,
|
||||
iamRoleArnLambda,
|
||||
iamRoleArnApiGateway;
|
||||
|
||||
if (_this._cfData) {
|
||||
for (let i = 0; i < _this._cfData.Outputs.length; i++) {
|
||||
if (_this._cfData.Outputs[i].OutputKey === 'IamRoleArnLambda') {
|
||||
iamRoleArnLambda = _this._cfData.Outputs[i].OutputValue;
|
||||
}
|
||||
|
||||
if (_this._cfData.Outputs[i].OutputKey === 'IamRoleArnApiGateway') {
|
||||
iamRoleArnApiGateway = _this._cfData.Outputs[i].OutputValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let templatesPath = path.join(__dirname, '..', 'templates'),
|
||||
jawsJson = utils.readAndParseJsonSync(path.join(templatesPath, 'jaws.json'));
|
||||
|
||||
jawsJson.stages[_this._stage] = [{
|
||||
region: _this._region,
|
||||
iamRoleArnLambda: iamRoleArnLambda || '',
|
||||
iamRoleArnApiGateway: iamRoleArnApiGateway || '',
|
||||
jawsBucket: _this._jawsBucket,
|
||||
}];
|
||||
|
||||
jawsJson.name = _this._name;
|
||||
jawsJson.domain = _this._domain;
|
||||
|
||||
fs.writeFileSync(path.join(_this._projectRootPath, 'jaws.json'),
|
||||
JSON.stringify(jawsJson, null, 2));
|
||||
|
||||
return jawsJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init Runtime
|
||||
* @private
|
||||
*/
|
||||
|
||||
_initRuntime() {
|
||||
|
||||
let _this = this;
|
||||
|
||||
JawsCLI.log('Preparing your runtime and installing jaws-core module...');
|
||||
|
||||
if (_this._runtime === 'nodejs') {
|
||||
let packageJsonTemplate = utils.readAndParseJsonSync(path.join(__dirname, '..', 'templates', 'nodejs', 'package.json'));
|
||||
packageJsonTemplate.name = _this._name;
|
||||
return fs.writeFileAsync(path.join(_this._projectRootPath, 'package.json'), JSON.stringify(packageJsonTemplate, null, 2))
|
||||
.then(function() {
|
||||
utils.jawsDebug('test_utils', 'Running NPM install...');
|
||||
utils.npmInstall(_this._projectRootPath);
|
||||
});
|
||||
} else {
|
||||
throw new JawsError('Unsupported runtime "' + _this.runtime + '"', JawsError.errorCodes.UNKNOWN);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************
|
||||
* EXPORTS
|
||||
**************************************/
|
||||
|
||||
/**
|
||||
* Run
|
||||
* @param name
|
||||
* @param stage
|
||||
* @param domain
|
||||
* @param region
|
||||
* @param notificationEmail
|
||||
* @param profile
|
||||
* @param noCf
|
||||
* @param runtime defaults to 'nodejs'
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
exports.run = function(name, stage, region, domain, notificationEmail, profile, noCf, runtime) {
|
||||
utils.jawsDebug('Running new project:', name);
|
||||
let command = new CMD(
|
||||
name,
|
||||
stage,
|
||||
region,
|
||||
domain,
|
||||
notificationEmail,
|
||||
profile,
|
||||
noCf,
|
||||
runtime);
|
||||
return command.run();
|
||||
};
|
||||
@ -7,13 +7,13 @@
|
||||
*/
|
||||
|
||||
const ProjectCmd = require('./ProjectCmd.js'),
|
||||
JawsError = require('../jaws-error'),
|
||||
JawsCLI = require('../utils/cli'),
|
||||
Promise = require('bluebird'),
|
||||
os = require('os'),
|
||||
path = require('path'),
|
||||
AWSUtils = require('../utils/aws'),
|
||||
utils = require('../utils');
|
||||
JawsError = require('../jaws-error'),
|
||||
JawsCLI = require('../utils/cli'),
|
||||
Promise = require('bluebird'),
|
||||
os = require('os'),
|
||||
path = require('path'),
|
||||
AWSUtils = require('../utils/aws'),
|
||||
utils = require('../utils');
|
||||
|
||||
let fs = require('fs');
|
||||
|
||||
@ -22,10 +22,10 @@ Promise.promisifyAll(fs);
|
||||
const CMD = class StageRegion extends ProjectCmd {
|
||||
constructor(JAWS, type, stage, region, noCf) {
|
||||
super(JAWS);
|
||||
this._type = type;
|
||||
this._stage = stage;
|
||||
this._region = region;
|
||||
this._noCf = noCf;
|
||||
this._type = type;
|
||||
this._stage = stage;
|
||||
this._region = region;
|
||||
this._noCf = noCf;
|
||||
this._spinner = null;
|
||||
this._prompts = {
|
||||
properties: {},
|
||||
@ -41,53 +41,55 @@ const CMD = class StageRegion extends ProjectCmd {
|
||||
let _this = this;
|
||||
|
||||
return _this._JAWS.validateProject()
|
||||
.bind(_this)
|
||||
.then(function() {
|
||||
// Report Status
|
||||
if (_this._type === 'stage') JawsCLI.log('Creating new stage...');
|
||||
if (_this._type === 'region') JawsCLI.log('Creating new region...');
|
||||
})
|
||||
.then(_this._promptStage)
|
||||
.then(_this._promptRegion)
|
||||
.then(_this._validate)
|
||||
.then(function() {
|
||||
return utils.generateResourcesCf(
|
||||
_this._JAWS._meta.projectRootPath,
|
||||
_this._JAWS._meta.projectJson.name,
|
||||
_this._JAWS._meta.projectJson.domain,
|
||||
_this._stage,
|
||||
_this._region,
|
||||
'',
|
||||
_this._jawsBucket
|
||||
.bind(_this)
|
||||
.then(function() {
|
||||
// Report Status
|
||||
if (_this._type === 'stage') JawsCLI.log('Creating new stage...');
|
||||
if (_this._type === 'region') JawsCLI.log('Creating new region...');
|
||||
})
|
||||
.then(_this._promptStage)
|
||||
.then(_this._promptRegion)
|
||||
.then(_this._validate)
|
||||
.then(function() {
|
||||
return utils.generateResourcesCf(
|
||||
_this._JAWS._projectRootPath,
|
||||
_this._JAWS._meta.projectJson.name,
|
||||
_this._JAWS._meta.projectJson.domain,
|
||||
_this._stage,
|
||||
_this._region,
|
||||
''
|
||||
);
|
||||
})
|
||||
.then(() => {
|
||||
return AWSUtils.createBucket(_this.Jaws._awsProfile, _this._region, _this.Jaws.getJawsBucket(_this._region, _this._stage));
|
||||
})
|
||||
.then(function() {
|
||||
|
||||
if (_this._noCf) {
|
||||
let stackName = AWSUtils.cfGetResourcesStackName(
|
||||
_this._stage,
|
||||
_this._JAWS._meta.projectJson.name
|
||||
);
|
||||
})
|
||||
.then(function() {
|
||||
|
||||
if (_this._noCf) {
|
||||
let stackName = AWSUtils.cfGetResourcesStackName(
|
||||
_this._stage,
|
||||
_this._JAWS._meta.projectJson.name
|
||||
);
|
||||
|
||||
JawsCLI.log('Remember to run CloudFormation manually');
|
||||
JawsCLI.log(`!!MAKE SURE!! to create stack with name: ${stackName}`);
|
||||
JawsCLI.log('After creating CF stack, remember to put the IAM role outputs and jawsBucket in your '
|
||||
+ 'project jaws.json in the right stage/region.');
|
||||
return false;
|
||||
} else {
|
||||
return _this._createCfStack()
|
||||
.bind(_this)
|
||||
.then(function(cfData) {
|
||||
if (_this._spinner) {
|
||||
_this._spinner.stop(true);
|
||||
}
|
||||
_this._cfData = cfData;
|
||||
})
|
||||
.then(_this._putEnvFile)
|
||||
.then(_this._putCfFile);
|
||||
}
|
||||
})
|
||||
.then(_this._updateProjectJson);
|
||||
JawsCLI.log('Remember to run CloudFormation manually');
|
||||
JawsCLI.log(`!!MAKE SURE!! to create stack with name: ${stackName}`);
|
||||
JawsCLI.log('After creating CF stack, remember to put the IAM role outputs and jawsBucket in your '
|
||||
+ 'project jaws.json in the right stage/region.');
|
||||
return false;
|
||||
} else {
|
||||
return _this._createCfStack()
|
||||
.bind(_this)
|
||||
.then(function(cfData) {
|
||||
if (_this._spinner) {
|
||||
_this._spinner.stop(true);
|
||||
}
|
||||
_this._cfData = cfData;
|
||||
})
|
||||
.then(_this._putEnvFile)
|
||||
.then(_this._putCfFile);
|
||||
}
|
||||
})
|
||||
.then(_this._updateProjectJson);
|
||||
}
|
||||
|
||||
_promptStage() {
|
||||
@ -99,14 +101,14 @@ const CMD = class StageRegion extends ProjectCmd {
|
||||
if (_this._type === 'stage') {
|
||||
|
||||
// User is creating a stage
|
||||
_this.Prompter = JawsCLI.prompt();
|
||||
_this.Prompter = JawsCLI.prompt();
|
||||
let stageDescription = `Enter the name of the stage to be created: \n`;
|
||||
|
||||
_this._prompts.properties.stage = {
|
||||
description: stageDescription.yellow,
|
||||
default: 'dev',
|
||||
message: 'Stage must be letters only',
|
||||
conform: function(stage) {
|
||||
default: 'dev',
|
||||
message: 'Stage must be letters only',
|
||||
conform: function(stage) {
|
||||
let re = /^[a-zA-Z]+$/;
|
||||
return re.test(stage);
|
||||
},
|
||||
@ -114,9 +116,9 @@ const CMD = class StageRegion extends ProjectCmd {
|
||||
|
||||
// Show Prompt
|
||||
return _this.Prompter.getAsync(_this._prompts)
|
||||
.then(function(answers) {
|
||||
_this._stage = answers.stage;
|
||||
});
|
||||
.then(function(answers) {
|
||||
_this._stage = answers.stage;
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
@ -138,22 +140,22 @@ const CMD = class StageRegion extends ProjectCmd {
|
||||
let choices = [];
|
||||
for (let i = 0; i < stages.length; i++) {
|
||||
choices.push({
|
||||
key: (i + 1) + ') ',
|
||||
key: (i + 1) + ') ',
|
||||
value: stages[i],
|
||||
label: stages[i],
|
||||
});
|
||||
}
|
||||
|
||||
return JawsCLI.select('Which stage are you creating a region for: ', choices, false)
|
||||
.then(function(results) {
|
||||
_this._stage = results[0].value;
|
||||
});
|
||||
.then(function(results) {
|
||||
_this._stage = results[0].value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_promptRegion() {
|
||||
|
||||
let _this = this,
|
||||
let _this = this,
|
||||
validRegions = AWSUtils.validLambdaRegions;
|
||||
|
||||
if (validRegions.indexOf(_this._region) != -1) { //they specified region and its valid
|
||||
@ -164,7 +166,7 @@ const CMD = class StageRegion extends ProjectCmd {
|
||||
msg;
|
||||
validRegions.forEach(function(r) {
|
||||
choices.push({
|
||||
key: '',
|
||||
key: '',
|
||||
value: r,
|
||||
label: r,
|
||||
});
|
||||
@ -178,9 +180,9 @@ const CMD = class StageRegion extends ProjectCmd {
|
||||
}
|
||||
|
||||
return JawsCLI.select(msg, choices, false)
|
||||
.then(function(results) {
|
||||
_this._region = results[0].value;
|
||||
});
|
||||
.then(function(results) {
|
||||
_this._region = results[0].value;
|
||||
});
|
||||
}
|
||||
|
||||
_validate() {
|
||||
@ -227,8 +229,8 @@ const CMD = class StageRegion extends ProjectCmd {
|
||||
|
||||
// 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;
|
||||
})) {
|
||||
return Promise.reject(new JawsError('Region "' + _this._region + '" is already defined in the stage "' + _this._stage + '"'));
|
||||
}
|
||||
}
|
||||
@ -241,27 +243,27 @@ const CMD = class StageRegion extends ProjectCmd {
|
||||
let _this = this;
|
||||
|
||||
JawsCLI.log('Creating CloudFormation stack for stage: "'
|
||||
+ _this._stage
|
||||
+ '" and region: "'
|
||||
+ _this._region
|
||||
+ '" (~5 mins)');
|
||||
+ _this._stage
|
||||
+ '" and region: "'
|
||||
+ _this._region
|
||||
+ '" (~5 mins)');
|
||||
_this._spinner = JawsCLI.spinner();
|
||||
_this._spinner.start();
|
||||
|
||||
// Create CF stack
|
||||
return AWSUtils.cfCreateResourcesStack(
|
||||
_this._JAWS._meta.profile,
|
||||
_this._region,
|
||||
_this._JAWS._meta.projectRootPath,
|
||||
_this._JAWS._meta.projectJson.name,
|
||||
_this._stage,
|
||||
_this._domain,
|
||||
'', // TODO: read email out of existing jaws-cf.json?
|
||||
_this._jawsBucket
|
||||
)
|
||||
.then(function(cfData) {
|
||||
return AWSUtils.monitorCf(cfData, _this._JAWS._meta.profile, _this._region, 'create');
|
||||
});
|
||||
_this._JAWS._awsProfile,
|
||||
_this._region,
|
||||
_this._JAWS._projectRootPath,
|
||||
_this._JAWS._meta.projectJson.name,
|
||||
_this._stage,
|
||||
_this._domain,
|
||||
'', // TODO: read email out of existing jaws-cf.json?
|
||||
_this._jawsBucket
|
||||
)
|
||||
.then(function(cfData) {
|
||||
return AWSUtils.monitorCf(cfData, _this._JAWS._awsProfile, _this._region, 'create');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -279,12 +281,12 @@ const CMD = class StageRegion extends ProjectCmd {
|
||||
JAWS_DATA_MODEL_STAGE=${stage}`;
|
||||
|
||||
return AWSUtils.putEnvFile(
|
||||
_this._JAWS._meta.profile,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._JAWS._meta.projectJson.name,
|
||||
_this._stage,
|
||||
envFileContents);
|
||||
_this._JAWS._awsProfile,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._JAWS._meta.projectJson.name,
|
||||
_this._stage,
|
||||
envFileContents);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -297,13 +299,13 @@ JAWS_DATA_MODEL_STAGE=${stage}`;
|
||||
let _this = this;
|
||||
|
||||
return AWSUtils.putCfFile(
|
||||
_this._JAWS._meta.profile,
|
||||
_this._JAWS._meta.projectRootPath,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._JAWS._meta.projectJson.name,
|
||||
_this._stage,
|
||||
'resources');
|
||||
_this._JAWS._awsProfile,
|
||||
_this._JAWS._projectRootPath,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._JAWS._meta.projectJson.name,
|
||||
_this._stage,
|
||||
'resources');
|
||||
|
||||
}
|
||||
|
||||
@ -316,10 +318,10 @@ JAWS_DATA_MODEL_STAGE=${stage}`;
|
||||
let _this = this;
|
||||
|
||||
let regionObj = {
|
||||
region: _this._region,
|
||||
iamRoleArnLambda: '',
|
||||
region: _this._region,
|
||||
iamRoleArnLambda: '',
|
||||
iamRoleArnApiGateway: '',
|
||||
jawsBucket: _this._jawsBucket,
|
||||
jawsBucket: _this._jawsBucket,
|
||||
};
|
||||
|
||||
if (_this._cfData) {
|
||||
@ -341,8 +343,8 @@ JAWS_DATA_MODEL_STAGE=${stage}`;
|
||||
}
|
||||
|
||||
return utils.writeFile(
|
||||
path.join(_this._JAWS._meta.projectRootPath, 'jaws.json'),
|
||||
JSON.stringify(_this._JAWS._meta.projectJson, null, 2));
|
||||
path.join(_this._JAWS._projectRootPath, 'jaws.json'),
|
||||
JSON.stringify(_this._JAWS._meta.projectJson, null, 2));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -144,7 +144,7 @@ CMD.prototype.run = Promise.method(function() {
|
||||
CMD.prototype._prepareResources = Promise.method(function() {
|
||||
let _this = this;
|
||||
|
||||
return JawsUtils.findAllAwsmJsons(path.join(_this._JAWS._meta.projectRootPath, 'aws_modules'))
|
||||
return JawsUtils.findAllAwsmJsons(path.join(_this._JAWS._projectRootPath, 'aws_modules'))
|
||||
.then(function(jsonPaths) {
|
||||
|
||||
let hybrids = [];
|
||||
|
||||
@ -76,7 +76,7 @@ const CMD = class Postinstall extends ProjectCmd {
|
||||
return Promise.all(deferredDepInstalls);
|
||||
})
|
||||
.then(function() {
|
||||
return utils.findAllEnvletsForAwsm(_this._JAWS._meta.projectRootPath, _this._moduleName);
|
||||
return utils.findAllEnvletsForAwsm(_this._JAWS._projectRootPath, _this._moduleName);
|
||||
})
|
||||
.then(function(envlets) {
|
||||
JawsCLI.log('Successfully installed ' + _this._moduleName);
|
||||
@ -104,9 +104,9 @@ const CMD = class Postinstall extends ProjectCmd {
|
||||
pkgMgrDir = 'node_modules';
|
||||
}
|
||||
|
||||
let srcAwsmPath = path.join(_this._JAWS._meta.projectRootPath, pkgMgrDir, _this._moduleName, 'awsm'),
|
||||
srcAwsmJsonPath = path.join(_this._JAWS._meta.projectRootPath, pkgMgrDir, _this._moduleName, 'awsm.json'),
|
||||
awsModsPath = path.join(_this._JAWS._meta.projectRootPath, 'aws_modules');
|
||||
let srcAwsmPath = path.join(_this._JAWS._projectRootPath, pkgMgrDir, _this._moduleName, 'awsm'),
|
||||
srcAwsmJsonPath = path.join(_this._JAWS._projectRootPath, pkgMgrDir, _this._moduleName, 'awsm.json'),
|
||||
awsModsPath = path.join(_this._JAWS._projectRootPath, 'aws_modules');
|
||||
|
||||
if (!utils.fileExistsSync(srcAwsmJsonPath)) {
|
||||
return Promise.reject(new JawsError('Module missing awsm.json file in root of project', JawsError.errorCodes.UNKNOWN));
|
||||
|
||||
@ -66,7 +66,7 @@ const CMD = class Tag extends ProjectCmd {
|
||||
|
||||
return this._JAWS.validateProject()
|
||||
.then(function() {
|
||||
return utils[findAllFunc](path.join(_this._JAWS._meta.projectRootPath, 'aws_modules'));
|
||||
return utils[findAllFunc](path.join(_this._JAWS._projectRootPath, 'aws_modules'));
|
||||
})
|
||||
.then(function(awsmJsonPaths) {
|
||||
let tagQueue = [];
|
||||
@ -95,7 +95,7 @@ const CMD = class Tag extends ProjectCmd {
|
||||
|
||||
return this._JAWS.validateProject()
|
||||
.then(() => {
|
||||
return utils[findAllFunc](path.join(_this._JAWS._meta.projectRootPath, 'aws_modules'));
|
||||
return utils[findAllFunc](path.join(_this._JAWS._projectRootPath, 'aws_modules'));
|
||||
})
|
||||
.then(function(lAwsmJsonPaths) {
|
||||
|
||||
|
||||
@ -89,28 +89,28 @@ usage: jaws lambda alias <version> <aliasName>`,
|
||||
JawsUtils.jawsDebug(`Preparing to version ${version} to alias ${aliasName} for stage:`, _this._stage);
|
||||
|
||||
return this._JAWS.validateProject()
|
||||
.bind(_this)
|
||||
.then(_this._promptStage)
|
||||
.then(_this._setLambdaLogicalIds)
|
||||
.then(_this._getRegions)
|
||||
.each(region => {
|
||||
//1) For each region, get all the lambdas for stack
|
||||
let lStackName = AWSUtils.cfGetLambdasStackName(_this._stage, _this._JAWS._projectJson.name);
|
||||
return AWSUtils.cfGetLambdaResourceSummaries(_this.Jaws._profile, region, lStackName)
|
||||
.then(lambdaSummaries => {
|
||||
//2) identify physical function names from logical
|
||||
return AWSUtils.cfGetLambdaPhysicalsFromLogicals(_this._lambdaLogicalIdsToAlias, lambdaSummaries);
|
||||
})
|
||||
.then(lambdaNamesToAlias => {
|
||||
//3) create alias (should only be one lambda name, as we only support aliasing one lambda at a time
|
||||
return AWSUtils.lambdaCreateAlias(_this.Jaws._profile, region, lambdaNamesToAlias[0], version, aliasName);
|
||||
});
|
||||
})
|
||||
.then(aliasedLambda => {
|
||||
JawsCLI.log('Lambda Alias: Successfully aliased lambda in requested regions:');
|
||||
JawsCLI.log(aliasedLambda);
|
||||
return aliasedLambda;
|
||||
});
|
||||
.bind(_this)
|
||||
.then(_this._promptStage)
|
||||
.then(_this._setLambdaLogicalIds)
|
||||
.then(_this._getRegions)
|
||||
.each(region => {
|
||||
//1) For each region, get all the lambdas for stack
|
||||
let lStackName = AWSUtils.cfGetLambdasStackName(_this._stage, _this.Jaws._projectJson.name);
|
||||
return AWSUtils.cfGetLambdaResourceSummaries(_this.Jaws._awsProfile, region, lStackName)
|
||||
.then(lambdaSummaries => {
|
||||
//2) identify physical function names from logical
|
||||
return AWSUtils.cfGetLambdaPhysicalsFromLogicals(_this._lambdaLogicalIdsToAlias, lambdaSummaries);
|
||||
})
|
||||
.then(lambdaNamesToAlias => {
|
||||
//3) create alias (should only be one lambda name, as we only support aliasing one lambda at a time
|
||||
return AWSUtils.lambdaCreateAlias(_this.Jaws._awsProfile, region, lambdaNamesToAlias[0], version, aliasName);
|
||||
});
|
||||
})
|
||||
.then(aliasedLambda => {
|
||||
JawsCLI.log('Lambda Alias: Successfully aliased lambda in requested regions:');
|
||||
JawsCLI.log(aliasedLambda);
|
||||
return aliasedLambda;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,7 +124,7 @@ usage: jaws lambda alias <version> <aliasName>`,
|
||||
|
||||
// If stage exists, skip
|
||||
if (!this._stage) {
|
||||
stages = Object.keys(_this.JAWS._projectJson.stages);
|
||||
stages = Object.keys(_this.Jaws._projectJson.stages);
|
||||
|
||||
// If project only has 1 stage, skip prompt
|
||||
if (stages.length === 1) {
|
||||
@ -147,9 +147,9 @@ usage: jaws lambda alias <version> <aliasName>`,
|
||||
}
|
||||
|
||||
return this.selectInput('AliasLambda: Choose a stage: ', choices, false)
|
||||
.then(results => {
|
||||
_this._stage = results[0].value;
|
||||
});
|
||||
.then(results => {
|
||||
_this._stage = results[0].value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,7 +166,7 @@ usage: jaws lambda alias <version> <aliasName>`,
|
||||
//Deploy to all regions in stage
|
||||
|
||||
let stage = this._stage,
|
||||
projJson = this.JAWS._projectJson;
|
||||
projJson = this.Jaws._projectJson;
|
||||
|
||||
let regionConfigs = projJson.stages[stage],
|
||||
regions = regionConfigs.map(rCfg => {
|
||||
@ -185,12 +185,12 @@ usage: jaws lambda alias <version> <aliasName>`,
|
||||
_setLambdaLogicalIds() {
|
||||
let _this = this;
|
||||
return JawsUtils.getFullLambdaPaths(process.cwd(), [])
|
||||
.then(fullAwsmJsonPaths => {
|
||||
_this._lambdaLogicalIdsToAlias = fullAwsmJsonPaths.map(alp => {
|
||||
let awsmJson = JawsUtils.readAndParseJsonSync(alp);
|
||||
return JawsUtils.getLambdaName(awsmJson);
|
||||
});
|
||||
.then(fullAwsmJsonPaths => {
|
||||
_this._lambdaLogicalIdsToAlias = fullAwsmJsonPaths.map(alp => {
|
||||
let awsmJson = JawsUtils.readAndParseJsonSync(alp);
|
||||
return JawsUtils.getLambdaName(awsmJson);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -41,91 +41,91 @@ class Deployer {
|
||||
awsmLambdas = [];
|
||||
|
||||
return BbPromise.try(function() {
|
||||
})
|
||||
.bind(_this)
|
||||
.then(function() {
|
||||
return _this._lambdaAwsmPaths;
|
||||
})
|
||||
.each(function(lambdaAwsmPath) {
|
||||
let packager = new Packager(
|
||||
_this._JAWS,
|
||||
_this._stage,
|
||||
_this._region,
|
||||
lambdaAwsmPath
|
||||
);
|
||||
|
||||
return BbPromise.try(function() {
|
||||
})
|
||||
.bind(_this)
|
||||
.then(function() {
|
||||
return packager.run();
|
||||
})
|
||||
.then(function(packagedLambda) {
|
||||
let jawsBucket = _this._JAWS.getJawsBucket(_this._region, _this._stage);
|
||||
JawsCLI.log('Lambda Deployer: Uploading ' + packagedLambda.lambdaName + ` to ${jawsBucket}`);
|
||||
|
||||
return AWSUtils.putLambdaZip(
|
||||
_this._JAWS._profile,
|
||||
_this._region,
|
||||
jawsBucket,
|
||||
projName,
|
||||
_this._stage,
|
||||
packagedLambda.lambdaName,
|
||||
packagedLambda.zipBuffer
|
||||
)
|
||||
.then(function(s3Key) {
|
||||
awsmLambdas.push({
|
||||
awsmPath: lambdaAwsmPath,
|
||||
Code: {
|
||||
S3Bucket: jawsBucket,
|
||||
S3Key: s3Key,
|
||||
},
|
||||
lambdaName: packagedLambda.lambdaName,
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
//At this point all packages have been created and uploaded to s3
|
||||
let lambdaRoleArn = JawsUtils
|
||||
.getProjRegionConfigForStage(_this._JAWS._projectJson, _this._stage, _this._region).iamRoleArnLambda;
|
||||
return [lambdaRoleArn, _this._generateLambdaCf(awsmLambdas, lambdaRoleArn)];
|
||||
})
|
||||
.spread(function(lambdaRoleArn, existingStack) {
|
||||
if (_this._noExeCf) {
|
||||
JawsCLI.log(`Lambda Deployer: not executing CloudFormation. Remember to set aaLambdaRoleArn parameter to ${lambdaRoleArn}`);
|
||||
return false;
|
||||
} else {
|
||||
let createOrUpdate,
|
||||
cfDeferred;
|
||||
|
||||
JawsUtils.jawsDebug(`Deploying with lambda role arn ${lambdaRoleArn}`);
|
||||
|
||||
if (existingStack) {
|
||||
cfDeferred = AWSUtils.cfUpdateLambdasStack(_this._JAWS, _this._stage, _this._region, lambdaRoleArn);
|
||||
createOrUpdate = 'update';
|
||||
} else {
|
||||
cfDeferred = AWSUtils.cfCreateLambdasStack(_this._JAWS, _this._stage, _this._region, lambdaRoleArn);
|
||||
createOrUpdate = 'create';
|
||||
}
|
||||
|
||||
JawsCLI.log('Running CloudFormation lambda deploy...');
|
||||
let spinner = JawsCLI.spinner();
|
||||
spinner.start();
|
||||
|
||||
return cfDeferred
|
||||
.then(function(cfData) {
|
||||
return AWSUtils.monitorCf(cfData, _this._JAWS._profile, _this._region, createOrUpdate);
|
||||
})
|
||||
.then(function() {
|
||||
spinner.stop(true);
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(function() {
|
||||
JawsCLI.log('Lambda Deployer: Done deploying lambdas in ' + _this._region);
|
||||
}
|
||||
})
|
||||
.bind(_this)
|
||||
.then(function() {
|
||||
return _this._lambdaAwsmPaths;
|
||||
})
|
||||
.each(function(lambdaAwsmPath) {
|
||||
let packager = new Packager(
|
||||
_this._JAWS,
|
||||
_this._stage,
|
||||
_this._region,
|
||||
lambdaAwsmPath
|
||||
);
|
||||
|
||||
return BbPromise.try(function() {
|
||||
})
|
||||
.bind(_this)
|
||||
.then(function() {
|
||||
return packager.run();
|
||||
})
|
||||
.then(function(packagedLambda) {
|
||||
let jawsBucket = _this._JAWS.getJawsBucket(_this._region, _this._stage);
|
||||
JawsCLI.log('Lambda Deployer: Uploading ' + packagedLambda.lambdaName + ` to ${jawsBucket}`);
|
||||
|
||||
return AWSUtils.putLambdaZip(
|
||||
_this._JAWS._awsProfile,
|
||||
_this._region,
|
||||
jawsBucket,
|
||||
projName,
|
||||
_this._stage,
|
||||
packagedLambda.lambdaName,
|
||||
packagedLambda.zipBuffer
|
||||
)
|
||||
.then(function(s3Key) {
|
||||
awsmLambdas.push({
|
||||
awsmPath: lambdaAwsmPath,
|
||||
Code: {
|
||||
S3Bucket: jawsBucket,
|
||||
S3Key: s3Key,
|
||||
},
|
||||
lambdaName: packagedLambda.lambdaName,
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
//At this point all packages have been created and uploaded to s3
|
||||
let lambdaRoleArn = JawsUtils
|
||||
.getProjRegionConfigForStage(_this._JAWS._projectJson, _this._stage, _this._region).iamRoleArnLambda;
|
||||
return [lambdaRoleArn, _this._generateLambdaCf(awsmLambdas, lambdaRoleArn)];
|
||||
})
|
||||
.spread(function(lambdaRoleArn, existingStack) {
|
||||
if (_this._noExeCf) {
|
||||
JawsCLI.log(`Lambda Deployer: not executing CloudFormation. Remember to set aaLambdaRoleArn parameter to ${lambdaRoleArn}`);
|
||||
return false;
|
||||
} else {
|
||||
let createOrUpdate,
|
||||
cfDeferred;
|
||||
|
||||
JawsUtils.jawsDebug(`Deploying with lambda role arn ${lambdaRoleArn}`);
|
||||
|
||||
if (existingStack) {
|
||||
cfDeferred = AWSUtils.cfUpdateLambdasStack(_this._JAWS, _this._stage, _this._region, lambdaRoleArn);
|
||||
createOrUpdate = 'update';
|
||||
} else {
|
||||
cfDeferred = AWSUtils.cfCreateLambdasStack(_this._JAWS, _this._stage, _this._region, lambdaRoleArn);
|
||||
createOrUpdate = 'create';
|
||||
}
|
||||
|
||||
JawsCLI.log('Running CloudFormation lambda deploy...');
|
||||
let spinner = JawsCLI.spinner();
|
||||
spinner.start();
|
||||
|
||||
return cfDeferred
|
||||
.then(function(cfData) {
|
||||
return AWSUtils.monitorCf(cfData, _this._JAWS._awsProfile, _this._region, createOrUpdate);
|
||||
})
|
||||
.then(function() {
|
||||
spinner.stop(true);
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(function() {
|
||||
JawsCLI.log('Lambda Deployer: Done deploying lambdas in ' + _this._region);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,84 +150,84 @@ class Deployer {
|
||||
existingStack = true,
|
||||
projName = this._JAWS._projectJson.name;
|
||||
|
||||
return AWSUtils.cfGetLambdasStackTemplate(_this._JAWS._profile, _this._region, _this._stage, projName)
|
||||
.error(e => {
|
||||
if (e && ['ValidationError', 'ResourceNotFoundException'].indexOf(e.code) == -1) { //ValidationError if DNE
|
||||
console.error(
|
||||
'Error trying to fetch existing lambda cf stack for region', _this._region, 'stage', _this._stage, e
|
||||
);
|
||||
throw new JawsError(e.message, JawsError.errorCodes.UNKNOWN);
|
||||
}
|
||||
|
||||
JawsUtils.jawsDebug('no exsting lambda stack');
|
||||
existingStack = false;
|
||||
return false;
|
||||
})
|
||||
.then(cfTemplateBody => {
|
||||
let templatesPath = path.join(__dirname, '..', 'templates'),
|
||||
lambdaCf = JawsUtils.readAndParseJsonSync(path.join(templatesPath, 'lambdas-cf.json'));
|
||||
|
||||
delete lambdaCf.Resources.lTemplate;
|
||||
lambdaCf.Description = projName + " lambdas";
|
||||
lambdaCf.Parameters.aaLambdaRoleArn.Default = lambdaRoleArn;
|
||||
|
||||
//Always add lambdas tagged for deployment
|
||||
taggedLambdaPkgs.forEach(function(pkg) {
|
||||
let lResource = {
|
||||
Type: "AWS::Lambda::Function",
|
||||
Properties: {}
|
||||
},
|
||||
awsm = JawsUtils.readAndParseJsonSync(pkg.awsmPath);
|
||||
|
||||
lResource.Properties = awsm.lambda.cloudFormation;
|
||||
lResource.Properties.Code = pkg.Code;
|
||||
lResource.Properties.Role = {
|
||||
Ref: "aaLambdaRoleArn"
|
||||
};
|
||||
|
||||
JawsUtils.jawsDebug('adding Resource ' + pkg.lambdaName + ': ');
|
||||
JawsUtils.jawsDebug(lResource);
|
||||
|
||||
lambdaCf.Resources[pkg.lambdaName] = lResource;
|
||||
});
|
||||
|
||||
// If existing lambdas CF template
|
||||
if (cfTemplateBody) {
|
||||
JawsUtils.jawsDebug('existing stack detected');
|
||||
|
||||
// Find all lambdas in project, and copy ones that are in existing lambda-cf
|
||||
let existingTemplate = JSON.parse(cfTemplateBody);
|
||||
|
||||
return JawsUtils.getAllLambdaNames(_this._JAWS._projectRootPath)
|
||||
.then(allLambdaNames => {
|
||||
Object.keys(existingTemplate.Resources).forEach(resource => {
|
||||
|
||||
if (!lambdaCf.Resources[resource] && allLambdaNames.indexOf(resource) != -1) {
|
||||
JawsUtils.jawsDebug(`Adding exsiting lambda ${resource}`);
|
||||
lambdaCf.Resources[resource] = existingTemplate.Resources[resource];
|
||||
}
|
||||
});
|
||||
|
||||
return lambdaCf;
|
||||
});
|
||||
} else {
|
||||
return lambdaCf;
|
||||
}
|
||||
})
|
||||
.then(lambdaCfTemplate => {
|
||||
let lambdasCfPath = path.join(
|
||||
_this._JAWS._projectRootPath,
|
||||
'cloudformation',
|
||||
_this._stage,
|
||||
_this._region,
|
||||
'lambdas-cf.json'
|
||||
return AWSUtils.cfGetLambdasStackTemplate(_this._JAWS._awsProfile, _this._region, _this._stage, projName)
|
||||
.error(e => {
|
||||
if (e && ['ValidationError', 'ResourceNotFoundException'].indexOf(e.code) == -1) { //ValidationError if DNE
|
||||
console.error(
|
||||
'Error trying to fetch existing lambda cf stack for region', _this._region, 'stage', _this._stage, e
|
||||
);
|
||||
throw new JawsError(e.message, JawsError.errorCodes.UNKNOWN);
|
||||
}
|
||||
|
||||
JawsUtils.jawsDebug(`Wrting to ${lambdasCfPath}`);
|
||||
JawsUtils.jawsDebug('no exsting lambda stack');
|
||||
existingStack = false;
|
||||
return false;
|
||||
})
|
||||
.then(cfTemplateBody => {
|
||||
let templatesPath = path.join(__dirname, '..', 'templates'),
|
||||
lambdaCf = JawsUtils.readAndParseJsonSync(path.join(templatesPath, 'lambdas-cf.json'));
|
||||
|
||||
return JawsUtils.writeFile(lambdasCfPath, JSON.stringify(lambdaCfTemplate, null, 2))
|
||||
.then(() => existingStack);
|
||||
delete lambdaCf.Resources.lTemplate;
|
||||
lambdaCf.Description = projName + " lambdas";
|
||||
lambdaCf.Parameters.aaLambdaRoleArn.Default = lambdaRoleArn;
|
||||
|
||||
//Always add lambdas tagged for deployment
|
||||
taggedLambdaPkgs.forEach(function(pkg) {
|
||||
let lResource = {
|
||||
Type: "AWS::Lambda::Function",
|
||||
Properties: {}
|
||||
},
|
||||
awsm = JawsUtils.readAndParseJsonSync(pkg.awsmPath);
|
||||
|
||||
lResource.Properties = awsm.lambda.cloudFormation;
|
||||
lResource.Properties.Code = pkg.Code;
|
||||
lResource.Properties.Role = {
|
||||
Ref: "aaLambdaRoleArn"
|
||||
};
|
||||
|
||||
JawsUtils.jawsDebug('adding Resource ' + pkg.lambdaName + ': ');
|
||||
JawsUtils.jawsDebug(lResource);
|
||||
|
||||
lambdaCf.Resources[pkg.lambdaName] = lResource;
|
||||
});
|
||||
|
||||
// If existing lambdas CF template
|
||||
if (cfTemplateBody) {
|
||||
JawsUtils.jawsDebug('existing stack detected');
|
||||
|
||||
// Find all lambdas in project, and copy ones that are in existing lambda-cf
|
||||
let existingTemplate = JSON.parse(cfTemplateBody);
|
||||
|
||||
return JawsUtils.getAllLambdaNames(_this._JAWS._projectRootPath)
|
||||
.then(allLambdaNames => {
|
||||
Object.keys(existingTemplate.Resources).forEach(resource => {
|
||||
|
||||
if (!lambdaCf.Resources[resource] && allLambdaNames.indexOf(resource) != -1) {
|
||||
JawsUtils.jawsDebug(`Adding exsiting lambda ${resource}`);
|
||||
lambdaCf.Resources[resource] = existingTemplate.Resources[resource];
|
||||
}
|
||||
});
|
||||
|
||||
return lambdaCf;
|
||||
});
|
||||
} else {
|
||||
return lambdaCf;
|
||||
}
|
||||
})
|
||||
.then(lambdaCfTemplate => {
|
||||
let lambdasCfPath = path.join(
|
||||
_this._JAWS._projectRootPath,
|
||||
'cloudformation',
|
||||
_this._stage,
|
||||
_this._region,
|
||||
'lambdas-cf.json'
|
||||
);
|
||||
|
||||
JawsUtils.jawsDebug(`Wrting to ${lambdasCfPath}`);
|
||||
|
||||
return JawsUtils.writeFile(lambdasCfPath, JSON.stringify(lambdaCfTemplate, null, 2))
|
||||
.then(() => existingStack);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,22 +251,22 @@ class Packager {
|
||||
this._lambdaName = this.createLambdaName();
|
||||
|
||||
return this._createDistFolder()
|
||||
.then(function() {
|
||||
.then(function() {
|
||||
|
||||
// Package by runtime
|
||||
switch (_this._awsmJson.lambda.cloudFormation.Runtime) {
|
||||
case 'nodejs':
|
||||
return _this._packageNodeJs()
|
||||
.then(function(packageData) {
|
||||
packageData.lambdaName = _this._lambdaName;
|
||||
return packageData;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return Promise.reject(new JawsError('Unsupported lambda runtime ' + _this._awsmJson.lambda.cloudFormation.Runtime));
|
||||
break;
|
||||
}
|
||||
});
|
||||
// Package by runtime
|
||||
switch (_this._awsmJson.cloudFormation.Lambda.Runtime) {
|
||||
case 'nodejs':
|
||||
return _this._packageNodeJs()
|
||||
.then(function(packageData) {
|
||||
packageData.lambdaName = _this._lambdaName;
|
||||
return packageData;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return Promise.reject(new JawsError('Unsupported lambda runtime ' + _this._awsmJson.cloudFormation.Lambda.Runtime));
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -304,44 +304,44 @@ class Packager {
|
||||
JawsUtils.jawsDebug('copying', _this._JAWS._projectRootPath, 'to', _this._distDir);
|
||||
|
||||
// Copy entire test project to temp folder
|
||||
_this._excludePatterns = _this._awsmJson.lambda.package.excludePatterns || [];
|
||||
_this._excludePatterns = _this._awsmJson.package.excludePatterns || [];
|
||||
wrench.copyDirSyncRecursive(
|
||||
_this._JAWS._projectRootPath,
|
||||
_this._distDir,
|
||||
{
|
||||
exclude: function(name, prefix) {
|
||||
if (!_this._excludePatterns.length) {
|
||||
return false;
|
||||
_this._JAWS._projectRootPath,
|
||||
_this._distDir,
|
||||
{
|
||||
exclude: function(name, prefix) {
|
||||
if (!_this._excludePatterns.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let relPath = path.join(
|
||||
prefix.replace(_this._distDir, ''), name);
|
||||
|
||||
return _this._excludePatterns.some(sRegex => {
|
||||
relPath = (relPath.charAt(0) == path.sep) ? relPath.substr(1) : relPath;
|
||||
|
||||
let re = new RegExp(sRegex),
|
||||
matches = re.exec(relPath);
|
||||
|
||||
let willExclude = (matches && matches.length > 0);
|
||||
|
||||
if (willExclude) {
|
||||
JawsCLI.log(`Lambda Deployer: Excluding ${relPath}`);
|
||||
}
|
||||
|
||||
let relPath = path.join(
|
||||
prefix.replace(_this._distDir, ''), name);
|
||||
|
||||
return _this._excludePatterns.some(sRegex => {
|
||||
relPath = (relPath.charAt(0) == path.sep) ? relPath.substr(1) : relPath;
|
||||
|
||||
let re = new RegExp(sRegex),
|
||||
matches = re.exec(relPath);
|
||||
|
||||
let willExclude = (matches && matches.length > 0);
|
||||
|
||||
if (willExclude) {
|
||||
JawsCLI.log(`Lambda Deployer: Excluding ${relPath}`);
|
||||
}
|
||||
|
||||
return willExclude;
|
||||
});
|
||||
},
|
||||
}
|
||||
return willExclude;
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
JawsUtils.jawsDebug('Packaging stage & region:', _this._stage, _this._region);
|
||||
|
||||
// Get ENV file from S3
|
||||
return _this._JAWS.getEnvFile(_this._region, _this._stage)
|
||||
.then(function(s3ObjData) {
|
||||
fs.writeFileSync(path.join(_this._distDir, '.env'), s3ObjData.Body);
|
||||
});
|
||||
.then(function(s3ObjData) {
|
||||
fs.writeFileSync(path.join(_this._distDir, '.env'), s3ObjData.Body);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -354,47 +354,47 @@ class Packager {
|
||||
let _this = this,
|
||||
deferred = null;
|
||||
|
||||
if (_this._awsmJson.lambda.package
|
||||
&& _this._awsmJson.lambda.package.optimize
|
||||
&& _this._awsmJson.lambda.package.optimize.builder) {
|
||||
if (_this._awsmJson.package
|
||||
&& _this._awsmJson.package.optimize
|
||||
&& _this._awsmJson.package.optimize.builder) {
|
||||
|
||||
deferred = _this._optimizeNodeJs()
|
||||
.then(optimizedCodeBuffer => {
|
||||
.then(optimizedCodeBuffer => {
|
||||
|
||||
// Lambda freaks out if code doesnt end in newline
|
||||
let ocbWithNewline = optimizedCodeBuffer.concat(new Buffer('\n'));
|
||||
let envData = fs.readFileSync(path.join(_this._distDir, '.env'));
|
||||
// Lambda freaks out if code doesnt end in newline
|
||||
let ocbWithNewline = optimizedCodeBuffer.concat(new Buffer('\n'));
|
||||
let envData = fs.readFileSync(path.join(_this._distDir, '.env'));
|
||||
|
||||
let handlerFileName = _this._awsmJson.lambda.cloudFormation.Handler.split('.')[0],
|
||||
compressPaths = [
|
||||
let handlerFileName = _this._awsmJson.cloudFormation.Lambda.Handler.split('.')[0],
|
||||
compressPaths = [
|
||||
|
||||
// handlerFileName is the full path lambda file including dir rel to back
|
||||
{fileName: handlerFileName + '.js', data: ocbWithNewline},
|
||||
{fileName: '.env', data: envData},
|
||||
];
|
||||
// handlerFileName is the full path lambda file including dir rel to back
|
||||
{fileName: handlerFileName + '.js', data: ocbWithNewline},
|
||||
{fileName: '.env', data: envData},
|
||||
];
|
||||
|
||||
if (_this._awsmJson.lambda.package.optimize.includePaths.length) {
|
||||
compressPaths = compressPaths.concat(_this._generateIncludePaths());
|
||||
}
|
||||
if (_this._awsmJson.package.optimize.includePaths.length) {
|
||||
compressPaths = compressPaths.concat(_this._generateIncludePaths());
|
||||
}
|
||||
|
||||
return _this._compressCode(compressPaths);
|
||||
});
|
||||
return _this._compressCode(compressPaths);
|
||||
});
|
||||
} else {
|
||||
// User chose not to optimize, zip up whatever is in back
|
||||
_this._awsmJson.lambda.package.optimize.includePaths = ['.'];
|
||||
let compressPaths = _this._generateIncludePaths();
|
||||
deferred = _this._compressCode(compressPaths);
|
||||
_this._awsmJson.package.optimize.includePaths = ['.'];
|
||||
let compressPaths = _this._generateIncludePaths();
|
||||
deferred = _this._compressCode(compressPaths);
|
||||
}
|
||||
|
||||
return deferred
|
||||
.then(function(compressedCodeBuffer) {
|
||||
let zippedFilePath = path.join(_this._distDir, 'package.zip'); // Save for auditing;
|
||||
fs.writeFileSync(zippedFilePath, compressedCodeBuffer);
|
||||
.then(function(compressedCodeBuffer) {
|
||||
let zippedFilePath = path.join(_this._distDir, 'package.zip'); // Save for auditing;
|
||||
fs.writeFileSync(zippedFilePath, compressedCodeBuffer);
|
||||
|
||||
JawsCLI.log(`Lambda Deployer: Compressed lambda written to ${zippedFilePath}`);
|
||||
JawsCLI.log(`Lambda Deployer: Compressed lambda written to ${zippedFilePath}`);
|
||||
|
||||
return Promise.resolve({awsmFilePath: _this._lambdaPath, zipBuffer: compressedCodeBuffer});
|
||||
});
|
||||
return Promise.resolve({awsmFilePath: _this._lambdaPath, zipBuffer: compressedCodeBuffer});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -406,12 +406,12 @@ class Packager {
|
||||
|
||||
let _this = this;
|
||||
|
||||
if (!_this._awsmJson.lambda.package.optimize
|
||||
|| !_this._awsmJson.lambda.package.optimize.builder) {
|
||||
if (!_this._awsmJson.package.optimize
|
||||
|| !_this._awsmJson.package.optimize.builder) {
|
||||
return Promise.reject(new JawsError('Cant optimize for nodejs. lambda jaws.json does not have optimize.builder set'));
|
||||
}
|
||||
|
||||
if (_this._awsmJson.lambda.package.optimize.builder.toLowerCase() == 'browserify') {
|
||||
if (_this._awsmJson.package.optimize.builder.toLowerCase() == 'browserify') {
|
||||
return _this._browserifyBundle();
|
||||
} else {
|
||||
return Promise.reject(new JawsError(`Unsupported builder ${builder}`));
|
||||
@ -432,7 +432,7 @@ class Packager {
|
||||
};
|
||||
let b = browserify({
|
||||
basedir: _this._distDir,
|
||||
entries: [_this._awsmJson.lambda.cloudFormation.Handler.split('.')[0] + '.js'],
|
||||
entries: [_this._awsmJson.cloudFormation.Lambda.Handler.split('.')[0] + '.js'],
|
||||
standalone: 'lambda',
|
||||
browserField: false, // Setup for node app (copy logic of --node in bin/args.js)
|
||||
builtins: false,
|
||||
@ -447,21 +447,21 @@ class Packager {
|
||||
},
|
||||
});
|
||||
|
||||
if (_this._awsmJson.lambda.package.optimize.babel) {
|
||||
if (_this._awsmJson.package.optimize.babel) {
|
||||
b.transform(babelify)
|
||||
}
|
||||
|
||||
if (_this._awsmJson.lambda.package.optimize.transform) {
|
||||
b.transform(_this._awsmJson.lambda.package.optimize.transform);
|
||||
if (_this._awsmJson.package.optimize.transform) {
|
||||
b.transform(_this._awsmJson.package.optimize.transform);
|
||||
}
|
||||
|
||||
// optimize.exclude
|
||||
_this._awsmJson.lambda.package.optimize.exclude.forEach(file => {
|
||||
_this._awsmJson.package.optimize.exclude.forEach(file => {
|
||||
b.exclude(file);
|
||||
});
|
||||
|
||||
// optimize.ignore
|
||||
_this._awsmJson.lambda.package.optimize.ignore.forEach(file => {
|
||||
_this._awsmJson.package.optimize.ignore.forEach(file => {
|
||||
b.ignore(file);
|
||||
});
|
||||
|
||||
@ -478,7 +478,7 @@ class Packager {
|
||||
fs.writeFileSync(bundledFilePath, bundledBuf);
|
||||
JawsCLI.log(`Lambda Deployer: Bundled file written to ${bundledFilePath}`);
|
||||
|
||||
if (_this._awsmJson.lambda.package.optimize.exclude) {
|
||||
if (_this._awsmJson.package.optimize.exclude) {
|
||||
let result = UglifyJS.minify(bundledFilePath, uglyOptions);
|
||||
|
||||
if (!result || !result.code) {
|
||||
@ -509,7 +509,7 @@ class Packager {
|
||||
stats,
|
||||
fullPath;
|
||||
|
||||
_this._awsmJson.lambda.package.optimize.includePaths.forEach(p => {
|
||||
_this._awsmJson.package.optimize.includePaths.forEach(p => {
|
||||
try {
|
||||
fullPath = path.resolve(path.join(_this._distDir, p));
|
||||
stats = fs.lstatSync(fullPath);
|
||||
@ -524,20 +524,20 @@ class Packager {
|
||||
let dirname = path.basename(p);
|
||||
|
||||
wrench
|
||||
.readdirSyncRecursive(fullPath)
|
||||
.forEach(file => {
|
||||
// Ignore certain files
|
||||
for (let i = 0; i < ignore.length; i++) {
|
||||
if (file.toLowerCase().indexOf(ignore[i]) > -1) return;
|
||||
}
|
||||
.readdirSyncRecursive(fullPath)
|
||||
.forEach(file => {
|
||||
// Ignore certain files
|
||||
for (let i = 0; i < ignore.length; i++) {
|
||||
if (file.toLowerCase().indexOf(ignore[i]) > -1) return;
|
||||
}
|
||||
|
||||
let filePath = [fullPath, file].join('/');
|
||||
if (fs.lstatSync(filePath).isFile()) {
|
||||
let pathInZip = path.join(dirname, file);
|
||||
JawsUtils.jawsDebug('Adding', pathInZip);
|
||||
compressPaths.push({fileName: pathInZip, data: fs.readFileSync(filePath)});
|
||||
}
|
||||
});
|
||||
let filePath = [fullPath, file].join('/');
|
||||
if (fs.lstatSync(filePath).isFile()) {
|
||||
let pathInZip = path.join(dirname, file);
|
||||
JawsUtils.jawsDebug('Adding', pathInZip);
|
||||
compressPaths.push({fileName: pathInZip, data: fs.readFileSync(filePath)});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -564,8 +564,8 @@ class Packager {
|
||||
|
||||
if (zippedData.length > 52428800) {
|
||||
Promise.reject(new JawsError(
|
||||
'Zip file is > the 50MB Lambda deploy limit (' + zippedData.length + ' bytes)',
|
||||
JawsError.errorCodes.ZIP_TOO_BIG)
|
||||
'Zip file is > the 50MB Lambda deploy limit (' + zippedData.length + ' bytes)',
|
||||
JawsError.errorCodes.ZIP_TOO_BIG)
|
||||
);
|
||||
}
|
||||
|
||||
@ -644,22 +644,22 @@ usage: jaws lambda deploy [rel or abs path to lambda dirs. default is cwd]`,
|
||||
this._noExeCf = (noExeCf == true || noExeCf == 'true');
|
||||
|
||||
return this._JAWS.validateProject()
|
||||
.bind(_this)
|
||||
.then(_this._promptStage)
|
||||
.then(_this._validate)
|
||||
.then(() => {
|
||||
JawsUtils.jawsDebug('Deploying to stage:', _this._stage);
|
||||
return _this._setLambdaAwsmPaths(lambdaPaths);
|
||||
})
|
||||
.then(_this._getRegions)
|
||||
.each(region => {
|
||||
let d = new Deployer(_this.JAWS, _this._lambdaAwsmPathsToDeploy, _this._stage, region, _this._noExeCf);
|
||||
return d.run();
|
||||
})
|
||||
.then(lambdaAwsmPkgs => {
|
||||
JawsCLI.log('Lambda Deployer: Successfully deployed lambdas to the requested regions!');
|
||||
return lambdaAwsmPkgs;
|
||||
});
|
||||
.bind(_this)
|
||||
.then(_this._promptStage)
|
||||
.then(_this._validate)
|
||||
.then(() => {
|
||||
JawsUtils.jawsDebug('Deploying to stage:', _this._stage);
|
||||
return _this._setLambdaAwsmPaths(lambdaPaths);
|
||||
})
|
||||
.then(_this._getRegions)
|
||||
.each(region => {
|
||||
let d = new Deployer(_this.Jaws, _this._lambdaAwsmPathsToDeploy, _this._stage, region, _this._noExeCf);
|
||||
return d.run();
|
||||
})
|
||||
.then(lambdaAwsmPkgs => {
|
||||
JawsCLI.log('Lambda Deployer: Successfully deployed lambdas to the requested regions!');
|
||||
return lambdaAwsmPkgs;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -673,7 +673,7 @@ usage: jaws lambda deploy [rel or abs path to lambda dirs. default is cwd]`,
|
||||
|
||||
// If stage exists, skip
|
||||
if (!this._stage) {
|
||||
stages = Object.keys(_this.JAWS._projectJson.stages);
|
||||
stages = Object.keys(_this.Jaws._projectJson.stages);
|
||||
|
||||
// If project only has 1 stage, skip prompt
|
||||
if (stages.length === 1) {
|
||||
@ -696,9 +696,9 @@ usage: jaws lambda deploy [rel or abs path to lambda dirs. default is cwd]`,
|
||||
}
|
||||
|
||||
return this.selectInput('Lambda Deployer: Choose a stage: ', choices, false)
|
||||
.then(results => {
|
||||
_this._stage = results[0].value;
|
||||
});
|
||||
.then(results => {
|
||||
_this._stage = results[0].value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -715,7 +715,7 @@ usage: jaws lambda deploy [rel or abs path to lambda dirs. default is cwd]`,
|
||||
//Deploy to all regions in stage
|
||||
|
||||
let stage = this._stage,
|
||||
projJson = this.JAWS._projectJson;
|
||||
projJson = this.Jaws._projectJson;
|
||||
|
||||
let regionConfigs = projJson.stages[stage],
|
||||
regions = regionConfigs.map(rCfg => {
|
||||
@ -734,7 +734,7 @@ usage: jaws lambda deploy [rel or abs path to lambda dirs. default is cwd]`,
|
||||
*/
|
||||
_validate() {
|
||||
// Validate: Check stage exists within project
|
||||
if (!this.JAWS._projectJson.stages[_this._stage]) {
|
||||
if (!this.Jaws._projectJson.stages[_this._stage]) {
|
||||
return Promise.reject(new JawsError(`Invalid stage ${stage}`, JawsError.errorCodes.UNKNOWN));
|
||||
}
|
||||
|
||||
@ -750,9 +750,9 @@ usage: jaws lambda deploy [rel or abs path to lambda dirs. default is cwd]`,
|
||||
_setLambdaAwsmPaths(lambdaPaths) {
|
||||
let _this = this;
|
||||
return JawsUtils.getFullLambdaPaths(process.cwd(), lambdaPaths)
|
||||
.then(fullAwsmJsonPaths => {
|
||||
_this._lambdaAwsmPathsToDeploy = fullAwsmJsonPaths;
|
||||
});
|
||||
.then(fullAwsmJsonPaths => {
|
||||
_this._lambdaAwsmPathsToDeploy = fullAwsmJsonPaths;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
358
lib/defaults/actions/ModuleCreate.js
Normal file
358
lib/defaults/actions/ModuleCreate.js
Normal file
@ -0,0 +1,358 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Action: ModuleCreate
|
||||
*/
|
||||
|
||||
const JawsPlugin = require('../../JawsPlugin'),
|
||||
JawsError = require('../../jaws-error'),
|
||||
JawsCLI = require('../../utils/cli'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
os = require('os'),
|
||||
BbPromise = require('bluebird'),
|
||||
AWSUtils = require('../../utils/aws'),
|
||||
JawsUtils = require('../../utils');
|
||||
|
||||
let fs = require('fs');
|
||||
BbPromise.promisifyAll(fs);
|
||||
|
||||
const supportedRuntimes = {
|
||||
nodejs: {
|
||||
defaultPkgMgr: 'npm',
|
||||
validPkgMgrs: ['npm']
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ModuleCreate Class
|
||||
*/
|
||||
|
||||
class ModuleCreate extends JawsPlugin {
|
||||
|
||||
/**
|
||||
* @param Jaws class object
|
||||
* @param config object
|
||||
*/
|
||||
|
||||
constructor(Jaws, config) {
|
||||
super(Jaws, config);
|
||||
this._templatesDir = path.join(__dirname, '..', '..', 'templates');
|
||||
this._resource = "";
|
||||
this._action = "";
|
||||
this._pkgMgr = false;
|
||||
this._createLambda = false;
|
||||
this._createEndpoint = false;
|
||||
this._runtime = 'nodejs';
|
||||
}
|
||||
|
||||
/**
|
||||
* Define your plugins name
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
static getName() {
|
||||
return 'jaws.core.' + ModuleCreate.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise} upon completion of all registrations
|
||||
*/
|
||||
|
||||
registerActions() {
|
||||
this.Jaws.action(this.createModule.bind(this), {
|
||||
handler: 'moduleCreate',
|
||||
description: `Creates scaffolding for new aws module.
|
||||
usage: jaws module create <module resource> <action>`,
|
||||
context: 'module',
|
||||
contextAction: 'create',
|
||||
options: [
|
||||
{
|
||||
option: 'runtime',
|
||||
shortcut: 'r',
|
||||
description: ''
|
||||
},
|
||||
{
|
||||
option: 'lambda',
|
||||
shortcut: 'l',
|
||||
description: ''
|
||||
},
|
||||
{
|
||||
option: 'endpoint',
|
||||
shortcut: 'e',
|
||||
description: ''
|
||||
},
|
||||
{
|
||||
option: 'package-manager',
|
||||
shortcut: 'p',
|
||||
description: ''
|
||||
},
|
||||
|
||||
],
|
||||
});
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param runtime
|
||||
* @param createLambda
|
||||
* @param createEndpoint
|
||||
* @param pkgMgr
|
||||
* @param resourceAction <array> resource action
|
||||
* @returns {Promise}
|
||||
*/
|
||||
createModule(runtime, createLambda, createEndpoint, pkgMgr) {
|
||||
let _this = this,
|
||||
resourceAction = Array.prototype.slice.call(arguments, 5);
|
||||
|
||||
if (!resourceAction || resourceAction.length !== 2) {
|
||||
return Promise.reject(new JawsError('Must specify a resource and action'));
|
||||
}
|
||||
|
||||
if (!createLambda && !createEndpoint) { //default is to create both
|
||||
createEndpoint = true;
|
||||
createLambda = true;
|
||||
}
|
||||
|
||||
this._resource = resourceAction[0];
|
||||
this._action = resourceAction[1];
|
||||
this._createEndpoint = createEndpoint;
|
||||
this._createLambda = createLambda;
|
||||
this._runtime = runtime || 'nodejs';
|
||||
|
||||
if (!supportedRuntimes[this._runtime]) {
|
||||
throw new JawsError('Unsupported runtime ' + _this._runtime, JawsError.errorCodes.UNKNOWN);
|
||||
}
|
||||
|
||||
this._pkgMgr = pkgMgr || supportedRuntimes[this._runtime].defaultPkgMgr;
|
||||
|
||||
if (supportedRuntimes[this._runtime].validPkgMgrs.indexOf(this._pkgMgr) == -1) {
|
||||
throw new JawsError('Unsupported package manger "' + this._pkgMgr + '"', JawsError.errorCodes.UNKNOWN);
|
||||
}
|
||||
|
||||
return this._JAWS.validateProject()
|
||||
.bind(_this)
|
||||
.then(_this._sanitizeData)
|
||||
.then(_this._createSkeleton)
|
||||
.then(_this._createPackageMgrSkeleton)
|
||||
.then(_this._initRuntime)
|
||||
.then(function() {
|
||||
JawsCLI.log('Successfully created '
|
||||
+ _this._resourcee
|
||||
+ '/'
|
||||
+ _this._action);
|
||||
});
|
||||
}
|
||||
|
||||
_sanitizeData() {
|
||||
this._action = this._action.toLowerCase().trim()
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/[^a-zA-Z-\d:]/g, '')
|
||||
.substring(0, 19);
|
||||
|
||||
this._resource = this._resource.toLowerCase().trim()
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/[^a-zA-Z-\d:]/g, '')
|
||||
.substring(0, 19);
|
||||
}
|
||||
|
||||
_generateActionAwsmJson() {
|
||||
let actionTemplateJson = utils.readAndParseJsonSync(path.join(_this._templatesDir, 'action.awsm.json'));
|
||||
|
||||
//We prefix with an l to make sure the CloudFormation resource map index is unique
|
||||
actionTemplateJson.name = 'l' + this._resource.charAt(0).toUpperCase() + this._resource.slice(1) + this.action.charAt(0).toUpperCase() + this.action.slice(1);
|
||||
|
||||
if (this._createLambda) {
|
||||
actionTemplateJson.cloudFormation.Lambda.Runtime = this._runtime;
|
||||
|
||||
// Create files for lambda actions
|
||||
switch (this._runtime) {
|
||||
case 'nodejs':
|
||||
actionTemplateJson.cloudFormation.Lambda.Handler = path.join('aws_modules', this._resource, this._action, 'handler.handler');
|
||||
break;
|
||||
default:
|
||||
throw new JawsError('This runtime is not supported "' + this._runtime + '"', JawsError.errorCodes.UNKNOWN);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
delete actionTemplateJson.lambda;
|
||||
}
|
||||
|
||||
if (this._createEndpoint) {
|
||||
actionTemplateJson.cloudFormation.APIGatewayEndpoint.Path = this._resource + '/' + this._action;
|
||||
} else {
|
||||
delete actionTemplateJson.cloudFormation.APIGatewayEndpoint;
|
||||
}
|
||||
|
||||
//TODO: how do we support LambdaEventSourceMapping and LambdaAccessPolicyX
|
||||
delete actionTemplateJson.cloudFormation.LambdaEventSourceMapping;
|
||||
delete actionTemplateJson.cloudFormation.LambdaAccessPolicyX;
|
||||
|
||||
return actionTemplateJson;
|
||||
}
|
||||
|
||||
_generateModuleAwsmJson() {
|
||||
let moduleTemplateJson = utils.readAndParseJsonSync(path.join(this._templatesDir, 'module.awsm.json'));
|
||||
moduleTemplateJson.name = this._resource;
|
||||
return moduleTemplateJson;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
_createPackageMgrSkeleton() {
|
||||
let _this = this,
|
||||
deferredWrites = [];
|
||||
|
||||
switch (_this.runtime) {
|
||||
case 'nodejs':
|
||||
if (_this.pkgMgr == 'npm') {
|
||||
|
||||
let modulePath = path.join(_this._JAWS._projectRootPath, 'node_modules', _this._resource);
|
||||
|
||||
// Create node_module if DNE in node_modules
|
||||
if (!utils.dirExistsSync(modulePath)) {
|
||||
deferredWrites.push(fs.mkdirAsync(modulePath));
|
||||
}
|
||||
|
||||
// Create module package.json if DNE in node_module
|
||||
if (!utils.fileExistsSync(path.join(modulePath, 'package.json'))) {
|
||||
let packageJsonTemplate = utils.readAndParseJsonSync(path.join(_this._templatesDir, 'nodejs', 'package.json'));
|
||||
packageJsonTemplate.name = _this._resource;
|
||||
packageJsonTemplate.description = 'An aws-module';
|
||||
packageJsonTemplate.dependencies = {};
|
||||
|
||||
deferredWrites.push(
|
||||
fs.writeFileAsync(
|
||||
path.join(modulePath, 'package.json'),
|
||||
JSON.stringify(packageJsonTemplate, null, 2)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Create module awsm.json if DNE in node_module
|
||||
if (!utils.fileExistsSync(path.join(modulePath, 'awsm.json'))) {
|
||||
let moduleTemplateJson = _this._generateModuleAwsmJson();
|
||||
deferredWrites.push(
|
||||
utils.writeFile(
|
||||
path.join(modulePath, 'awsm.json'),
|
||||
JSON.stringify(moduleTemplateJson, null, 2)));
|
||||
}
|
||||
|
||||
// Create root lib folder if DNE in node_module
|
||||
let modLibPath = path.join(modulePath, 'lib');
|
||||
if (!utils.dirExistsSync(modLibPath)) {
|
||||
deferredWrites.push(fs.mkdirAsync(modLibPath));
|
||||
}
|
||||
|
||||
// Create awsm folder if DNE in node_module
|
||||
if (!utils.dirExistsSync(path.join(modulePath, 'awsm'))) {
|
||||
deferredWrites.push(fs.mkdirAsync(path.join(modulePath, 'awsm')));
|
||||
}
|
||||
|
||||
// Create action if DNE in node_module
|
||||
let actionPath = path.join(modulePath, 'awsm', _this.action);
|
||||
if (!utils.dirExistsSync(actionPath)) {
|
||||
|
||||
let actionTemplateJson = this._generateActionAwsmJson(),
|
||||
handlerJs = fs.readFileSync(path.join(_this._templatesDir, 'nodejs', 'handler.js')),
|
||||
indexJs = fs.readFileSync(path.join(_this._templatesDir, 'nodejs', 'index.js'));
|
||||
|
||||
deferredWrites.push(
|
||||
utils.writeFile(
|
||||
path.join(actionPath, 'awsm.json'),
|
||||
JSON.stringify(actionTemplateJson, null, 2)
|
||||
),
|
||||
utils.writeFile(path.join(actionPath, 'handler.js'), handlerJs),
|
||||
utils.writeFile(path.join(actionPath, 'index.js'), indexJs),
|
||||
utils.writeFile(path.join(actionPath, 'event.json'), '{}')
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Promise.all(deferredWrites);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
_createSkeleton() {
|
||||
let _this = this,
|
||||
writeFilesDeferred = [];
|
||||
|
||||
let modulePath = path.join(_this._JAWS._projectRootPath, 'aws_modules', _this._resource),
|
||||
actionPath = path.join(modulePath, _this.action);
|
||||
|
||||
// If module/action already exists, throw error
|
||||
if (utils.dirExistsSync(actionPath)) {
|
||||
throw new JawsError(
|
||||
actionPath + ' already exists',
|
||||
JawsError.errorCodes.INVALID_PROJECT_JAWS
|
||||
);
|
||||
}
|
||||
|
||||
//module path will get created by util.writeFile if DNE
|
||||
|
||||
// If module awsm.json doesn't exist, create it
|
||||
if (!utils.fileExistsSync(path.join(modulePath, 'awsm.json'))) {
|
||||
let moduleTemplateJson = _this._generateModuleAwsmJson();
|
||||
writeFilesDeferred.push(
|
||||
utils.writeFile(
|
||||
path.join(modulePath, 'awsm.json'),
|
||||
JSON.stringify(moduleTemplateJson, null, 2)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Create action folder
|
||||
writeFilesDeferred.push(actionPath);
|
||||
|
||||
// Create action awsm.json
|
||||
let actionTemplateJson = _this._generateActionAwsmJson();
|
||||
|
||||
|
||||
let handlerJs = fs.readFileSync(path.join(this._templatesDir, 'nodejs', 'handler.js')),
|
||||
indexJs = fs.readFileSync(path.join(this._templatesDir, 'nodejs', 'index.js'));
|
||||
|
||||
writeFilesDeferred.push(
|
||||
utils.writeFile(path.join(actionPath, 'handler.js'), handlerJs),
|
||||
utils.writeFile(path.join(actionPath, 'index.js'), indexJs),
|
||||
utils.writeFile(path.join(actionPath, 'event.json'), '{}'),
|
||||
utils.writeFile(path.join(actionPath, 'awsm.json'), JSON.stringify(actionTemplateJson, null, 2))
|
||||
);
|
||||
|
||||
return Promise.all(writeFilesDeferred);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
_initRuntime() {
|
||||
let _this = this;
|
||||
|
||||
JawsCLI.log('Preparing your runtime..');
|
||||
|
||||
if (_this._runtime === 'nodejs') {
|
||||
let packageJsonTemplate = JawsUtils.readAndParseJsonSync(path.join(_this._templatesDir, 'nodejs', 'package.json'));
|
||||
packageJsonTemplate.name = _this.Jaws._projectJson.name;
|
||||
return fs.writeFileAsync(path.join(_this.Jaws, _projectRootPath, 'package.json'), JSON.stringify(packageJsonTemplate, null, 2))
|
||||
.then(function() {
|
||||
JawsCLI.log('Installing jaws-core module...');
|
||||
JawsUtils.npmInstall(_this._projectRootPath);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ModuleCreate;
|
||||
@ -4,16 +4,17 @@
|
||||
* Action: ProjectCreate
|
||||
*/
|
||||
|
||||
const JawsPlugin = require('../../JawsPlugin'),
|
||||
JawsError = require('../../jaws-error'),
|
||||
JawsCLI = require('../../utils/cli'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
os = require('os'),
|
||||
BbPromise = require('bluebird'),
|
||||
AWSUtils = require('../../utils/aws'),
|
||||
JawsUtils = require('../../utils'),
|
||||
shortid = require('shortid');
|
||||
const JawsPlugin = require('../../JawsPlugin'),
|
||||
JawsError = require('../../jaws-error'),
|
||||
JawsCLI = require('../../utils/cli'),
|
||||
path = require('path'),
|
||||
os = require('os'),
|
||||
BbPromise = require('bluebird'),
|
||||
AWSUtils = require('../../utils/aws'),
|
||||
JawsUtils = require('../../utils');
|
||||
|
||||
let fs = require('fs');
|
||||
BbPromise.promisifyAll(fs);
|
||||
|
||||
/**
|
||||
* ProjectCreate Class
|
||||
@ -28,6 +29,7 @@ class ProjectCreate extends JawsPlugin {
|
||||
|
||||
constructor(Jaws, config) {
|
||||
super(Jaws, config);
|
||||
this._templatesDir = path.join(__dirname, '..', '..', 'templates');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,7 +46,7 @@ class ProjectCreate extends JawsPlugin {
|
||||
*/
|
||||
|
||||
registerActions() {
|
||||
this.Jaws.action(this._action.bind(this), {
|
||||
this.Jaws.action(this.createProject.bind(this), {
|
||||
handler: 'projectCreate',
|
||||
description: 'Creates scaffolding for a new JAWS project',
|
||||
context: 'project',
|
||||
@ -85,269 +87,224 @@ class ProjectCreate extends JawsPlugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* Action
|
||||
* - Contains control flow
|
||||
*
|
||||
* @param name
|
||||
* @param domain
|
||||
* @param stage
|
||||
* @param region
|
||||
* @param notificationEmail
|
||||
* @param runtime
|
||||
* @param noCf
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
|
||||
_action(name, domain, stage, region, notificationEmail, runtime, noCf) {
|
||||
createProject(name, domain, stage, region, notificationEmail, runtime, noCf) {
|
||||
|
||||
let _this = this;
|
||||
/**
|
||||
* Non-Interactive Validations
|
||||
*/
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
||||
/**
|
||||
* Non-Interactive Validations
|
||||
*/
|
||||
|
||||
if (!_this.Jaws._interactive) {
|
||||
|
||||
// Check API Keys
|
||||
if (!_this.Jaws._awsAdminKeyId || !_this.Jaws._awsAdminSecretKey) {
|
||||
throw new JawsError('Missing AWS API Key and/or AWS Secret Key');
|
||||
}
|
||||
|
||||
// Check Params
|
||||
if (!name || !stage || !region || !domain || !notificationEmail) {
|
||||
throw new JawsError('Missing required properties');
|
||||
}
|
||||
if (!_this.Jaws._interactive && !this.Jaws._awsProfile) {
|
||||
// Check API Keys
|
||||
if (!_this.Jaws._awsAdminKeyId || !_this.Jaws._awsAdminSecretKey) {
|
||||
throw new JawsError('Missing AWS API Key and/or AWS Secret Key');
|
||||
}
|
||||
|
||||
/**
|
||||
* Defaults
|
||||
*/
|
||||
|
||||
_this._name = name || null;
|
||||
_this._domain = domain || null;
|
||||
_this._stage = stage ? stage.toLowerCase().replace(/\W+/g, '').substring(0, 15) : null;
|
||||
_this._notificationEmail = notificationEmail;
|
||||
_this._region = region;
|
||||
_this._runtime = runtime || 'nodejs';
|
||||
_this._noCf = noCf;
|
||||
|
||||
// Interactive Defaults
|
||||
if (_this.Jaws._interactive) {
|
||||
_this._prompts = {
|
||||
properties: {},
|
||||
};
|
||||
_this.Prompter = JawsCLI.prompt();
|
||||
_this.Prompter.override = {};
|
||||
_this._spinner = null;
|
||||
// Check Params
|
||||
if (!name || !stage || !region || !domain || !notificationEmail) {
|
||||
throw new JawsError('Missing required properties');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Control Flow
|
||||
*/
|
||||
/**
|
||||
* Defaults
|
||||
*/
|
||||
|
||||
return BbPromise.try(function() {
|
||||
_this._name = name || null;
|
||||
_this._domain = domain || null;
|
||||
_this._stage = stage ? stage.toLowerCase().replace(/\W+/g, '').substring(0, 15) : null;
|
||||
_this._notificationEmail = notificationEmail;
|
||||
_this._region = region;
|
||||
_this._runtime = runtime || 'nodejs';
|
||||
_this._noCf = noCf;
|
||||
|
||||
// ASCII Greeting
|
||||
if (_this.Jaws._interactive) JawsCLI.ascii();
|
||||
// Interactive Defaults
|
||||
if (_this.Jaws._interactive) {
|
||||
_this._prompts = {
|
||||
properties: {},
|
||||
};
|
||||
_this.Prompter = JawsCLI.prompt();
|
||||
_this.Prompter.override = {};
|
||||
_this._spinner = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Control Flow
|
||||
*/
|
||||
|
||||
return BbPromise.try(function() {
|
||||
if (_this.Jaws._interactive) {
|
||||
JawsCLI.asciiGreeting();
|
||||
}
|
||||
})
|
||||
.bind(_this)
|
||||
.then(_this._prompt)
|
||||
.then(_this._prepareProjectData)
|
||||
.then(_this._createProjectDirectory)
|
||||
.then(_this._putEnvFile)
|
||||
.then(_this._putCfFile)
|
||||
.then(_this._createCfStack)
|
||||
.then(_this._createProjectJson)
|
||||
.then(_this._initRuntime);
|
||||
|
||||
return resolve();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate ShortId
|
||||
*/
|
||||
|
||||
_generateShortId(maxLen) {
|
||||
return shortid.generate().replace(/\W+/g, '').substring(0, maxLen).replace(/[_-]/g, '');
|
||||
.bind(_this)
|
||||
.then(_this._prompt)
|
||||
.then(_this._prepareProjectData)
|
||||
.then(_this._createProjectDirectory)
|
||||
.then(_this._createJawsBucket)
|
||||
.then(_this._putEnvFile)
|
||||
.then(_this._putCfFile)
|
||||
.then(_this._createCfStack)
|
||||
.then(_this._createProjectJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt
|
||||
* @returns {*}
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
|
||||
_prompt() {
|
||||
let _this = this,
|
||||
overrides = {};
|
||||
|
||||
// Skip, if not interactive
|
||||
if (!this.Jaws._interactive) return Promise.resolve();
|
||||
//Setup overrides based off of member var values
|
||||
['name', 'domain', 'notificationEmail', 'stage', 'awsAdminKeyId', 'awsAdminSecretKey']
|
||||
.forEach(memberVarKey => {
|
||||
overrides[memberVarKey] = _this['_' + memberVarKey];
|
||||
});
|
||||
|
||||
JawsUtils.jawsDebug('Prompting for new project information');
|
||||
|
||||
let _this = this;
|
||||
|
||||
let nameDescription = 'Enter a project name: ';
|
||||
|
||||
// Prompt: name (project name)
|
||||
_this.Prompter.override.name = _this._name;
|
||||
// Set default name
|
||||
_this._name = 'jaws-' + _this._generateShortId(19);
|
||||
_this._prompts.properties.name = {
|
||||
description: nameDescription.yellow,
|
||||
default: _this._name,
|
||||
message: 'Name must be only letters, numbers or dashes',
|
||||
conform: function (name) {
|
||||
let re = /^[a-zA-Z0-9-_]+$/;
|
||||
return re.test(name);
|
||||
},
|
||||
let prompts = {
|
||||
properties: {
|
||||
name: {
|
||||
description: 'Enter a project name: '.yellow,
|
||||
default: 'jaws-' + JawsUtils.generateShortId(19),
|
||||
message: 'Name must be only letters, numbers or dashes',
|
||||
required: true,
|
||||
conform: function(name) {
|
||||
let re = /^[a-zA-Z0-9-_]+$/;
|
||||
return re.test(name);
|
||||
},
|
||||
},
|
||||
domain: {
|
||||
description: 'Enter a project domain (used for jaws s3 bucket name): '.yellow,
|
||||
default: 'myapp.com',
|
||||
message: 'Domain must only contain lowercase letters, numbers, periods and dashes',
|
||||
required: true,
|
||||
conform: function(bucket) {
|
||||
let re = /^[a-z0-9-.]+$/;
|
||||
return re.test(bucket);
|
||||
},
|
||||
},
|
||||
notificationEmail: {
|
||||
description: 'Enter an email to use for AWS alarms: '.yellow,
|
||||
required: true,
|
||||
message: 'Please enter a valid email',
|
||||
default: 'me@myapp.com',
|
||||
conform: function(email) {
|
||||
return (!email) ? false : true;
|
||||
},
|
||||
},
|
||||
stage: {
|
||||
description: 'Enter a stage name for this project: '.yellow,
|
||||
required: true,
|
||||
default: 'dev',
|
||||
message: 'Stage must be letters only',
|
||||
conform: function(stage) {
|
||||
let re = /^[a-zA-Z]+$/;
|
||||
return re.test(stage);
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Prompt: domain - for AWS hosted zone and more
|
||||
_this.Prompter.override.domain = _this._domain;
|
||||
|
||||
let domainDescription = 'Enter a project domain (You can change this at any time: ';
|
||||
|
||||
_this._prompts.properties.domain = {
|
||||
description: domainDescription.yellow,
|
||||
default: 'myapp.com',
|
||||
message: 'Domain must only contain lowercase letters, numbers, periods and dashes',
|
||||
conform: function (bucket) {
|
||||
let re = /^[a-z0-9-.]+$/;
|
||||
return re.test(bucket);
|
||||
},
|
||||
};
|
||||
|
||||
// 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: 'me@myapp.com',
|
||||
conform: function (email) {
|
||||
if (!email) return false;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// Prompt: stage
|
||||
_this.Prompter.override.stage = _this._stage;
|
||||
|
||||
let stageDescription = 'Enter a stage for this project: ';
|
||||
|
||||
_this._prompts.properties.stage = {
|
||||
description: stageDescription.yellow,
|
||||
default: 'dev',
|
||||
message: 'Stage must be letters only',
|
||||
conform: function (stage) {
|
||||
let re = /^[a-zA-Z]+$/;
|
||||
return re.test(stage);
|
||||
},
|
||||
};
|
||||
|
||||
// Prompt: notification email - for AWS alerts
|
||||
_this.Prompter.override.notificationEmail = _this._notificationEmail;
|
||||
|
||||
let notificationEmailDescription = 'Enter an email to use for AWS alarms: ';
|
||||
|
||||
_this._prompts.properties.notificationEmail = {
|
||||
description: notificationEmailDescription.yellow,
|
||||
required: true,
|
||||
message: 'Please enter a valid email',
|
||||
default: 'you@yourapp.com',
|
||||
conform: function (email) {
|
||||
if (!email) return false;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// Prompt: API Keys - Create an AWS profile by entering API keys
|
||||
//Create aws credentials if DNE
|
||||
if (!JawsUtils.fileExistsSync(path.join(AWSUtils.getConfigDir(), 'credentials'))) {
|
||||
|
||||
_this.Prompter.override.awsAdminKeyId = _this._awsAdminKeyId;
|
||||
|
||||
let apiKeyDescription = 'Enter the ACCESS KEY ID for your Admin AWS IAM User: ';
|
||||
|
||||
_this._prompts.properties.awsAdminKeyId = {
|
||||
description: apiKeyDescription.yellow,
|
||||
prompts.properties.awsAdminKeyId = {
|
||||
description: 'Enter the ACCESS KEY ID for your Admin AWS IAM User: '.yellow,
|
||||
required: true,
|
||||
message: 'Please enter a valid access key ID',
|
||||
conform: function (key) {
|
||||
if (!key) return false;
|
||||
return true;
|
||||
conform: function(key) {
|
||||
return (key) ? false : true;
|
||||
},
|
||||
};
|
||||
_this.Prompter.override.awsAdminSecretKey = _this._awsAdminSecretKey;
|
||||
|
||||
let apiSecretDescription = 'Enter the SECRET ACCESS KEY for your Admin AWS IAM User: ';
|
||||
|
||||
_this._prompts.properties.awsAdminSecretKey = {
|
||||
description: apiSecretDescription.yellow,
|
||||
prompts.properties.awsAdminSecretKey = {
|
||||
description: 'Enter the SECRET ACCESS KEY for your Admin AWS IAM User: '.yellow,
|
||||
required: true,
|
||||
message: 'Please enter a valid secret access key',
|
||||
conform: function (key) {
|
||||
conform: function(key) {
|
||||
if (!key) return false;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Show Prompts
|
||||
return _this.Prompter.getAsync(_this._prompts)
|
||||
.then(function (answers) {
|
||||
_this._name = answers.name;
|
||||
_this._domain = answers.domain;
|
||||
_this._stage = answers.stage.toLowerCase();
|
||||
_this._notificationEmail = answers.notificationEmail;
|
||||
_this._awsAdminKeyId = answers.awsAdminKeyId;
|
||||
_this._awsAdminSecretKey = answers.awsAdminSecretKey;
|
||||
return this.promptInput(prompts, overrides)
|
||||
.then(function(answers) {
|
||||
_this._name = answers.name;
|
||||
_this._domain = answers.domain;
|
||||
_this._stage = answers.stage.toLowerCase();
|
||||
_this._notificationEmail = answers.notificationEmail;
|
||||
_this._awsAdminKeyId = answers.awsAdminKeyId;
|
||||
_this._awsAdminSecretKey = answers.awsAdminSecretKey;
|
||||
|
||||
// If region exists, skip select prompt
|
||||
if (_this._region) return;
|
||||
// If region exists, skip select prompt
|
||||
if (_this._region) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prompt: region select
|
||||
let choices = [];
|
||||
AWSUtils.validLambdaRegions.forEach(function (r) {
|
||||
choices.push({
|
||||
key: '',
|
||||
value: r,
|
||||
label: r,
|
||||
});
|
||||
// Prompt: region select
|
||||
let choices = [];
|
||||
AWSUtils.validLambdaRegions.forEach(function(r) {
|
||||
choices.push({
|
||||
key: '',
|
||||
value: r,
|
||||
label: r,
|
||||
});
|
||||
|
||||
return JawsCLI.select('Select a region for your project: ', choices, false)
|
||||
.then(function (results) {
|
||||
_this._region = results[0].value;
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
|
||||
// If profile exists, skip select prompt
|
||||
if (_this._profile) return Promise.resolve();
|
||||
|
||||
// If aws credentials were passed, skip select prompt
|
||||
if (_this._awsAdminKeyId && _this._awsAdminSecretKey) return Promise.resolve();
|
||||
|
||||
// Prompt: profile select
|
||||
let profilesList = AWSUtils.profilesMap(),
|
||||
profiles = Object.keys(profilesList),
|
||||
choices = [];
|
||||
|
||||
for (let i = 0; i < profiles.length; i++) {
|
||||
choices.push({
|
||||
key: '',
|
||||
value: profiles[i],
|
||||
label: profiles[i],
|
||||
});
|
||||
}
|
||||
|
||||
return JawsCLI.select('Select an AWS profile for your project: ', choices, false)
|
||||
.then(function (results) {
|
||||
_this._profile = results[0].value;
|
||||
});
|
||||
});
|
||||
|
||||
return _this.selectInput('Select a region for your project: ', choices, false)
|
||||
.then(results => {
|
||||
_this._region = results[0].value;
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
|
||||
// If profile exists, skip select prompt
|
||||
if (_this._awsProfile) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If aws credentials were passed, skip select prompt
|
||||
if (_this._awsAdminKeyId && _this._awsAdminSecretKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prompt: profile select
|
||||
let profilesList = AWSUtils.profilesMap(),
|
||||
profiles = Object.keys(profilesList),
|
||||
choices = [];
|
||||
|
||||
for (let i = 0; i < profiles.length; i++) {
|
||||
choices.push({
|
||||
key: '',
|
||||
value: profiles[i],
|
||||
label: profiles[i],
|
||||
});
|
||||
}
|
||||
|
||||
return _this.selectInput('Select an AWS profile for your project: ', choices, false)
|
||||
.then(results => {
|
||||
_this._awsProfile = results[0].value;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Project Data
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
|
||||
_prepareProjectData() {
|
||||
@ -367,21 +324,21 @@ class ProjectCreate extends JawsPlugin {
|
||||
|
||||
// Append unique id if name is in use
|
||||
if (JawsUtils.dirExistsSync(path.join(process.cwd(), _this._name))) {
|
||||
_this._name = _this._name + '-' + _this._generateShortId(19);
|
||||
_this._name = _this._name + '-' + JawsUtils.generateShortId(19);
|
||||
}
|
||||
|
||||
// Append unique id if domain is default
|
||||
if (_this._domain === 'myapp.com') {
|
||||
_this._domain = 'myapp-' + _this._generateShortId(8) + '.com';
|
||||
_this._domain = 'myapp-' + JawsUtils.generateShortId(8) + '.com';
|
||||
}
|
||||
|
||||
// Set JAWS Bucket
|
||||
_this._jawsBucket = JawsUtils.generateJawsBucketName(_this._stage, _this._region, _this._domain);
|
||||
|
||||
// If no profile, ensure access keys, create profile
|
||||
if (!_this._profile) {
|
||||
if (!_this._awsProfile) {
|
||||
AWSUtils.profilesSet('default', _this._region, _this.Jaws._awsAdminKeyId, _this.Jaws._awsAdminSecretKey);
|
||||
_this._profile = 'default';
|
||||
_this._awsProfile = 'default';
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
@ -389,6 +346,7 @@ class ProjectCreate extends JawsPlugin {
|
||||
|
||||
/**
|
||||
* Create Project Directory
|
||||
* @returns {Private}
|
||||
* @private
|
||||
*/
|
||||
|
||||
@ -398,42 +356,52 @@ class ProjectCreate extends JawsPlugin {
|
||||
_this._projectRootPath = path.resolve(path.join(path.dirname('.'), _this._name));
|
||||
|
||||
// Prepare admin.env
|
||||
let adminEnv = 'JAWS_ADMIN_AWS_PROFILE=' + _this._profile + os.EOL;
|
||||
let adminEnv = 'JAWS_ADMIN_AWS_PROFILE=' + _this._awsProfile + os.EOL;
|
||||
|
||||
// Prepare README.md
|
||||
let readme = '#' + _this._name;
|
||||
|
||||
// Create Project Scaffolding
|
||||
return JawsUtils.writeFile(
|
||||
path.join(_this._projectRootPath, '.env'),
|
||||
'JAWS_STAGE=' + _this._stage
|
||||
+ '\nJAWS_DATA_MODEL_STAGE=' + _this._stage
|
||||
)
|
||||
.then(function () {
|
||||
return Promise.all([
|
||||
fs.mkdirAsync(path.join(_this._projectRootPath, 'tests')),
|
||||
fs.mkdirAsync(path.join(_this._projectRootPath, 'lib')),
|
||||
fs.mkdirAsync(path.join(_this._projectRootPath, 'aws_modules')),
|
||||
JawsUtils.writeFile(path.join(_this._projectRootPath, 'admin.env'), adminEnv),
|
||||
JawsUtils.writeFile(path.join(_this._projectRootPath, 'README.md'), readme),
|
||||
JawsUtils.generateResourcesCf(
|
||||
_this._projectRootPath,
|
||||
_this._name,
|
||||
_this._domain,
|
||||
_this._stage,
|
||||
_this._region,
|
||||
_this._notificationEmail,
|
||||
_this._jawsBucket
|
||||
),
|
||||
fs.writeFileAsync(path.join(_this._projectRootPath, '.gitignore'), fs.readFileSync(__dirname + '/../../templates/gitignore')),
|
||||
]);
|
||||
});
|
||||
path.join(_this._projectRootPath, '.env'),
|
||||
'JAWS_STAGE=' + _this._stage
|
||||
+ '\nJAWS_DATA_MODEL_STAGE=' + _this._stage
|
||||
)
|
||||
.then(function() {
|
||||
return Promise.all([
|
||||
fs.mkdirAsync(path.join(_this._projectRootPath, 'tests')),
|
||||
fs.mkdirAsync(path.join(_this._projectRootPath, 'lib')),
|
||||
fs.mkdirAsync(path.join(_this._projectRootPath, 'aws_modules')),
|
||||
JawsUtils.writeFile(path.join(_this._projectRootPath, 'admin.env'), adminEnv),
|
||||
JawsUtils.writeFile(path.join(_this._projectRootPath, 'README.md'), readme),
|
||||
JawsUtils.generateResourcesCf(
|
||||
_this._projectRootPath,
|
||||
_this._name,
|
||||
_this._domain,
|
||||
_this._stage,
|
||||
_this._region,
|
||||
_this._notificationEmail
|
||||
),
|
||||
fs.writeFileAsync(path.join(_this._projectRootPath, '.gitignore'), fs.readFileSync(path.join(_this._templatesDir, 'gitignore'))),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create jaws bucket if it does not exist
|
||||
*
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
_createJawsBucket() {
|
||||
JawsUtils.jawsDebug('Creating jaws s3 bucket: ', this._jawsBucket);
|
||||
return AWSUtils.createBucket(this._awsProfile, this._region, this._jawsBucket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put ENV File
|
||||
* - Creates ENV file in JAWS stage/region bucket
|
||||
* @returns {Private}
|
||||
* @private
|
||||
*/
|
||||
|
||||
@ -446,18 +414,18 @@ class ProjectCreate extends JawsPlugin {
|
||||
JAWS_DATA_MODEL_STAGE=${stage}`;
|
||||
|
||||
return AWSUtils.putEnvFile(
|
||||
_this._profile,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._name,
|
||||
_this._stage,
|
||||
envFileContents);
|
||||
_this._awsProfile,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._name,
|
||||
_this._stage,
|
||||
envFileContents);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Put CF File
|
||||
* @returns {*}
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
|
||||
@ -466,22 +434,26 @@ class ProjectCreate extends JawsPlugin {
|
||||
let _this = this;
|
||||
|
||||
return AWSUtils.putCfFile(
|
||||
_this._profile,
|
||||
_this._projectRootPath,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._name,
|
||||
_this._stage,
|
||||
'resources');
|
||||
_this._awsProfile,
|
||||
_this._projectRootPath,
|
||||
_this._region,
|
||||
_this._jawsBucket,
|
||||
_this._name,
|
||||
_this._stage,
|
||||
'resources');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create CloudFormation Stack
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
|
||||
_createCfStack() {
|
||||
if (this._noCf) {
|
||||
JawsUtils.jawsDebug('No execute CF was specified, skipping');
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let _this = this;
|
||||
|
||||
@ -491,45 +463,42 @@ class ProjectCreate extends JawsPlugin {
|
||||
|
||||
// Create CF stack
|
||||
return AWSUtils.cfCreateResourcesStack(
|
||||
_this._profile,
|
||||
_this._region,
|
||||
_this._projectRootPath,
|
||||
_this._name,
|
||||
_this._stage,
|
||||
_this._domain,
|
||||
_this._notificationEmail,
|
||||
_this._jawsBucket
|
||||
)
|
||||
.then(function (cfData) {
|
||||
return AWSUtils.monitorCf(cfData, _this._profile, _this._region, 'create');
|
||||
});
|
||||
_this._awsProfile,
|
||||
_this._region,
|
||||
_this._projectRootPath,
|
||||
_this._name,
|
||||
_this._stage,
|
||||
_this._domain,
|
||||
_this._notificationEmail
|
||||
)
|
||||
.then(cfData => {
|
||||
return AWSUtils.monitorCf(cfData, _this._awsProfile, _this._region, 'create');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Project JSON
|
||||
* @private
|
||||
*/
|
||||
|
||||
_createProjectJson() {
|
||||
_createProjectJson(cfStackData) {
|
||||
|
||||
let _this = this,
|
||||
iamRoleArnLambda,
|
||||
iamRoleArnApiGateway;
|
||||
|
||||
if (_this._cfData) {
|
||||
for (let i = 0; i < _this._cfData.Outputs.length; i++) {
|
||||
if (_this._cfData.Outputs[i].OutputKey === 'IamRoleArnLambda') {
|
||||
iamRoleArnLambda = _this._cfData.Outputs[i].OutputValue;
|
||||
if (cfStackData) {
|
||||
for (let i = 0; i < cfStackData.Outputs.length; i++) {
|
||||
if (cfStackData.Outputs[i].OutputKey === 'IamRoleArnLambda') {
|
||||
iamRoleArnLambda = cfStackData.Outputs[i].OutputValue;
|
||||
}
|
||||
|
||||
if (_this._cfData.Outputs[i].OutputKey === 'IamRoleArnApiGateway') {
|
||||
iamRoleArnApiGateway = _this._cfData.Outputs[i].OutputValue;
|
||||
if (cfStackData.Outputs[i].OutputKey === 'IamRoleArnApiGateway') {
|
||||
iamRoleArnApiGateway = cfStackData.Outputs[i].OutputValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let templatesPath = path.join(__dirname, '..', '..', 'templates'),
|
||||
jawsJson = JawsUtils.readAndParseJsonSync(path.join(templatesPath, 'jaws.json'));
|
||||
let jawsJson = JawsUtils.readAndParseJsonSync(path.join(_this._templatesDir, 'jaws.json'));
|
||||
|
||||
jawsJson.stages[_this._stage] = [{
|
||||
region: _this._region,
|
||||
@ -538,38 +507,14 @@ class ProjectCreate extends JawsPlugin {
|
||||
jawsBucket: _this._jawsBucket,
|
||||
}];
|
||||
|
||||
jawsJson.name = _this._name;
|
||||
jawsJson.name = _this._name;
|
||||
jawsJson.domain = _this._domain;
|
||||
|
||||
fs.writeFileSync(path.join(_this._projectRootPath, 'jaws.json'),
|
||||
JSON.stringify(jawsJson, null, 2));
|
||||
JSON.stringify(jawsJson, null, 2));
|
||||
|
||||
return jawsJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init Runtime
|
||||
* @private
|
||||
*/
|
||||
|
||||
_initRuntime() {
|
||||
|
||||
let _this = this;
|
||||
|
||||
JawsCLI.log('Preparing your runtime and installing jaws-core module...');
|
||||
|
||||
if (_this._runtime === 'nodejs') {
|
||||
let packageJsonTemplate = JawsUtils.readAndParseJsonSync(path.join(__dirname, '..', 'templates', 'nodejs', 'package.json'));
|
||||
packageJsonTemplate.name = _this._name;
|
||||
return fs.writeFileAsync(path.join(_this._projectRootPath, 'package.json'), JSON.stringify(packageJsonTemplate, null, 2))
|
||||
.then(function () {
|
||||
JawsUtils.jawsDebug('test_utils', 'Running NPM install...');
|
||||
JawsUtils.npmInstall(_this._projectRootPath);
|
||||
});
|
||||
} else {
|
||||
throw new JawsError('Unsupported runtime "' + _this.runtime + '"', JawsError.errorCodes.UNKNOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ProjectCreate;
|
||||
@ -78,32 +78,32 @@ class VersionLambda extends JawsPlugin {
|
||||
this._stage = stage;
|
||||
this._region = region; //may not be set
|
||||
|
||||
return this._JAWS.validateProject()
|
||||
.bind(_this)
|
||||
.then(_this._promptStage)
|
||||
.then(() => {
|
||||
JawsUtils.jawsDebug('publishing version for stage:', _this._stage);
|
||||
return _this._setLambdaLogicalIds(lambdaPaths);
|
||||
})
|
||||
.then(_this._getRegions)
|
||||
.each(region => {
|
||||
//1) For each region, get all the lambdas for stack
|
||||
let lStackName = AWSUtils.cfGetLambdasStackName(_this._stage, _this._JAWS._projectJson.name);
|
||||
return AWSUtils.cfGetLambdaResourceSummaries(_this.Jaws._profile, region, lStackName)
|
||||
.then(lambdaSummaries => {
|
||||
//2) identify physical function names from logical
|
||||
return AWSUtils.cfGetLambdaPhysicalsFromLogicals(_this._lambdaLogicalIdsToVersion, lambdaSummaries);
|
||||
})
|
||||
.then(lambdaNamesToVersion => {
|
||||
//3) publishVersions
|
||||
return AWSUtils.lambdaPublishVersions(_this.Jaws._profile, region, lambdaNamesToVersion);
|
||||
});
|
||||
})
|
||||
.then(versionedLambdas => {
|
||||
JawsCLI.log('Lambda VersionLambda: Successfully published following lambda versions to the requested regions:');
|
||||
JawsCLI.log(versionedLambdas);
|
||||
return versionedLambdas;
|
||||
});
|
||||
return this.Jaws.validateProject()
|
||||
.bind(_this)
|
||||
.then(_this._promptStage)
|
||||
.then(() => {
|
||||
JawsUtils.jawsDebug('publishing version for stage:', _this._stage);
|
||||
return _this._setLambdaLogicalIds(lambdaPaths);
|
||||
})
|
||||
.then(_this._getRegions)
|
||||
.each(region => {
|
||||
//1) For each region, get all the lambdas for stack
|
||||
let lStackName = AWSUtils.cfGetLambdasStackName(_this._stage, _this.Jaws._projectJson.name);
|
||||
return AWSUtils.cfGetLambdaResourceSummaries(_this.Jaws._awsProfile, region, lStackName)
|
||||
.then(lambdaSummaries => {
|
||||
//2) identify physical function names from logical
|
||||
return AWSUtils.cfGetLambdaPhysicalsFromLogicals(_this._lambdaLogicalIdsToVersion, lambdaSummaries);
|
||||
})
|
||||
.then(lambdaNamesToVersion => {
|
||||
//3) publishVersions
|
||||
return AWSUtils.lambdaPublishVersions(_this.Jaws._awsProfile, region, lambdaNamesToVersion);
|
||||
});
|
||||
})
|
||||
.then(versionedLambdas => {
|
||||
JawsCLI.log('Lambda VersionLambda: Successfully published following lambda versions to the requested regions:');
|
||||
JawsCLI.log(versionedLambdas);
|
||||
return versionedLambdas;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,7 +117,7 @@ class VersionLambda extends JawsPlugin {
|
||||
|
||||
// If stage exists, skip
|
||||
if (!this._stage) {
|
||||
stages = Object.keys(_this.JAWS._projectJson.stages);
|
||||
stages = Object.keys(_this.Jaws._projectJson.stages);
|
||||
|
||||
// If project only has 1 stage, skip prompt
|
||||
if (stages.length === 1) {
|
||||
@ -140,9 +140,9 @@ class VersionLambda extends JawsPlugin {
|
||||
}
|
||||
|
||||
return this.selectInput('VersionLambda: Choose a stage: ', choices, false)
|
||||
.then(results => {
|
||||
_this._stage = results[0].value;
|
||||
});
|
||||
.then(results => {
|
||||
_this._stage = results[0].value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,7 +159,7 @@ class VersionLambda extends JawsPlugin {
|
||||
//Deploy to all regions in stage
|
||||
|
||||
let stage = this._stage,
|
||||
projJson = this.JAWS._projectJson;
|
||||
projJson = this.Jaws._projectJson;
|
||||
|
||||
let regionConfigs = projJson.stages[stage],
|
||||
regions = regionConfigs.map(rCfg => {
|
||||
@ -179,12 +179,12 @@ class VersionLambda extends JawsPlugin {
|
||||
_setLambdaLogicalIds(lambdaPaths) {
|
||||
let _this = this;
|
||||
return JawsUtils.getFullLambdaPaths(process.cwd(), lambdaPaths)
|
||||
.then(fullAwsmJsonPaths => {
|
||||
_this._lambdaLogicalIdsToVersion = fullAwsmJsonPaths.map(alp => {
|
||||
let awsmJson = JawsUtils.readAndParseJsonSync(alp);
|
||||
return JawsUtils.getLambdaName(awsmJson);
|
||||
});
|
||||
.then(fullAwsmJsonPaths => {
|
||||
_this._lambdaLogicalIdsToVersion = fullAwsmJsonPaths.map(alp => {
|
||||
let awsmJson = JawsUtils.readAndParseJsonSync(alp);
|
||||
return JawsUtils.getLambdaName(awsmJson);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,5 +5,6 @@
|
||||
"author": "",
|
||||
"description": "",
|
||||
"domain": "",
|
||||
"stages": {}
|
||||
"stages": {},
|
||||
"plugins": []
|
||||
}
|
||||
@ -4,7 +4,7 @@
|
||||
"description": "A JAWS application",
|
||||
"author": "me",
|
||||
"license": "MIT",
|
||||
"private": false,
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/"
|
||||
|
||||
@ -9,10 +9,6 @@
|
||||
"Type": "String",
|
||||
"Default": "myapp.com"
|
||||
},
|
||||
"aaJawsBucket": {
|
||||
"Type": "String",
|
||||
"Default": "myapp.com"
|
||||
},
|
||||
"aaStage": {
|
||||
"Type": "String"
|
||||
},
|
||||
@ -139,7 +135,9 @@
|
||||
":",
|
||||
[
|
||||
"arn:aws:logs",
|
||||
{ "Ref" : "AWS::Region" },
|
||||
{
|
||||
"Ref": "AWS::Region"
|
||||
},
|
||||
"*:*"
|
||||
]
|
||||
]
|
||||
@ -189,7 +187,9 @@
|
||||
":",
|
||||
[
|
||||
"arn:aws:lambda",
|
||||
{ "Ref" : "AWS::Region" },
|
||||
{
|
||||
"Ref": "AWS::Region"
|
||||
},
|
||||
"*:*"
|
||||
]
|
||||
]
|
||||
@ -208,16 +208,6 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"JawsBucket" : {
|
||||
"Type" : "AWS::S3::Bucket",
|
||||
"Properties" : {
|
||||
"AccessControl" : "Private",
|
||||
"BucketName" : {
|
||||
"Ref": "aaJawsBucket"
|
||||
}
|
||||
},
|
||||
"DeletionPolicy" : "Retain"
|
||||
}
|
||||
},
|
||||
"Outputs": {
|
||||
|
||||
241
lib/utils/aws.js
241
lib/utils/aws.js
@ -53,8 +53,8 @@ module.exports.getConfigDir = function() {
|
||||
|
||||
let env = process.env;
|
||||
let home = env.HOME ||
|
||||
env.USERPROFILE ||
|
||||
(env.HOMEPATH ? ((env.HOMEDRIVE || 'C:/') + env.HOMEPATH) : null);
|
||||
env.USERPROFILE ||
|
||||
(env.HOMEPATH ? ((env.HOMEDRIVE || 'C:/') + env.HOMEPATH) : null);
|
||||
|
||||
if (!home) {
|
||||
throw new JawsError('Cant find homedir', JawsError.errorCodes.MISSING_HOMEDIR);
|
||||
@ -94,16 +94,16 @@ module.exports.profilesSet = function(awsProfile, awsRegion, accessKeyId, secret
|
||||
}
|
||||
|
||||
fs.appendFileSync(
|
||||
credsPath,
|
||||
`[${awsProfile}]
|
||||
credsPath,
|
||||
`[${awsProfile}]
|
||||
aws_access_key_id = ${accessKeyId.trim()}
|
||||
aws_secret_access_key = ${secretKey.trim()}\n`);
|
||||
|
||||
let profileNameForConfig = (awsProfile == 'default') ? 'default' : 'profile ' + awsProfile;
|
||||
|
||||
fs.appendFileSync(
|
||||
configPath,
|
||||
`[${profileNameForConfig}]
|
||||
configPath,
|
||||
`[${profileNameForConfig}]
|
||||
region = ${awsRegion}\n`);
|
||||
};
|
||||
|
||||
@ -152,8 +152,8 @@ exports.iamGetRole = function(awsProfile, awsRegion, roleName) {
|
||||
|
||||
if (error) {
|
||||
return reject(new JawsError(
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
} else {
|
||||
return resolve(data);
|
||||
}
|
||||
@ -190,8 +190,8 @@ exports.cfDescribeStacks = function(awsProfile, awsRegion, stackName) {
|
||||
|
||||
if (error) {
|
||||
return reject(new JawsError(
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
} else {
|
||||
return resolve(data);
|
||||
}
|
||||
@ -231,8 +231,8 @@ exports.cfDescribeStackResource = function(awsProfile, awsRegion, stackId, cfRes
|
||||
|
||||
if (error) {
|
||||
return reject(new JawsError(
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
} else {
|
||||
return resolve(data);
|
||||
}
|
||||
@ -296,40 +296,40 @@ exports.cfGetLambdaResourceSummaries = function(awsProfile, awsRegion, stackName
|
||||
|
||||
return new Promise((resolve, reject)=> {
|
||||
async.whilst(
|
||||
function() {
|
||||
return moreResources === true;
|
||||
},
|
||||
function(callback) {
|
||||
_this.cfListStackResources(awsProfile, awsRegion, stackName, nextStackToken)
|
||||
.then(function(lambdaCfResources) {
|
||||
if (lambdaCfResources.StackResourceSummaries) {
|
||||
lambdas = lambdas.concat(lambdaCfResources.StackResourceSummaries);
|
||||
}
|
||||
function() {
|
||||
return moreResources === true;
|
||||
},
|
||||
function(callback) {
|
||||
_this.cfListStackResources(awsProfile, awsRegion, stackName, nextStackToken)
|
||||
.then(function(lambdaCfResources) {
|
||||
if (lambdaCfResources.StackResourceSummaries) {
|
||||
lambdas = lambdas.concat(lambdaCfResources.StackResourceSummaries);
|
||||
}
|
||||
|
||||
// Check if more resources are available
|
||||
if (!lambdaCfResources.NextToken) {
|
||||
moreResources = false;
|
||||
} else {
|
||||
nextStackToken = lambdaCfResources.NextToken;
|
||||
}
|
||||
// Check if more resources are available
|
||||
if (!lambdaCfResources.NextToken) {
|
||||
moreResources = false;
|
||||
} else {
|
||||
nextStackToken = lambdaCfResources.NextToken;
|
||||
}
|
||||
|
||||
callback();
|
||||
})
|
||||
.catch(function(error) {
|
||||
JawsCli.log('Warning: JAWS could not find a deployed Cloudformation '
|
||||
+ 'template containing lambda functions.');
|
||||
console.log(error);
|
||||
moreResources = false;
|
||||
callback(error);
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(lambdas);
|
||||
}
|
||||
callback();
|
||||
})
|
||||
.catch(function(error) {
|
||||
JawsCli.log('Warning: JAWS could not find a deployed Cloudformation '
|
||||
+ 'template containing lambda functions.');
|
||||
console.log(error);
|
||||
moreResources = false;
|
||||
callback(error);
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(lambdas);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
@ -384,11 +384,11 @@ exports.lambdaPublishVersions = function(awsProfile, awsRegion, functionNames) {
|
||||
});
|
||||
|
||||
return Promise.all(deferreds)
|
||||
.then(data => {
|
||||
return data.map(d => {
|
||||
return {FunctionName: d.FunctionName, Version: d.Version, FunctionArn: d.FunctionArn};
|
||||
});
|
||||
.then(data => {
|
||||
return data.map(d => {
|
||||
return {FunctionName: d.FunctionName, Version: d.Version, FunctionArn: d.FunctionArn};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -419,9 +419,9 @@ exports.lambdaCreateAlias = function(awsProfile, awsRegion, functionName, functi
|
||||
};
|
||||
|
||||
return L.createAliasAsync(params)
|
||||
.then(d => {
|
||||
return {AliasArn: d.AliasArn, FunctionVersion: d.FunctionVersion};
|
||||
});
|
||||
.then(d => {
|
||||
return {AliasArn: d.AliasArn, FunctionVersion: d.FunctionVersion};
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -466,11 +466,11 @@ exports.cfGetLambdasStackTemplate = function(awsProfile, awsRegion, stage, projN
|
||||
}));
|
||||
|
||||
return CF.getTemplateAsync({
|
||||
StackName: _this.cfGetLambdasStackName(stage, projName)
|
||||
})
|
||||
.then(function(data) {
|
||||
return data.TemplateBody;
|
||||
});
|
||||
StackName: _this.cfGetLambdasStackName(stage, projName)
|
||||
})
|
||||
.then(function(data) {
|
||||
return data.TemplateBody;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -502,13 +502,13 @@ exports.putCfFile = function(awsProfile, projRootPath, awsRegion, bucketName, pr
|
||||
};
|
||||
|
||||
return this.putS3Object(awsProfile, awsRegion, params)
|
||||
.then(function() {
|
||||
//Really AWS - TemplateURL is an https:// URL. You force us to lookup endpt vs bucket/key attrs!?!? wtf not cool
|
||||
let s3 = new AWS.S3();
|
||||
.then(function() {
|
||||
//Really AWS - TemplateURL is an https:// URL. You force us to lookup endpt vs bucket/key attrs!?!? wtf not cool
|
||||
let s3 = new AWS.S3();
|
||||
|
||||
//Seriously, not cool...
|
||||
return 'https://' + s3.endpoint.hostname + `/${bucketName}/${key}`;
|
||||
})
|
||||
//Seriously, not cool...
|
||||
return 'https://' + s3.endpoint.hostname + `/${bucketName}/${key}`;
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
@ -550,10 +550,10 @@ exports.cfCreateLambdasStack = function(JAWS, stage, region, lambdaRoleArn) {
|
||||
};
|
||||
|
||||
return _this.putCfFile(awsProfile, projRootPath, region, bucketName, projName, stage, 'lambdas')
|
||||
.then(function(templateUrl) {
|
||||
params.TemplateURL = templateUrl;
|
||||
return CF.createStackAsync(params);
|
||||
});
|
||||
.then(function(templateUrl) {
|
||||
params.TemplateURL = templateUrl;
|
||||
return CF.createStackAsync(params);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -591,10 +591,10 @@ exports.cfUpdateLambdasStack = function(JAWS, stage, region, lambdaRoleArn) {
|
||||
};
|
||||
|
||||
return _this.putCfFile(awsProfile, projRootPath, region, bucketName, projName, stage, 'lambdas')
|
||||
.then(function(templateUrl) {
|
||||
params.TemplateURL = templateUrl;
|
||||
return CF.updateStackAsync(params);
|
||||
});
|
||||
.then(function(templateUrl) {
|
||||
params.TemplateURL = templateUrl;
|
||||
return CF.updateStackAsync(params);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -614,8 +614,7 @@ exports.cfCreateResourcesStack = function(awsProfile,
|
||||
projName,
|
||||
projStage,
|
||||
projDomain,
|
||||
projNotificationEmail,
|
||||
jawsBucket) {
|
||||
projNotificationEmail) {
|
||||
|
||||
let _this = this;
|
||||
|
||||
@ -643,10 +642,6 @@ exports.cfCreateResourcesStack = function(awsProfile,
|
||||
ParameterKey: 'aaStage',
|
||||
ParameterValue: projStage,
|
||||
UsePreviousValue: false,
|
||||
}, {
|
||||
ParameterKey: 'aaJawsBucket',
|
||||
ParameterValue: jawsBucket,
|
||||
UsePreviousValue: false,
|
||||
}, {
|
||||
ParameterKey: 'aaDataModelStage',
|
||||
ParameterValue: projStage,
|
||||
@ -707,10 +702,10 @@ exports.cfUpdateResourcesStack = function(JAWS, stage, region) {
|
||||
};
|
||||
|
||||
return _this.putCfFile(awsProfile, projRootPath, region, bucketName, projName, stage, 'resources')
|
||||
.then(function(templateUrl) {
|
||||
params.TemplateURL = templateUrl;
|
||||
return CF.updateStackAsync(params);
|
||||
});
|
||||
.then(function(templateUrl) {
|
||||
params.TemplateURL = templateUrl;
|
||||
return CF.updateStackAsync(params);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -746,31 +741,31 @@ exports.monitorCf = function(cfData, awsProfile, region, createOrUpdate, checkFr
|
||||
stackData = null;
|
||||
|
||||
async.whilst(
|
||||
function() {
|
||||
return stackStatus !== stackStatusComplete;
|
||||
},
|
||||
function() {
|
||||
return stackStatus !== stackStatusComplete;
|
||||
},
|
||||
|
||||
function(callback) {
|
||||
setTimeout(function() {
|
||||
_this.cfDescribeStacks(awsProfile, region, cfData.StackId)
|
||||
.then(function(data) {
|
||||
stackData = data;
|
||||
stackStatus = stackData.Stacks[0].StackStatus;
|
||||
function(callback) {
|
||||
setTimeout(function() {
|
||||
_this.cfDescribeStacks(awsProfile, region, cfData.StackId)
|
||||
.then(function(data) {
|
||||
stackData = data;
|
||||
stackStatus = stackData.Stacks[0].StackStatus;
|
||||
|
||||
if (!stackStatus || validStatuses.indexOf(stackStatus) === -1) {
|
||||
console.log((data.Stacks && data.Stacks.length ? data.Stacks[0] : data));
|
||||
return reject(new JawsError(
|
||||
`Something went wrong while ${createOrUpdate}ing your cloudformation`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
});
|
||||
}, checkFreq);
|
||||
},
|
||||
if (!stackStatus || validStatuses.indexOf(stackStatus) === -1) {
|
||||
console.log((data.Stacks && data.Stacks.length ? data.Stacks[0] : data));
|
||||
return reject(new JawsError(
|
||||
`Something went wrong while ${createOrUpdate}ing your cloudformation`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
});
|
||||
}, checkFreq);
|
||||
},
|
||||
|
||||
function() {
|
||||
return resolve(stackData.Stacks[0]);
|
||||
}
|
||||
function() {
|
||||
return resolve(stackData.Stacks[0]);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
@ -780,30 +775,30 @@ exports.monitorCf = function(cfData, awsProfile, region, createOrUpdate, checkFr
|
||||
* @param awsProfile
|
||||
* @param awsRegion
|
||||
* @param bucketName
|
||||
* @returns {*}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
exports.createBucket = function(awsProfile, awsRegion, bucketName) {
|
||||
this.configAWS(awsProfile, awsRegion);
|
||||
|
||||
let s3 = Promise.promisifyAll(new AWS.S3());
|
||||
|
||||
return s3.getBucketAclAsync({Bucket: bucketName})
|
||||
.then(function() {
|
||||
})
|
||||
.error(function(err) {
|
||||
if (err.code == 'AccessDenied') {
|
||||
throw new JawsError(
|
||||
`Bucket ${bucketName} already exists and you do not have permissions to use it`,
|
||||
JawsError.errorCodes.ACCESS_DENIED
|
||||
);
|
||||
}
|
||||
.then(function() {
|
||||
//we are good, bucket already exists and we own it!
|
||||
})
|
||||
.error(function(err) {
|
||||
if (err.code == 'AccessDenied') {
|
||||
throw new JawsError(
|
||||
`Bucket ${bucketName} already exists and you do not have permissions to use it`,
|
||||
JawsError.errorCodes.ACCESS_DENIED
|
||||
);
|
||||
}
|
||||
|
||||
return s3.createBucketAsync({
|
||||
Bucket: bucketName,
|
||||
ACL: 'private',
|
||||
});
|
||||
return s3.createBucketAsync({
|
||||
Bucket: bucketName,
|
||||
ACL: 'private',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -900,9 +895,9 @@ exports.putLambdaZip = function(awsProfile, awsRegion, bucketName, projectName,
|
||||
utils.jawsDebug(`lambda zip s3 key: ${key}`);
|
||||
|
||||
return this.putS3Object(awsProfile, awsRegion, params)
|
||||
.then(function() {
|
||||
return key;
|
||||
});
|
||||
.then(function() {
|
||||
return key;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -931,8 +926,8 @@ exports.cwGetLogStreams = function(logGroupName, limit) {
|
||||
|
||||
if (error) {
|
||||
return reject(new JawsError(
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
} else {
|
||||
return resolve(data);
|
||||
}
|
||||
@ -963,8 +958,8 @@ exports.cwGetStreamEvents = function(logGroupName, logStreamName) {
|
||||
cwLogs.getLogEvents(params, function(err, data) {
|
||||
if (error) {
|
||||
return reject(new JawsError(
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
error.message,
|
||||
JawsError.errorCodes.UNKNOWN));
|
||||
} else {
|
||||
return resolve(data);
|
||||
}
|
||||
|
||||
@ -4,16 +4,16 @@
|
||||
* JAWS Services: CLI
|
||||
*/
|
||||
|
||||
let Promise = require('bluebird'),
|
||||
prompt = require('prompt'),
|
||||
path = require('path'),
|
||||
os = require('os'),
|
||||
let Promise = require('bluebird'),
|
||||
prompt = require('prompt'),
|
||||
path = require('path'),
|
||||
os = require('os'),
|
||||
JawsError = require('../jaws-error/index'),
|
||||
utils = require('../utils'),
|
||||
fs = require('fs'),
|
||||
chalk = require('chalk'),
|
||||
Spinner = require('cli-spinner').Spinner,
|
||||
keypress = require('keypress');
|
||||
utils = require('../utils'),
|
||||
fs = require('fs'),
|
||||
chalk = require('chalk'),
|
||||
Spinner = require('cli-spinner').Spinner,
|
||||
keypress = require('keypress');
|
||||
|
||||
Promise.promisifyAll(fs);
|
||||
Promise.promisifyAll(prompt);
|
||||
@ -21,16 +21,17 @@ Promise.promisifyAll(prompt);
|
||||
/**
|
||||
* ASCII
|
||||
*/
|
||||
exports.ascii = function() {
|
||||
exports.asciiGreeting = function() {
|
||||
let ver = require('../../package.json').version;
|
||||
|
||||
let art = '';
|
||||
art = art + ' ____ _____ __ __ _________ ' + os.EOL;
|
||||
art = art + ' | | / _ \\/ \\ / \\/ _____/ ' + os.EOL;
|
||||
art = art + ' | |/ /_\\ \\ \\/\\/ /\\_____ \\ ' + os.EOL;
|
||||
art = art + ' /\\__| / | \\ / / \\ ' + os.EOL;
|
||||
art = art + ' \\________\\____|__ /\\__/\\__/ /_________/ v1 (BETA)' + os.EOL;
|
||||
art = art + '' + os.EOL;
|
||||
art = art + ' *** The Server-Less Framework *** ' + os.EOL;
|
||||
art = art + ' ____ _____ __ __ _________ ' + os.EOL;
|
||||
art = art + ' | | / _ \\/ \\ / \\/ _____/ ' + os.EOL;
|
||||
art = art + ' | |/ /_\\ \\ \\/\\/ /\\_____ \\ ' + os.EOL;
|
||||
art = art + ' /\\__| / | \\ / / \\ ' + os.EOL;
|
||||
art = art + ' \\________\\____|__ /\\__/\\__/ /_________/ v' + ver + os.EOL;
|
||||
art = art + '' + os.EOL;
|
||||
art = art + ' *** The Server-Less Framework *** ' + os.EOL;
|
||||
|
||||
console.log(chalk.yellow(art));
|
||||
};
|
||||
@ -50,11 +51,11 @@ exports.spinner = function(message) {
|
||||
|
||||
// Non-interactive spinner object
|
||||
spinner = {
|
||||
start: function (message) {
|
||||
start: function(message) {
|
||||
message = message || 'Loading... ';
|
||||
process.stdout.write(`JAWS: ${message}`);
|
||||
},
|
||||
stop: function (message) {
|
||||
stop: function(message) {
|
||||
|
||||
// Because of how spinner is used with normal library
|
||||
// we do a small hack and still allow for setting message
|
||||
@ -85,7 +86,7 @@ exports.log = function(message) {
|
||||
exports.prompt = function() {
|
||||
prompt.start();
|
||||
prompt.delimiter = '';
|
||||
prompt.message = 'JAWS: ';
|
||||
prompt.message = 'JAWS: ';
|
||||
return prompt;
|
||||
};
|
||||
|
||||
@ -138,7 +139,7 @@ Select._render = function() {
|
||||
for (let i = 0; i < _this.state.choices.length; i++) {
|
||||
|
||||
let choice = _this.state.choices[i],
|
||||
line = '';
|
||||
line = '';
|
||||
|
||||
// Increment line count
|
||||
_this.state.lines++;
|
||||
@ -216,7 +217,7 @@ exports.select = function(message, choices, multi, doneLabel) {
|
||||
|
||||
if (!_this.isInteractive()) {
|
||||
throw new JawsError('You must specify all necessary options when in a non-interactive mode.',
|
||||
JawsError.errorCodes.UNKNOWN);
|
||||
JawsError.errorCodes.UNKNOWN);
|
||||
}
|
||||
|
||||
// Set keypress listener, if not set
|
||||
@ -264,7 +265,7 @@ exports.select = function(message, choices, multi, doneLabel) {
|
||||
|
||||
// Check if "done" option
|
||||
if (Select.state.choices[Select.state.index - 1].action
|
||||
&& Select.state.choices[Select.state.index - 1].action.toLowerCase() === 'done') {
|
||||
&& Select.state.choices[Select.state.index - 1].action.toLowerCase() === 'done') {
|
||||
process.stdin.removeListener('keypress', keypressHandler);
|
||||
return Select._close();
|
||||
} else {
|
||||
@ -293,21 +294,21 @@ exports.select = function(message, choices, multi, doneLabel) {
|
||||
|
||||
// Update CheckList
|
||||
Select.state = {
|
||||
choices: choices,
|
||||
index: (choices[0] && choices[0].spacer) ? 2 : 1,
|
||||
lines: 0,
|
||||
multi: multi,
|
||||
choices: choices,
|
||||
index: (choices[0] && choices[0].spacer) ? 2 : 1,
|
||||
lines: 0,
|
||||
multi: multi,
|
||||
doneLabel: doneLabel ? doneLabel : 'Done',
|
||||
};
|
||||
|
||||
// Add Done and Cancel to choices
|
||||
if (Select.state.multi) {
|
||||
Select.state.choices.push(
|
||||
{spacer: '- - - - -'},
|
||||
{
|
||||
action: 'Done',
|
||||
label: Select.state.doneLabel,
|
||||
});
|
||||
{spacer: '- - - - -'},
|
||||
{
|
||||
action: 'Done',
|
||||
label: Select.state.doneLabel,
|
||||
});
|
||||
}
|
||||
|
||||
// Log Message
|
||||
|
||||
@ -11,7 +11,8 @@ let Promise = require('bluebird'),
|
||||
readdirp = require('readdirp'),
|
||||
JawsError = require('../jaws-error'),
|
||||
fs = require('fs'),
|
||||
mkdirpAsync = require('mkdirp-then');
|
||||
mkdirpAsync = require('mkdirp-then'),
|
||||
shortid = require('shortid');
|
||||
|
||||
Promise.promisifyAll(fs);
|
||||
|
||||
@ -37,26 +38,26 @@ exports.findAllAwsmPathsOfType = function(startPath, type) {
|
||||
}
|
||||
|
||||
return _this.readRecursively(startPath, '*awsm.json')
|
||||
.then(function(jsonPaths) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
.then(function(jsonPaths) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
let jawsPathsOfType = [];
|
||||
let jawsPathsOfType = [];
|
||||
|
||||
// Check each file to ensure it is a lambda
|
||||
async.eachLimit(jsonPaths, 10, function(jsonPath, cb) {
|
||||
let lambdaJawsPath = path.join(startPath, jsonPath),
|
||||
json = require(lambdaJawsPath);
|
||||
// Check each file to ensure it is a lambda
|
||||
async.eachLimit(jsonPaths, 10, function(jsonPath, cb) {
|
||||
let lambdaJawsPath = path.join(startPath, jsonPath),
|
||||
json = require(lambdaJawsPath);
|
||||
|
||||
if (typeof json[jawsJsonAttr] !== 'undefined') jawsPathsOfType.push(lambdaJawsPath);
|
||||
return cb();
|
||||
},
|
||||
if (typeof json[jawsJsonAttr] !== 'undefined') jawsPathsOfType.push(lambdaJawsPath);
|
||||
return cb();
|
||||
},
|
||||
|
||||
function(error) {
|
||||
if (error) reject(error);
|
||||
resolve(jawsPathsOfType);
|
||||
});
|
||||
});
|
||||
function(error) {
|
||||
if (error) reject(error);
|
||||
resolve(jawsPathsOfType);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -102,15 +103,15 @@ exports.findProjectRootPath = function(startDir) {
|
||||
|
||||
exports.execute = function(promise) {
|
||||
promise
|
||||
.catch(JawsError, function(e) {
|
||||
console.error(e);
|
||||
process.exit(e.messageId);
|
||||
})
|
||||
.error(function(e) {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.done();
|
||||
.catch(JawsError, function(e) {
|
||||
console.error(e);
|
||||
process.exit(e.messageId);
|
||||
})
|
||||
.error(function(e) {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.done();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -128,15 +129,15 @@ exports.readRecursively = function(path, filter) {
|
||||
root: path,
|
||||
fileFilter: filter,
|
||||
})
|
||||
.on('data', function(entry) {
|
||||
files.push(entry.path);
|
||||
})
|
||||
.on('error', function(error) {
|
||||
reject(error);
|
||||
})
|
||||
.on('end', function() {
|
||||
resolve(files);
|
||||
});
|
||||
.on('data', function(entry) {
|
||||
files.push(entry.path);
|
||||
})
|
||||
.on('error', function(error) {
|
||||
reject(error);
|
||||
})
|
||||
.on('end', function() {
|
||||
resolve(files);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@ -171,24 +172,24 @@ exports.findAllEnvletsForAwsm = function(projectRootPath, modName) {
|
||||
let _this = this;
|
||||
|
||||
return this.findAllAwsmPathsOfType(path.join(projectRootPath, 'aws_modules', modName), 'lambda')
|
||||
.then(function(awsmJsonPaths) {
|
||||
let envletKeys = [];
|
||||
.then(function(awsmJsonPaths) {
|
||||
let envletKeys = [];
|
||||
|
||||
awsmJsonPaths.forEach(function(awsmJsonPath) {
|
||||
let awsmJson = _this.readAndParseJsonSync(awsmJsonPath);
|
||||
awsmJsonPaths.forEach(function(awsmJsonPath) {
|
||||
let awsmJson = _this.readAndParseJsonSync(awsmJsonPath);
|
||||
|
||||
//TODO: change to es6 set...
|
||||
if (awsmJson.lambda && awsmJson.lambda.envlets) {
|
||||
awsmJson.lambda.envlets.forEach(function(envlet) {
|
||||
if (envletKeys.indexOf(envlet) == -1) {
|
||||
envletKeys.push(envlet);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return envletKeys;
|
||||
//TODO: change to es6 set...
|
||||
if (awsmJson.lambda && awsmJson.lambda.envlets) {
|
||||
awsmJson.lambda.envlets.forEach(function(envlet) {
|
||||
if (envletKeys.indexOf(envlet) == -1) {
|
||||
envletKeys.push(envlet);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return envletKeys;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -199,11 +200,11 @@ exports.findAllEnvletsForAwsm = function(projectRootPath, modName) {
|
||||
*/
|
||||
exports.findAllAwsmJsons = function(startPath) {
|
||||
return this.readRecursively(startPath, '*awsm.json')
|
||||
.then(function(jsonPaths) {
|
||||
return jsonPaths.map(function(jsonPath) {
|
||||
return path.resolve(path.join(startPath, jsonPath));
|
||||
});
|
||||
.then(function(jsonPaths) {
|
||||
return jsonPaths.map(function(jsonPath) {
|
||||
return path.resolve(path.join(startPath, jsonPath));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -250,9 +251,13 @@ exports.writeFile = function(filePath, contents) {
|
||||
}
|
||||
|
||||
return mkdirpAsync(path.dirname(filePath))
|
||||
.then(function() {
|
||||
return fs.writeFileAsync(filePath, contents);
|
||||
});
|
||||
.then(function() {
|
||||
return fs.writeFileAsync(filePath, contents);
|
||||
});
|
||||
};
|
||||
|
||||
exports.generateShortId = function(maxLen) {
|
||||
return shortid.generate().replace(/\W+/g, '').substring(0, maxLen).replace(/[_-]/g, '');
|
||||
};
|
||||
|
||||
/**
|
||||
@ -294,16 +299,16 @@ exports.getAllLambdaNames = function(projectRootPath) {
|
||||
lambdaNames = [];
|
||||
|
||||
return this.findAllLambdas(projectRootPath)
|
||||
.then(function(lambdaAwsmPaths) {
|
||||
lambdaAwsmPaths.forEach(function(ljp) {
|
||||
let awsm = _this.readAndParseJsonSync(ljp),
|
||||
lambdaName = _this.getLambdaName(awsm);
|
||||
.then(function(lambdaAwsmPaths) {
|
||||
lambdaAwsmPaths.forEach(function(ljp) {
|
||||
let awsm = _this.readAndParseJsonSync(ljp),
|
||||
lambdaName = _this.getLambdaName(awsm);
|
||||
|
||||
lambdaNames.push(lambdaName);
|
||||
});
|
||||
|
||||
return lambdaNames;
|
||||
lambdaNames.push(lambdaName);
|
||||
});
|
||||
|
||||
return lambdaNames;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -371,7 +376,7 @@ exports.npmInstall = function(dir) {
|
||||
process.chdir(cwd);
|
||||
};
|
||||
|
||||
exports.generateResourcesCf = function(projRootPath, projName, projDomain, stage, region, notificationEmail, jawsBucket) {
|
||||
exports.generateResourcesCf = function(projRootPath, projName, projDomain, stage, region, notificationEmail) {
|
||||
|
||||
let cfTemplate = require('../templates/resources-cf');
|
||||
cfTemplate.Parameters.aaProjectName.Default = projName;
|
||||
@ -379,13 +384,12 @@ exports.generateResourcesCf = function(projRootPath, projName, projDomain, stage
|
||||
cfTemplate.Parameters.aaProjectDomain.Default = projDomain;
|
||||
cfTemplate.Parameters.aaStage.Default = stage;
|
||||
cfTemplate.Parameters.aaDataModelStage.Default = stage; //to simplify bootstrap use same stage
|
||||
cfTemplate.Parameters.aaJawsBucket.Default = jawsBucket;
|
||||
cfTemplate.Parameters.aaNotficationEmail.Default = notificationEmail;
|
||||
cfTemplate.Description = projName + " resources";
|
||||
|
||||
return this.writeFile(
|
||||
path.join(projRootPath, 'cloudformation', stage, region, 'resources-cf.json'),
|
||||
JSON.stringify(cfTemplate, null, 2)
|
||||
path.join(projRootPath, 'cloudformation', stage, region, 'resources-cf.json'),
|
||||
JSON.stringify(cfTemplate, null, 2)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user