deepify
Version:
DEEP Development Tools
390 lines (336 loc) • 10.4 kB
JavaScript
/**
* Created by CCristi on 5/31/16.
* @todo: move into '/lib/Helpers/' folder when get rid of uglifyjs
*/
;
let AbstractService = require('deep-package-manager').Provisioning_Service_AbstractService;
let CognitoIdentityProviderService = require('deep-package-manager')
.Provisioning_Service_CognitoIdentityProviderService;
let S3Service = require('deep-package-manager').Provisioning_Service_S3Service;
let DeployConfig = require('deep-package-manager').Property_DeployConfig;
let co = require('co');
let os = require('os');
module.exports = class ApplicationFormatter {
/**
* @param {Property_Instance} property
*/
constructor(property) {
this._namingCache = {};
this._property = property;
}
/**
* @param {Object} result
* @param {Number} levelsFlags
* @param {String[]|null} regions
* @returns {Promise}
*/
format(result, levelsFlags, regions = null) {
let formattedResult = {};
return co(function* () {
for (let region in result) {
if (!result.hasOwnProperty(region) || (regions && regions.indexOf(region) === -1)) {
continue;
}
let regionResources = result[region].resources;
for (let service in regionResources) {
if (!regionResources.hasOwnProperty(service)) {
continue;
}
let serviceApps = regionResources[service];
for (let appHash in serviceApps) {
if (!serviceApps.hasOwnProperty(appHash)) {
continue;
}
let resources = serviceApps[appHash];
for (let resourceName in resources) {
if (!resources.hasOwnProperty(resourceName)) {
continue;
}
let resourceData = resources[resourceName];
// @todo: display app name for each app hash
// let appName = yield this._resolveAppName(service, resourceName, resourceData);
let appName = appHash;
formattedResult[region] = formattedResult[region] || {};
formattedResult[region][appName] = formattedResult[region][appName] || {};
formattedResult[region][appName][service] = formattedResult[region][appName][service] || [];
let suitableResourceName = this._findSuitableResourceName(service, resourceData, resourceName);
if (formattedResult[region][appName][service].indexOf(suitableResourceName) === -1) {
formattedResult[region][appName][service].push(suitableResourceName);
}
}
}
}
}
return this._stringifyResult(formattedResult, levelsFlags);
}.bind(this));
}
/**
* @param {String} service
* @param {String} resourceName
* @param {Object} resourceData
* @returns {Promise}
* @private
*/
_resolveAppName(service, resourceName, resourceData) {
let resourceId;
let appBaseHash;
let appEnv;
switch (service) {
case 'APIGateway':
case 'APIGatewayKey':
case 'APIGatewayPlan':
resourceId = resourceData.name;
break;
case 'CloudFront':
resourceId = resourceData.DeepResourceId; // "DeepResourceId" is injected by CloudFront Listing Driver
break;
case 'IAM':
resourceId = resourceData.RoleName;
break;
case 'CognitoIdentity':
resourceId = resourceData.IdentityPoolName;
break;
case 'CognitoIdentityProvider':
resourceId = resourceData.Name;
break;
default:
resourceId = resourceName;
}
appBaseHash = AbstractService.extractBaseHashFromResourceName(resourceId);
appEnv = AbstractService.extractEnvFromResourceName(resourceId);
if (appBaseHash && appEnv) {
let cacheKey = `${appBaseHash}.${appEnv}`;
if (this._namingCache.hasOwnProperty(cacheKey)) {
return Promise.resolve(this._namingCache[cacheKey]);
}
return co(function* () {
try {
let data = yield this._tryReadS3ProvisionConfig(appBaseHash, appEnv);
let config = JSON.parse(data.Body.toString());
this._namingCache[cacheKey] = `${config.appName} (${appBaseHash})`;
} catch (e) {
this._namingCache[cacheKey] = `${appEnv} (${appBaseHash})`;
}
return this._namingCache[cacheKey];
}.bind(this));
}
return Promise.resolve(ApplicationFormatter.UNKNOWN_APPLICATION);
}
/**
* @param {Object} result
* @param {Number} levelsFlags
* @returns {*}
* @private
*/
_stringifyResult(result, levelsFlags) {
let TAB = ' ';
let output = os.EOL;
Object.keys(result).sort().forEach((regionName) => {
let appResult = result[regionName];
let appIndex = 0;
let regionLabel = `REGION: ${regionName}${os.EOL}`;
output += `${'#'.repeat(regionLabel.length -1)}${os.EOL}${regionLabel}`;
Object.keys(appResult).sort().forEach((appHash) => {
let appName = `Application ${appHash}`;
let serviceIndex = 0;
let servicesObj = appResult[appHash];
let servicesNames = Object.keys(servicesObj);
if (levelsFlags & ApplicationFormatter.APP_LEVEL) {
appName += ` | using ${servicesNames.length} cloud services`;
output += `${os.EOL}#${++appIndex}. ${appName} ${os.EOL}`;
output += ` ${'-'.repeat(appName.length)} ${os.EOL}`;
}
servicesNames.sort(ApplicationFormatter.serviceSorting).forEach((serviceName) => {
let resourceIndex = 0;
let resourcesArr = servicesObj[serviceName];
if (levelsFlags & ApplicationFormatter.SERVICE_LEVEL) {
output += `${os.EOL}${TAB.repeat(2)}${++serviceIndex}. ${this._humanizeAwsServiceName(serviceName)} `;
output += `| using ${resourcesArr.length} cloud resources: ${os.EOL}`;
}
if (levelsFlags & ApplicationFormatter.RESOURCE_LEVEL) {
for (let resource of resourcesArr) {
output += `${TAB.repeat(3)}${serviceIndex}.${++resourceIndex}. ${resource}${os.EOL}`;
}
}
});
output += os.EOL;
});
});
return output;
}
/**
* @param {String} appBaseHash
* @param {String} appEnv
* @returns {Promise}
* @private
*/
_tryReadS3ProvisionConfig(appBaseHash, appEnv) {
let s3 = this._property.provisioning.getAwsServiceByName('s3');
let payload = {
Bucket: this._generateSystemBucketARN(appBaseHash, appEnv),
Key: DeployConfig.generateConfigFilename(appBaseHash, appEnv),
};
return s3.getObject(payload).promise();
}
/**
* @param {String} baseHash
* @param {String} env
* @returns {String}
* @private
*/
_generateSystemBucketARN(baseHash, env) {
return [
AbstractService.AWS_RESOURCES_PREFIX,
env,
S3Service.PRIVATE_BUCKET,
baseHash
].join(AbstractService.DELIMITER_DOT);
}
/**
*
* @param {String} service
* @returns {String}
* @private
*/
_humanizeAwsServiceName(service) {
return `${this._findSuitableServiceTier(service)} Tier / Amazon ${service}`;
}
/**
* @param {String} service
* @returns {*}
* @private
*/
_findSuitableServiceTier(service) {
switch(service) {
case 'IAM':
case 'CognitoIdentity':
case 'CognitoIdentityProvider':
return ApplicationFormatter.SECURITY_TIER;
case 'ES':
case 'ElastiCache':
case 'CloudWatchLogs':
case 'DynamoDB':
case 'SQS':
return ApplicationFormatter.DATA_TIER;
case 'CloudWatchEvents':
case 'Lambda':
case 'APIGateway':
case 'APIGatewayKey':
case 'APIGatewayPlan':
return ApplicationFormatter.BACKEND_TIER;
case 'S3':
case 'CloudFront':
return ApplicationFormatter.FRONTEND_TIER;
default:
return '';
}
}
/**
* @param {String} serviceA
* @param {String} serviceB
* @returns {Number}
* @private
*/
static serviceSorting(serviceA, serviceB) {
let order = [
'IAM',
'CognitoIdentity',
'CognitoIdentityProvider',
'S3',
'CloudFront',
'APIGateway',
'APIGatewayKey',
'APIGatewayPlan',
'Lambda',
'CloudWatchEvents',
'DynamoDB',
'SQS',
'ElastiCache',
'ES',
'CloudWatchLogs',
];
return order.indexOf(serviceA) - order.indexOf(serviceB);
}
/**
* @param {String} service
* @param {Object} resourceData
* @param {String} defaultName
* @returns {*}
* @private
*/
_findSuitableResourceName(service, resourceData, defaultName) {
switch (service) {
case 'IAM':
return resourceData.RoleName;
case 'CognitoIdentity':
return `${resourceData.IdentityPoolId} (${resourceData.IdentityPoolName})`;
case 'CloudFront':
return `${resourceData.DomainName} | ${resourceData.Enabled ? 'Enabled' : 'Disabled'}`;
case 'APIGateway':
case 'APIGatewayKey':
case 'APIGatewayPlan':
return resourceData.name;
case 'Lambda':
return resourceData.FunctionName;
case 'S3':
case 'CloudWatchEvents':
return resourceData.Name;
case 'ES':
return `${resourceData.DomainName} | ${resourceData.Deleted ? 'Deleting' : 'Running'}`;
case 'CognitoIdentityProvider':
return this._property.provisioning.services
.find(CognitoIdentityProviderService)
._generateCognitoProviderName(resourceData);
default:
return defaultName;
}
}
/**
* @returns {Number}
*/
static get APP_LEVEL() {
return 0x001;
}
/**
* @returns {Number}
*/
static get SERVICE_LEVEL() {
return 0x002;
}
/**
* @returns {Number}
*/
static get RESOURCE_LEVEL() {
return 0x004;
}
/**
* @returns {String}
*/
static get BACKEND_TIER() {
return 'Backend';
}
/**
* @returns {String}
*/
static get FRONTEND_TIER() {
return 'Frontend';
}
/**
* @returns {String}
*/
static get SECURITY_TIER() {
return 'Security';
}
/**
* @returns {String}
*/
static get DATA_TIER() {
return 'Data';
}
/**
* @returns {String}
*/
static get UNKNOWN_APPLICATION() {
return 'unknown application';
}
};