UNPKG

berlioz

Version:

Berlioz - cloud deployment and migration services

336 lines (285 loc) 11 kB
const Promise = require('the-promise'); const _ = require('the-lodash'); const uuid = require('uuid/v4'); const keypair = require('keypair'); const DependencyResolver = require('processing-tools/dependency-resolver'); const SubnetAllocator = require('processing-tools/subnet-allocator'); const PortAllocator = require('processing-tools/port-allocator'); const ServiceProcessor = require('./service-processor'); class SectorProcessor { constructor(clusterProcessor, sectorEntity) { this._sectorEntity = sectorEntity; this._clusterProcessor = clusterProcessor; this._rootProcessor = clusterProcessor.rootProcessor; this._logger = clusterProcessor.logger; this._serviceProcessors = {}; for (var serviceEntity of this.sectorEntity.services) { var svc = new ServiceProcessor(this, serviceEntity); this._serviceProcessors[serviceEntity.name] = svc; } } get logger() { return this._logger; } get clusterEntity() { return this.clusterProcessor.clusterEntity; } get sectorEntity() { return this._sectorEntity; } get sectorName() { return this.sectorEntity.name; } get clusterName() { return this.clusterEntity.name; } get serviceProcessors() { return _.values(this._serviceProcessors); } get rootProcessor() { return this._rootProcessor; } get clusterProcessor() { return this._clusterProcessor; } get currentConfig() { return this.rootProcessor._currentConfig; } get deploymentName() { return this.rootProcessor.deploymentName; } getServiceProcessor(name) { return this._serviceProcessors[name]; } finalizeSetup() { return Promise.serial(this.serviceProcessors, x => x.finalizeSetup()); } constructConfig(config) { this._logger.info('[sector::constructConfig] %s', this.sectorEntity.id); return Promise.resolve() .then(() => this._constructEncryptionKeys(config)) // .then(() => this._constructSecrets(config)) .then(() => this._constructSidecars(config)) .then(() => this._constructServices(config)) .then(() => this._setupConfigTaskDependencies(config)) ; } preConstructInit() { this._preparePortAllocator(); for(var serviceProcessor of this.serviceProcessors) { serviceProcessor.preConstructInit(); } } _preparePortAllocator() { } _constructDatabases(config) { return Promise.serial(this.clusterEntity.databases, x => this.getDatabase(config, x)); } getDatabase(config, database) { if (database.className == 'nosql' && database.subClassName == 'dynamodb') { return this._constructDynamoDBDatabase(config, database); } } _constructDynamoDBDatabase(config, database) { var naming = [this.deploymentName, this.clusterName, this.sectorName, database.name]; var db = config.find('dynamodb', naming); if (db) { return db; } db = config.section('dynamodb').create(naming); db.config.AttributeDefinitions = {}; db.config.KeySchema = {}; for(var attribute of database.attributes) { db.config.AttributeDefinitions[attribute.name] = { AttributeType: _.upperCase(attribute.type.substring(0, 1)) }; if (attribute.keyType == 'hash' || attribute.keyType == 'range') { db.config.KeySchema[attribute.name] = { KeyType: _.upperCase(attribute.keyType) }; } } return db; } _constructEncryptionKeys(config) { this._logger.info('[sector::_constructEncryptionKeys] '); return this.getEncryptionKeyAlias(config) } getEncryptionKeyAlias(config) { if (!this.hasAwsProvider) { return null; } this._logger.info('[sector::getEncryptionKeyAlias] ...'); var aliasNaming = [this.deploymentName, this.clusterName, this.sectorName]; var keyAliasItem = config.find('encryption-key-alias', aliasNaming); if (keyAliasItem) { return keyAliasItem; } keyAliasItem = config.section('encryption-key-alias').create(aliasNaming) var keyNaming = [this.deploymentName, this.clusterName, this.sectorName]; var keyItem = config.section('encryption-key').create(keyNaming); keyItem.setConfig('KeyState', 'Enabled') return Promise.resolve() .then(() => keyAliasItem.relation(keyItem)) .then(() => keyAliasItem); } _constructSecrets(config) { this._logger.info('[cluster::_constructSecrets] '); return Promise.serial(this.clusterEntity.secrets, x => this.getSecret(config, x)); } getSecret(config, secret) { if (!secret) { return null; } this._logger.info('[cluster::getSecret] %s...', secret.name); if (secret.className == 'public-key' && secret.subClassName == 'rsa') { return this._constructRsaSecret(config, secret); } } getSecretForAction(config, secret, action) { this._logger.info('[cluster::getSecretForAction] %s :: %s...', secret.id, action); return Promise.resolve(this.getSecret(config, secret)) .then(result => { if (!result) { this._logger.warn('[cluster::getSecretForAction] no result for %s :: %s...', secret.id, action); return null; } this._logger.warn('[cluster::getSecretForAction] %s :: %s, results:', secret.id, action, _.keys(result)); if (action in result) { return result[action]; } return null; }) } _constructRsaSecret(config, secret) { this._logger.info('[cluster::_constructRsaSecret] %s...', secret.name); var namingPublic = [this.deploymentName, this.clusterName, this.sectorName, secret.name, 'secret_public_key']; var namingPrivate = [this.deploymentName, this.clusterName, this.sectorName, secret.name, 'secret_private_key']; var secretPublicItem = config.find('parameter', namingPublic); var secretPrivateItem = config.find('parameter', namingPrivate); return Promise.resolve() .then(() => { if (!secretPublicItem || !secretPrivateItem) { secretPublicItem = config.section('parameter').create(namingPublic); secretPublicItem.setConfig('Type', 'SecureString'); secretPrivateItem = config.section('parameter').create(namingPrivate); secretPrivateItem.setConfig('Type', 'SecureString'); var pair = keypair(secret.length); secretPublicItem.setRuntime({ Value: pair.public }) secretPrivateItem.setRuntime({ Value: pair.private }) } return Promise.resolve() .then(() => this.getEncryptionKeyAlias(config)) .then(keyAlias => { return Promise.resolve() .then(() => secretPublicItem.relation(keyAlias)) .then(() => secretPrivateItem.relation(keyAlias)) }) }) .then(() => ({ public: secretPublicItem, private: secretPrivateItem, encrypt: secretPublicItem, decrypt: secretPrivateItem })) } _constructQueues(config) { this._logger.info('[cluster::_constructQueues] '); return Promise.serial(this.clusterEntity.queues, x => this.getQueue(config, x)); } getQueue(config, queue) { if (!queue) { return null; } this._logger.info('[cluster::getQueue] %s...', queue.name); if (queue.className == 'queue' && queue.subClassName == 'kinesis') { return this._constructKinesisQueue(config, queue); } } _constructKinesisQueue(config, queue) { this._logger.info('[cluster::_constructKinesisQueue] %s...', queue.name); var naming = [this.deploymentName, this.clusterName, this.sectorName, queue.name]; var queueItem = config.find('kinesis', naming); if (queueItem) { return queueItem; } queueItem = config.section('kinesis').create(naming); return queueItem; } _constructSidecars(config) { this._logger.info('[sector::_constructSidecars] %s', this.sectorName); var services = this.sectorEntity.services.filter(x => x.sidecar == 'instance'); return Promise.serial(services, service => { var serviceProcessor = this.getServiceProcessor(service.name); return serviceProcessor.constructConfig(config); }); } _constructServices(config) { var resolver = new DependencyResolver(); for (var serviceEntity of this.sectorEntity.services) { if (serviceEntity.sidecar) { continue; } this._logger.info('[sector::_constructServices] service: %s', serviceEntity.name); resolver.add(serviceEntity.name); for (var consumerEntity of serviceEntity.localConsumes) { resolver.add(serviceEntity.name, consumerEntity.targetNaming[1]); } } this._logger.info('[sector::_constructServices] service order: ', resolver.order ); return Promise.serial(resolver.order, name => { this._logger.info('[sector::_constructServices] 2. service: %s', name); var serviceProcessor = this.getServiceProcessor(name); return serviceProcessor.constructConfig(config); }); } _setupConfigTaskDependencies(config) { this._logger.info('[_setupConfigTaskDependencies]'); return Promise.serial(_.values(this._serviceProcessors), x => x.setupTasksDependencies(config)); } markNewStageNeeded(reason) { return this.rootProcessor.markNewStageNeeded(reason); } _setupReadyContainerObject(config, item) { var readyObject = config.section('ready-' + item.meta.name).create(item.naming); readyObject.setConfig('naming', item.naming); return Promise.resolve() .then(() => readyObject.relation(item)) .then(() => readyObject) ; } } module.exports = SectorProcessor;