utils: refactor common utils for simplicity

This commit is contained in:
Austen Collins 2015-11-09 21:12:17 -08:00
parent d50e70c451
commit 00dbf8a41e
7 changed files with 302 additions and 211 deletions

View File

@ -68,13 +68,30 @@ class EndpointDeploy extends JawsPlugin {
* @param region
* @returns {Promise.<T>}
*/
endpointDeploy(stage, region, noExeCf) {
let _this = this;
this._stage = stage;
this._region = region;
this._noExeCf = (noExeCf == true || noExeCf == 'true');
this._endpointAwsmPaths = Array.prototype.slice.call(arguments, 3);
let _this = this;
this._stage = stage;
this._region = region;
this._noExeCf = (noExeCf == true || noExeCf == 'true');
this._servicePaths = Array.prototype.slice.call(arguments, 3);
// Resolve full paths for services
if (this._servicePaths) {
this._servicePaths = JawsUtils.getServices(
_this.Jaws._projectRootPath,
'endpoint',
this._servicePaths
);
}
return console.log(this._servicePaths);
// TODO: If no servicePaths, check if interactive, check if in a service, deploy that, or throw error
return BbPromise.try(function() {})
.bind(_this)
@ -153,6 +170,7 @@ class EndpointDeploy extends JawsPlugin {
}
_deployRegions() {
let _this = this;
return BbPromise.try(function() {
@ -162,10 +180,12 @@ class EndpointDeploy extends JawsPlugin {
// Deploy endpoints to each region
_this._regionJson = JawsUtils.getProjRegionConfigForStage(_this.Jaws._projectJson, _this._stage, region);
return _this._fetchDeployedLambdas()
.bind(_this)
.then(_this._findOrCreateApi);
.then(_this._findOrCreateApi)
.then(_this._getApiResources)
.then(_this._buildEndpoints);
});
}
@ -198,11 +218,6 @@ class EndpointDeploy extends JawsPlugin {
let _this = this;
// If missing restApiId, check if regional REST API exists in another stage
if (!_this._regionJson.restApiId) {
_this._regionJson.restApiId = JawsUtils.findRegionalApi(_this.Jaws._projectJson, _this._region);
}
// Check Project's jaws.json for restApiId, otherwise create an api
if (_this._regionJson.restApiId) {
@ -220,25 +235,115 @@ class EndpointDeploy extends JawsPlugin {
});
} else {
// Create regional REST API
// List all REST APIs
return AwsApiGateway.getRestApis()
.then(function(response) {
let apiName = _this.Jaws._projectJson.name;
apiName = apiName.substr(0, 1023); // keep the name length below the limits
// Find REST API w/ same name as project
for (let i = 0; i < response.items.length;i++) {
if (response.items[i].name === _this.Jaws._projectJson.name) {
_this._restApiId = response.items[i].id;
return AwsApiGateway.createRestApi(apiName,
_this.Jaws._projectJson.description ? _this.Jaws._projectJson.description : 'A REST API for a JAWS project.'
).then(function(response) {
// Save to jaws.json
JawsUtils.saveRegionalApi(_this.Jaws._projectJson, _this._region, _this._restApiId, _this.Jaws._projectRootPath);
break;
}
}
_this._restApiId = response.id;
JawsCLI.log(
'Endpoint Deployer: "'
+ _this._stage + ' - '
+ _this._regionJson.region
+ '": created a new REST API on AWS API Gateway with ID: '
+ response.id);
});
// If no REST API found, create one
if (!_this._restApiId) {
let apiName = _this.Jaws._projectJson.name;
apiName = apiName.substr(0, 1023); // keep the name length below the limits
return AwsApiGateway.createRestApi(
apiName,
_this.Jaws._projectJson.description ? _this.Jaws._projectJson.description : 'A REST API for a JAWS project.'
).then(function (response) {
_this._restApiId = response.id;
// Save to jaws.json
JawsUtils.saveRegionalApi(_this.Jaws._projectJson, _this._region, _this._restApiId, _this.Jaws._projectRootPath);
JawsCLI.log(
'Endpoint Deployer: "'
+ _this._stage + ' - '
+ _this._regionJson.region
+ '": created a new REST API on AWS API Gateway with ID: '
+ response.id);
});
}
});
}
}
/**
* Get API Resources
* @returns {Promise}
* @private
*/
_getApiResources() {
let _this = this;
// List all Resources for this REST API
return AwsApiGateway.getResources(_this._restApiId)
.then(function(response) {
_this._resources = response.items;
// Get Parent Resource ID
for (let i = 0; i < _this._resources.length; i++) {
if (_this._resources[i].path === '/') {
_this._parentResourceId = _this._resources[i].id;
}
}
JawsCLI.log(
'Endpoint Deployer: "'
+ _this._stage + ' - '
+ _this._regionJson.region
+ '": found '
+ _this._resources.length
+ ' existing resources on API Gateway');
});
}
/**
* Build Endpoints
* @returns {Promise}
* @private
*/
_buildEndpoints() {
let _this = this;
return BbPromise.try(function() {
return _this._servicePaths;
}).each(function(servicePath) {
return console.log(service);
return _this._createEndpointResources(endpoint)
.bind(_this)
.then(_this._createEndpointMethod)
.then(_this._createEndpointIntegration)
.then(_this._manageLambdaAccessPolicy)
.then(_this._createEndpointMethodResponses)
.then(_this._createEndpointMethodIntegResponses)
.then(function() {
// Clean-up hack
// TODO figure out how "apig" temp property is being written to the awsm's json and remove that
if (endpoint.apiGateway.apig) delete endpoint.apiGateway.apig;
});
});
}
}
module.exports = EndpointDeploy;

View File

@ -192,7 +192,7 @@ usage: jaws lambda alias <version|GREATEST> <aliasName>`,
*/
_setLambdaLogicalIds() {
let _this = this;
return JawsUtils.getFullLambdaPaths(process.cwd(), []) //leaving here for to be created GREATEST and 'ALL' option
return JawsUtils.getFullServicePaths(process.cwd(), []) //leaving here for to be created GREATEST and 'ALL' option
.then(fullAwsmJsonPaths => {
_this._lambdaLogicalIdsToAlias = fullAwsmJsonPaths.map(alp => {
let awsmJson = JawsUtils.readAndParseJsonSync(alp);

View File

@ -750,7 +750,7 @@ ex:
*/
_setLambdaAwsmPaths(lambdaPaths) {
let _this = this;
return JawsUtils.resolveLambdaPaths(process.cwd(), this.Jaws._projectRootPath, lambdaPaths)
return JawsUtils.resolveServicePaths(process.cwd(), this.Jaws._projectRootPath, lambdaPaths)
.then(fullAwsmJsonPaths => {
_this._lambdaAwsmPathsToDeploy = fullAwsmJsonPaths;
});

View File

@ -182,7 +182,7 @@ ex:
*/
_setLambdaLogicalIds(lambdaPaths) {
let _this = this;
return JawsUtils.resolveLambdaPaths(process.cwd(), this.Jaws._projectRootPath, lambdaPaths)
return JawsUtils.resolveServicePaths(process.cwd(), this.Jaws._projectRootPath, lambdaPaths)
.then(fullAwsmJsonPaths => {
_this._lambdaLogicalIdsToVersion = fullAwsmJsonPaths.map(alp => {
let awsmJson = JawsUtils.readAndParseJsonSync(alp);

View File

@ -31,3 +31,32 @@ module.exports.createRestApi = function(name, description) {
return ApiGateway.createRestApiAsync(params);
};
/**
* Get REST APIs
*/
module.exports.getRestApis = function() {
var params = {
limit: 500,
//position:
};
return ApiGateway.getRestApisAsync(params);
};
/**
* Get Resources
*/
module.exports.getResources = function(restApiId) {
var params = {
restApiId: restApiId,
limit: 500,
//position:
};
return ApiGateway.getResourcesAsync(params);
};

View File

@ -18,81 +18,13 @@ let Promise = require('bluebird'),
Promise.promisifyAll(fs);
/**
* Find all lambda.awsm.json paths of given type
*
* @param startPath
* @param type type lambda|endpoint
* @returns {Promise.<Array>} list of full paths tho lambda.awsm.json's
*/
exports.findAllAwsmPathsOfType = function(startPath, type) {
let _this = this,
jawsJsonAttr;
switch (type) {
case 'lambda':
jawsJsonAttr = 'lambda';
break;
case 'endpoint':
jawsJsonAttr = 'apiGateway';
break;
default:
return Promise.reject(new JawsError(`Invalid type ${type}`, JawsError.errorCodes.UNKNOWN));
break;
}
return _this.readRecursively(startPath, '*lambda.awsm.json')
.then(function(jsonPaths) {
_this.jawsDebug('lambda.awsm.json paths found: ', jsonPaths);
return new Promise(function(resolve, reject) {
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 = _this.readAndParseJsonSync(lambdaJawsPath);
if (typeof json.cloudFormation[jawsJsonAttr] !== 'undefined') jawsPathsOfType.push(lambdaJawsPath);
return cb();
},
function(error) {
if (error) reject(error);
_this.jawsDebug('lambda.awsm.json FULL paths found: ', jawsPathsOfType);
let s = new Set(jawsPathsOfType);
resolve(Array.from(s));
});
});
});
};
/**
* Given a list of paths to lambda dirs, will resolve to abs path (ex: ~,./).
* If lambdaPaths[0] == 'all' will find all lambda paths
* If lambdaPaths is empty or not set, will use lambda at cwd
*
* @param cwd
* @param projectRootPath
* @param lambdaPaths Array
* @returns {Promise.<Array>} list of full paths to lambda.awsm.json files that are type lambda
*/
exports.resolveLambdaPaths = function(cwd, projectRootPath, lambdaPaths) {
if (lambdaPaths[0] && lambdaPaths[0].toLowerCase() == 'all') {
this.jawsDebug('all lambda paths specified, searching..');
return this.findAllLambdas(projectRootPath);
} else {
return this.getFullLambdaPaths(cwd, lambdaPaths);
}
};
/**
* Find project root path
*
* @param startDir
* @returns {*}
*/
exports.findProjectRootPath = function(startDir) {
let _this = this;
@ -131,16 +63,16 @@ exports.findProjectRootPath = function(startDir) {
exports.execute = function(promise) {
promise
.catch(JawsError, function(e) {
//console.error(e);
throw e;
process.exit(e.messageId);
})
.error(function(e) {
console.error(e);
process.exit(1);
})
.done();
.catch(JawsError, function(e) {
//console.error(e);
throw e;
process.exit(e.messageId);
})
.error(function(e) {
console.error(e);
process.exit(1);
})
.done();
};
/**
@ -158,36 +90,95 @@ 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);
});
});
};
/**
* Find all dirs that are lambdas
* Get Services
*
* @param projectRootPath
* @returns {Promise.<Array>} list of full paths to lambda.awsm.json files that are type lambda
* @param baseDir
* @param type
* @param servicePaths
* @returns {*}
*/
exports.findAllLambdas = function(projectRootPath) {
return this.findAllAwsmPathsOfType(projectRootPath, 'lambda');
};
/**
* Find all dirs that are endpoints
*
* @param projectRootPath
* @returns {Promise.<Array>} list of full paths to awsm.json files that are type endpoint
*/
exports.findAllEndpoints = function(projectRootPath) {
return this.findAllAwsmPathsOfType(projectRootPath, 'endpoint');
exports.getServices = function(baseDir, type, servicePaths) {
let _this = this,
resolvedPaths = [];
// Get services by service paths
if (servicePaths) {
for (let servicePath of servicePaths) {
let tempPath = '';
servicePath = expandHomeDir(servicePath);
if (servicePath.indexOf('/') == 0) {
tempPath = path.join(baseDir, servicePath, 'lambda.awsm.json');
} else {
tempPath = path.resolve(baseDir, servicePath, './lambda.awsm.json');
}
resolvedPaths.push(tempPath);
}
resolvedPaths.forEach(p => {
if (!_this.fileExistsSync(p)) {
throw new JawsError(`Invalid service path ${p}`, JawsError.errorCodes.INVALID_RESOURCE_NAME);
}
});
return Promise.resolve(resolvedPaths);
}
// Get services by base directory
if (!servicePaths) {
return _this.readRecursively(baseDir, '*lambda.awsm.json')
.then(function (servicePaths) {
_this.jawsDebug('lambda.awsm.json paths found: ', servicePaths);
return new Promise(function (resolve, reject) {
let resolvedPaths = [];
// Check each file to ensure it is a lambda
async.eachLimit(servicePaths, 10, function (servicePath, cb) {
servicePath = path.join(baseDir, servicePath);
let serviceJson = _this.readAndParseJsonSync(servicePath);
if (type) {
if (typeof serviceJson.cloudFormation[type] !== 'undefined') resolvedPaths.push(servicePath);
} else {
resolvedPaths.push(servicePath);
}
return cb();
}, function (error) {
if (error) reject(error);
_this.jawsDebug('lambda.awsm.json FULL paths found: ', resolvedPaths);
let s = new Set(resolvedPaths);
resolve(Array.from(s));
});
});
});
}
};
/**
@ -200,25 +191,25 @@ exports.findAllEndpoints = function(projectRootPath) {
exports.findAllEnvletsForAwsm = function(projectRootPath, modName) {
let _this = this;
return this.findAllAwsmPathsOfType(path.join(projectRootPath, 'aws_modules', modName), 'lambda')
.then(function(awsmJsonPaths) {
let envletKeys = [];
return this.getServices(path.join(projectRootPath, 'aws_modules', modName), 'lambda')
.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);
}
});
}
//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;
});
return envletKeys;
});
};
/**
@ -229,53 +220,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));
});
});
});
};
/**
*
* @param baseDir typically CWD
* @param lambdaPaths <Array> optional abs or rel (to baseDir) paths to lambda dirs. If ommitted returns lambda at baseDir
* @returns {Promise.<Array>}
*/
exports.getFullLambdaPaths = function(baseDir, lambdaPaths) {
let _this = this,
fullPaths = [];
if (!lambdaPaths || lambdaPaths.length == 0) { //getting lambda at CWD
let awsmPath = path.join(process.cwd(), 'lambda.awsm.json');
fullPaths.push(awsmPath);
}
for (let lambdaPath of lambdaPaths) {
let awsmPath = '';
lambdaPath = expandHomeDir(lambdaPath);
if (lambdaPath.indexOf('/') == 0) {
awsmPath = path.join(lambdaPath, 'lambda.awsm.json');
} else {
awsmPath = path.resolve(baseDir, lambdaPath, './lambda.awsm.json');
}
fullPaths.push(awsmPath);
}
fullPaths.forEach(p => {
if (!_this.fileExistsSync(p)) {
throw new JawsError(`Invalid lambda path ${p}`, JawsError.errorCodes.INVALID_RESOURCE_NAME);
}
});
this.jawsDebug('got full lambda paths:', fullPaths);
let s = new Set(fullPaths);
return Promise.resolve(Array.from(s));
};
/**
@ -293,9 +242,9 @@ 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) {
@ -340,17 +289,17 @@ exports.getAllLambdaNames = function(projectRootPath) {
let _this = this,
lambdaNames = [];
return this.findAllLambdas(projectRootPath)
.then(function(lambdaAwsmPaths) {
lambdaAwsmPaths.forEach(function(ljp) {
let awsm = _this.readAndParseJsonSync(ljp),
lambdaName = _this.getLambdaName(awsm);
return this.getServices(projectRootPath, 'lambda')
.then(function(lambdaAwsmPaths) {
lambdaAwsmPaths.forEach(function(ljp) {
let awsm = _this.readAndParseJsonSync(ljp),
lambdaName = _this.getLambdaName(awsm);
lambdaNames.push(lambdaName);
lambdaNames.push(lambdaName);
});
return lambdaNames;
});
return lambdaNames;
});
};
/**
@ -432,8 +381,8 @@ exports.generateResourcesCf = function(projRootPath, projName, projDomain, stage
cfTemplate.Description = projName + ' resources';
return this.writeFile(
path.join(projRootPath, 'cloudformation', 'resources-cf.json'),
JSON.stringify(cfTemplate, null, 2)
path.join(projRootPath, 'cloudformation', 'resources-cf.json'),
JSON.stringify(cfTemplate, null, 2)
);
};
@ -452,8 +401,8 @@ exports.addStageToResourcesCf = function(projRootPath, stage) {
cfTemplate.Parameters.aaDataModelStage.AllowedValues.push(stage);
return this.writeFile(
projResoucesCfPath,
JSON.stringify(cfTemplate, null, 2)
projResoucesCfPath,
JSON.stringify(cfTemplate, null, 2)
);
};
@ -518,7 +467,8 @@ exports.findRegionalApi = function(projectJawsJson, regionName) {
*/
exports.saveRegionalApi = function(projectJawsJson, regionName, restApiId, rootPath) {
for (stages of Object.keys(projectJawsJson.stages)) {
for (let stages of Object.keys(projectJawsJson.stages)) {
for (let i = 0; i < stages.length; i++) {
if (stages[i].region === regionName) {
stages[i].restApiId = restApiId;

View File

@ -20,9 +20,11 @@ describe('Test action: Endpoint Deploy', function() {
testUtils.createTestProject(config)
.then(projPath => {
process.chdir(projPath);
Jaws = new JAWS({
interactive: false,
});
done();
});
});
@ -36,7 +38,12 @@ describe('Test action: Endpoint Deploy', function() {
it('Endpoint Deploy', function(done) {
this.timeout(0);
Jaws.actions.endpointDeploy(config.stage, config.region, config.noExecuteCf)
Jaws.actions.endpointDeploy(
config.stage,
config.region,
config.noExecuteCf,
'aws_modules/users/create'
)
.then(function() {
done();
})