berlioz
Version:
Berlioz - cloud deployment and migration services
838 lines (712 loc) • 29.6 kB
JavaScript
const Promise = require('the-promise');
const _ = require('the-lodash');
const Path = require('path');
const uuid = require('uuid/v4');
const EnvTools = require('processing-tools/env-tools');
class ServiceProcessor
{
constructor(sectorProcessor, serviceEntity)
{
this._sectorProcessor = sectorProcessor;
this._clusterProcessor = sectorProcessor.clusterProcessor;
this._logger = this.sectorProcessor.logger;
this._serviceEntity = serviceEntity;
this._volumes = [];
}
get repoStore() {
return this.rootProcessor.repoStore;
}
get serviceEntity() {
return this._serviceEntity;
}
get definition() {
return this.serviceEntity.definition;
}
get serviceName() {
return this.serviceEntity.name;
}
get full_name() {
return this.clusterName + '-' + this.serviceName;
}
get volumes() {
return this._volumes;
}
get clusterProcessor() {
return this._clusterProcessor;
}
get sectorProcessor() {
return this._sectorProcessor;
}
get rootProcessor() {
return this.sectorProcessor.rootProcessor;
}
get metadataProcessor() {
return this.rootProcessor.metadataProcessor;
}
get endpointProcessor() {
return this.rootProcessor.endpointProcessor;
}
get nativeProcessor() {
return this.rootProcessor.nativeProcessor;
}
get peersFetcher() {
return this.rootProcessor.peersFetcher;
}
get clusterName() {
return this.serviceEntity.clusterName;
}
get sectorName() {
return this.serviceEntity.sectorName;
}
get desiredCount() {
if (this.serviceEntity.sidecar == 'instance') {
return 1;
}
var scaling = this.serviceEntity.getScaling();
this._logger.info('DesiredCount CHECK. %s, scaling:', this.serviceEntity.id, scaling);
return scaling.desired;
}
get provides() {
return _.values(this._provides);
}
get memory() {
var value = this.getResource('memory').min;
if (!value)
{
value = this.getResource('memory').max;
}
return value;
}
get ignition() {
if (!this.definition.ignition) {
return {};
}
return this.definition.ignition;
}
get identity() {
return this.serviceEntity.identity;
}
finalizeSetup()
{
if (!this.serviceEntity.isManaged) {
return;
}
this._massageVolumeConfig();
}
preConstructInit()
{
this._massageProvidesConfig();
}
constructConfig(config)
{
this._logger.info('[service::constructConfig] %s', this.serviceEntity.id);
if (!this.serviceEntity.isManaged) {
return;
}
if (!this._getMyImage()) {
this._logger.error('[service::constructConfig] repository not present for %s.', this.serviceEntity.id);
return;
}
return Promise.resolve()
.then(() => this._processLoadBalancers(config))
.then(() => this._processTasks(config))
.then(() => this._constructServices(config))
;
}
_constructServices(config)
{
this._logger.info('[_constructServices] %s', this.serviceEntity.id);
return Promise.serial(this.provides, x => this._constructExposeService(config, x));
}
_constructExposeService(config, provided)
{
var providedEntity = provided.providedEntity;
var clusterProvided = providedEntity.clusterProvided;
var endpointInfo = {
protocol: providedEntity.protocol,
networkProtocol: providedEntity.networkProtocol,
address: this.getInternalAddress(provided.name),
port: provided.exposedPort
}
var endpointProcId = [this.serviceEntity.id, provided.name].join('-');
this.endpointProcessor.reportInternalEndpoint(endpointProcId, "0", endpointInfo);
if (clusterProvided)
{
endpointProcId = [clusterProvided.cluster.id, clusterProvided.name].join('-');
this.endpointProcessor.reportInternalEndpoint(endpointProcId, "0", endpointInfo);
}
}
_processLoadBalancers(config)
{
return Promise.serial(this.provides, x => this._getLoadBalancer(config, x));
}
_getLoadBalancer(config, provided)
{
if (!provided.loadBalance) {
return null;
}
var naming = [this.clusterName, this.sectorName, this.serviceName, provided.name];
var lb = config.find('load-balancer', naming);
if (lb) {
return lb;
}
var repoInfo = this.rootProcessor.getHelperImage('load-balancer');
if (!repoInfo) {
this._logger.error('Repo for load balancer not present.')
return null;
}
lb = config.section('load-balancer').create(naming);
if (lb.resolved) {
lb.config.ipAddress = lb.resolved.config.ipAddress;
} else {
lb.config.ipAddress = this.rootProcessor.allocateContainerAddress();
}
var endpointWorkDir = this.rootProcessor.getServiceEndpointWorkingPath(this.serviceEntity, provided.name);
lb.config.haProxyConfigPath = Path.resolve(endpointWorkDir, 'haproxy.cfg');
lb.config.image = repoInfo.name;
lb.config.imageId = repoInfo.digest;
lb.config.aliases = {};
lb.config.labels = {
'berlioz:kind': 'load-balancer',
'berlioz:cluster': this.clusterName,
'berlioz:sector': this.sectorName,
'berlioz:service': this.serviceName,
'berlioz:endpoint': provided.name,
'berlioz:haproxycfg': lb.config.haProxyConfigPath
}
var hostPort = this._getContainerEndPointHostPort(lb, provided.networkProtocol, provided.exposedPort);
lb.config.ports = { tcp: {}, udp: {}};
lb.config.ports[provided.networkProtocol][provided.exposedPort] = String(hostPort);
lb.config.aliases[this.getInternalAddress(provided.name)] = true;
return Promise.resolve()
.then(() => this.clusterProcessor._setupReadyContainerObject(config, lb))
.then(() => lb);
}
_processTasks(config)
{
return Promise.resolve()
.then(() => this._deleteExtraTasks(config))
.then(() => {
var myTasks = this._getMyTasks(config);
this._logger.info('[_processTasks] ExistingTasks:', myTasks.map(x => x.dn));
this._logger.info('[_processTasks] Service=%s. Processing Current Tasks. length=%s', this.full_name, myTasks.length);
return Promise.serial(myTasks, x => this._configExistingTask(config, x));
})
.then(() => this._processNewTasks(config))
// .then(() => {
// var myTasks = this._getMyTasks(config);
// return Promise.serial(myTasks, x => this._setupTaskCompletionChecker(config, x));
// });
}
_deleteExtraTasks(config)
{
var myTasks = this._getMyTasks(config);
this._logger.info('[_deleteExtraTasks] %s. myTasks Count: %s', this.full_name, myTasks.length);
var desiredCount = this.desiredCount;
this._logger.info('[_deleteExtraTasks] %s. desiredCount: %s', this.full_name, desiredCount);
var toBeRemovedCount = myTasks.length - desiredCount;
this._logger.info('[_deleteExtraTasks] %s. toBeRemovedCount: %s', this.full_name, toBeRemovedCount);
if (toBeRemovedCount <= 0) {
return;
}
myTasks = _.sortBy(myTasks, x => x.id);
var toBeDeletedTasks = _.takeRight(myTasks, toBeRemovedCount);
this._logger.info('[_deleteExtraTasks] %s. toBeDeletedTasks: ', this.full_name, toBeDeletedTasks.map(x => x.dn));
for(var task of toBeDeletedTasks)
{
task.remove();
}
}
_setupTaskCompletionChecker(config, task)
{
// if (!this.ignition.period) {
// return true;
// }
//
// task.completionCheckerCb = () => {
// if (task.obj && task.obj.startedAt) {
// var diff = new DateDiff(Date.now(), task.obj.startedAt);
// this._logger.info('[_setupTaskCompletionChecker] %s, seconds %s past start...', task.dn, diff.seconds());
// var secondsToWait = this.ignition.period - diff.seconds();
// this._logger.info('[_setupTaskCompletionChecker] %s, %s seconds to wait...', task.dn, secondsToWait);
// if (secondsToWait <= 0) {
// return {
// ready: true
// };
// } else if (secondsToWait < 10) {
// return {
// ready: false,
// retry: true,
// timeout: secondsToWait
// };
// } else {
// this.rootProcessor.postponeWithTimeout(secondsToWait, 'TaskCompletionCheck: ' + task.dn);
// return {
// ready: false,
// retry: false
// };
// }
// }
//
// return {
// ready: false,
// retry: true,
// timeout: 10
// };
// };
}
_processNewTasks(config)
{
var myTasks = this._getMyTasks(config);
this._logger.info('[_processNewTasks] Service=%s. MyTasks::Length=%s, DesiredCount=%s', this.serviceEntity.id, myTasks.length, this.desiredCount);
var toBeCreatedCount = Math.max(this.desiredCount - myTasks.length, 0);
this._logger.info('[_processNewTasks] Service=%s. toBeCreatedCount=%s', this.serviceEntity.id, toBeCreatedCount);
var identities = [];
if (this.identity == 'sequential') {
identities = _.range(1, this.desiredCount + 1);
} else {
var nextIdentity = this._calculateNextIdentity(config);
this._logger.info('[_processNewTasks] Service=%s. nextIdentity=%s', this.serviceEntity.id, nextIdentity);
identities = _.range(nextIdentity, toBeCreatedCount + nextIdentity);
}
return Promise.serial(identities, identity => {
this._logger.info('[_processNewTasks] Service=%s. identity=%s', this.serviceEntity.id, identity);
var task = config.find('task', [this.clusterName, this.sectorName, this.serviceName, identity]);
if (!task) {
return this._createNewTask(config, identity);
} else {
this._logger.info('[_processNewTasks] Service=%s. identity=%s task already exists.', this.serviceEntity.id, identity);
}
});
}
_createNewTask(config, identity)
{
this._logger.info('[_createNewTask] Creating %s-%s task...', this.serviceEntity.id, identity);
var task = config.section('task').create([this.clusterName, this.sectorName, this.serviceName, identity]);
task.setConfig('taskId', uuid());
task.setConfig('ipAddress', this.rootProcessor.allocateContainerAddress());
return Promise.resolve()
.then(() => this._configTask(config, task))
;
}
_getContainerEndPointHostPort(item, protocol, port)
{
var hostPort = this.rootProcessor.fetchTaskHostPort(item.dn, protocol, port);
return hostPort;
}
_configExistingTask(config, task)
{
this._logger.info('[_configExistingTask] %s..', task.dn);
return this._configTask(config, task)
}
_getMyImage()
{
return this.rootProcessor.getImage(this.serviceEntity.id);
}
_configTask(config, task)
{
this._logger.info('[_configTask] %s..', task.dn);
task.setConfig('binds', []);
task.config.ports = { tcp: {}, udp: {}};
task.config.labels = {
'berlioz:kind': 'task',
'berlioz:cluster': task.naming[0],
'berlioz:sector': task.naming[1],
'berlioz:service': task.naming[2],
'berlioz:identity': task.naming[3].toString()
}
task.config.aliases = {};
{
{
var parts = [
task.naming[2] + task.naming[3],
task.naming[1],
task.naming[0]
];
var hostName = this.peersFetcher.getHostNameFromParts(parts);
task.config.aliases[hostName] = true;
}
{
task.config.aliases[this.getInternalAddress()] = true;
}
for(var provided of this.provides)
{
if (!provided.loadBalance)
{
task.config.aliases[this.getInternalAddress(provided.name)] = true;
}
}
}
var repoInfo = this._getMyImage();
task.config.image = repoInfo.name;
task.config.imageId = repoInfo.digest;
return Promise.resolve()
.then(() => this.clusterProcessor._setupReadyContainerObject(config, task))
.then(() => this._configTaskMetadataHolder(config, task))
.then(taskMetadata => {
var full_path = this.rootProcessor.getTaskMetadataWorkingPath(taskMetadata.naming[0]);
this.addBindToTask(task, full_path, this.serviceEntity.berliozConsumesPath);
this.nativeProcessor.setupConsumedRelationsAndPeers(
this.serviceEntity,
taskMetadata);
return task.relation(taskMetadata);
})
.then(() => {
return Promise.serial(this.provides, x => this._configTaskProvided(config, task, x));
})
.then(() => Promise.serial(this._volumes, x => this._setupTaskVolume(config, task, x)))
.then(() => Promise.serial(this.serviceEntity.storage, x => this._setupTaskBinds(config, task, x)))
.then(() => {
var environment = this.extractTaskEnvironment(config, task);
task.setConfig('environment', environment)
})
;
}
getInternalAddress(providedNameOrNone)
{
var parts = [];
if (providedNameOrNone) {
parts.push(providedNameOrNone);
}
parts.push(this.serviceName);
parts.push(this.sectorName);
parts.push(this.clusterName);
var hostName = this.peersFetcher.getHostNameFromParts(parts);
return hostName
}
_configTaskMetadataHolder(config, task)
{
var taskMetadataName = 'task-' + task.naming.join('-');
var naming = [taskMetadataName];
var taskMetadata = config.find('task-metadata', naming);
if (taskMetadata) {
return taskMetadata;
}
taskMetadata = config.section('task-metadata').create(naming);
return taskMetadata;
}
_setupTaskBinds(config, task, store)
{
if (store.kind != 'bind')
{
return;
}
task.config.binds.push(store.source + ':' + store.path);
}
addBindToTask(task, source, dest)
{
if (this.rootProcessor._shell.isWindows()) {
source = source.replace(/\\/g, '/');
source = source.replace(/:/g, '');
source = source.charAt(0).toLowerCase() + source.slice(1);
source = '/host_mnt/' + source;
}
task.config.binds.push(source + ':' + dest);
}
_configTaskProvided(config, task, provided)
{
var hostPort = this._getContainerEndPointHostPort(task, provided.networkProtocol, provided.port);
task.config.ports[provided.networkProtocol][provided.port] = String(hostPort);
return Promise.resolve(this._getLoadBalancer(config, provided))
.then(lb => {
if (!lb) {
return;
}
var lbTarget = config.section('load-balancer-target').create([task.dn, provided.name])
lbTarget.setConfig('port', provided.port);
return Promise.resolve()
.then(() => lbTarget.relation(task))
.then(() => lb.relation(lbTarget).then(rel => {
rel.markIgnoreDelta();
rel.markIgnoreDependency();
}))
});
}
setupTasksDependencies(config)
{
// var tasks = this._getMyTasks(config);
// return Promise.serial(tasks, x => this._setupTaskDependencies(config, x));
}
// _setupTaskDependencies(config, task)
// {
// this._logger.info('[_setupTaskDependencies] %s', task.dn);
// return Promise.resolve()
// .then(() => {
// var consumedServicesEntities = this.serviceEntity.localConsumes.map(x => x.localTarget);
// this._logger.info('[_setupTaskDependencies] %s, consumedServicesEntities: ', task.dn, consumedServicesEntities.map(x => x.id));
// consumedServicesEntities = _.uniqBy(consumedServicesEntities, x => x.id);
// this._logger.info('[_setupTaskDependencies] %s, unique consumedServicesEntities: ', task.dn, consumedServicesEntities.map(x => x.id));
// return Promise.serial(consumedServicesEntities, x => this._setupTaskToConsumedServiceDependencies(config, task, x))
// })
// .then(() => Promise.serial(this.serviceEntity.databasesConsumes, x => this._setupTaskToDatabaseDependency(config, task, x)))
// .then(() => Promise.serial(this.serviceEntity.queuesConsumes, x => this._setupTaskToQueueDependency(config, task, x)))
// .then(() => Promise.serial(this.serviceEntity.secretsConsumes, x => this._setupTaskToSecretDependency(config, task, x)))
// ;
// }
// _setupTaskToConsumedServiceDependencies(config, task, consumedServiceEntity)
// {
// this._logger.info('[_setupTaskToConsumedServiceDependencies] %s to %s', task.dn, consumedServiceEntity.id);
// var tasks = this._getServiceTasks(config, consumedServiceEntity)
// tasks = _.sortBy(tasks, x => parseInt(x.naming[3]));
// if (this.serviceEntity.id == consumedServiceEntity.id)
// {
// var identity = parseInt(task.naming[3]);
// tasks = tasks.filter(x => parseInt(x.naming[3]) < identity);
// }
// if (consumedServiceEntity.identity == 'sequential') {
// tasks = _.takeRight(tasks, 1);
// } else {
// tasks = _.take(tasks, 1);
// }
// return Promise.serial(tasks, x => {
// return task.relation('task', x.naming)
// .then(rel => rel.markIgnoreDelta());
// });
// }
// _setupTaskToDatabaseDependency(config, task, serviceDatabaseConsumed)
// {
// this._logger.info('[_setupTaskToDatabaseDependency] %s to %s', task.dn, serviceDatabaseConsumed.id);
// return Promise.resolve()
// .then(() => this.sectorProcessor.getDatabase(config, serviceDatabaseConsumed.localTarget))
// .then(dynamoDatabase => {
// if (!dynamoDatabase) {
// return null;
// }
// return task.relation(dynamoDatabase)
// .then(rel => rel.markIgnoreDelta());
// })
// ;
// }
// _setupTaskToQueueDependency(config, task, serviceQueueConsumed)
// {
// this._logger.info('[_setupTaskToQueueDependency] %s to %s', task.dn, serviceQueueConsumed.id);
// return Promise.resolve()
// .then(() => this.sectorProcessor.getQueue(config, serviceQueueConsumed.localTarget))
// .then(queue => {
// if (!queue) {
// return null;
// }
// return task.relation(queue)
// .then(rel => rel.markIgnoreDelta());
// })
// ;
// }
// _setupTaskToSecretDependency(config, task, serviceSecretConsumed)
// {
// this._logger.info('[_setupTaskToSecretDependency] %s to %s', task.dn, serviceSecretConsumed.id);
// this._logger.info('[_setupTaskToSecretDependency] %s to %s, target: %s', task.dn, serviceSecretConsumed.id, serviceSecretConsumed.targetId);
// var secretEntity = serviceSecretConsumed.localTarget;
// if (!secretEntity) {
// this._logger.error('[_setupTaskToSecretDependency] %s to %s, secret missing.', task.dn, serviceSecretConsumed.id);
// return;
// }
// return Promise.serial(serviceSecretConsumed.actions, action => {
// this._logger.info('[_setupTaskToSecretDependency] %s to %s, action: %s', task.dn, serviceSecretConsumed.id, action);
// return Promise.resolve(this.sectorProcessor.getSecretForAction(config, secretEntity, action))
// .then(keyAlias => {
// if (!keyAlias) {
// this._logger.warn('[_setupTaskToSecretDependency] alias missing for %s to %s, action: %s', task.dn, serviceSecretConsumed.id, action);
// return;
// }
// return task.relation(keyAlias)
// .then(rel => rel.markIgnoreDelta());
// })
// })
// }
_setupTaskVolume(config, task, volumeInfo)
{
// var identity = task.naming[3];
// var volumeNaming = [this.deploymentName, this.clusterName, this.name, volumeInfo.name, identity];
// var volume = config.section('volume').create(volumeNaming)
// .setConfig('size', volumeInfo.size)
// .setConfig('zone', instance.config.zone)
// .setConfig('hostPath', volumeInfo.hostPath);
//
// return Promise.resolve()
// .then(() => volume.relation(instance))
// .then(() => task.relation(volume));
}
_getTaskIpAddress(config, task)
{
return '0.0.0.0';
// var containerInstance = task.findRelation('container-instance').targetItem;
// var instance = containerInstance.findRelation('instance').targetItem;
//
// var niRelation = task.findRelation('network-interface');
// if (niRelation)
// {
// var ni = niRelation.targetItem;
// if (ni) {
// if (ni.obj) {
// return ni.obj.PrivateIpAddress;
// }
// }
// }
//
// if (instance.config.existing) {
// return instance.obj.PrivateIpAddress;
// }
//
// return 'not-present';
}
_getTaskListenAddress(config, task)
{
// var containerInstance = task.findRelation('container-instance').targetItem;
// var instance = containerInstance.findRelation('instance').targetItem;
//
// for (var x of this.addressReserveDiscovery) {
// // TODO
// var ni = config.resolve('network-interface', [this.deploymentName, this.clusterName, this.name, task.naming[2]]);
// if (ni) {
// if (ni.obj) {
// return ni.obj.PrivateIpAddress;
// }
// }
// }
//
return '0.0.0.0';
}
_calculateNextIdentity(config)
{
var myTasks = this._getMyTasks(config);
var ids = myTasks.filter(x => 'BERLIOZ_IDENTITY' in x.config.environment)
.map(x => parseInt(x.config.environment['BERLIOZ_IDENTITY']));
ids.push(0);
var maxId = _.max(ids);
return maxId + 1;
}
_getMyTasks(config)
{
return this._getServiceTasks(config, this.serviceEntity);
}
_getServiceTasks(config, serviceEntity)
{
return config.section('task').items.filter(x => {
return (x.naming[0] == serviceEntity.clusterName) && (x.naming[1] == serviceEntity.sectorName) && (x.naming[2] == serviceEntity.name);
});
}
getResource(name) {
if (!this.definition.resources)
return {};
return this.definition.resources[name];
}
extractTaskEnvironment(config, task)
{
var berlizAgentIp = '172.17.0.1';
var baseOverrides = {
'BERLIOZ_TASK_ID': task.config.taskId,
'BERLIOZ_ADDRESS': task.config.ipAddress,
'BERLIOZ_IDENTITY': task.naming[3]
};
for (var provided of this.provides) {
baseOverrides[provided.envListenPortName] = provided.port;
// TODO: CHECK THIS CHANGE:
// baseOverrides[provided.envProvidedPortName] = task.config.ports[provided.networkProtocol][provided.port];
baseOverrides[provided.envProvidedPortName] = provided.port;
}
var consumedEnv = this.peersFetcher.getConsumedEnvironment(this.serviceEntity);
baseOverrides = _.defaults(baseOverrides, consumedEnv);
var baseEnv = this.extractBaseEnvironment(task.config.definitionIndex);
var targetEnv = _.defaults(_.clone(baseOverrides), baseEnv);
var serviceEnv = this.serviceEntity.environment;
var userEnv = EnvTools.substituteEnvironment(serviceEnv, targetEnv);
userEnv = EnvTools.substituteEnvironment(userEnv, userEnv);
var finalEnv = _.defaults(_.clone(targetEnv), userEnv);
return finalEnv;
}
extractBaseEnvironment(definitionIndex) {
var baseEnv = {
'BERLIOZ_AGENT_PATH': '',
'BERLIOZ_TASK_ID': '',
'BERLIOZ_IDENTITY': 0,
'BERLIOZ_ADDRESS': '0.0.0.0',
'BERLIOZ_LISTEN_ADDRESS': '0.0.0.0',
'BERLIOZ_INFRA': 'local',
'BERLIOZ_REGION': 'earth-local',
'BERLIOZ_INSTANCE_ID': 'local-1234',
'BERLIOZ_CLUSTER': this.clusterName,
'BERLIOZ_SECTOR': this.sectorName,
'BERLIOZ_SERVICE': this.serviceName
};
for (var provided of this.provides) {
baseEnv[provided.envProvidedPortName] = '';
baseEnv[provided.envListenPortName] = '';
}
return baseEnv;
}
_massageProvidesConfig()
{
this._logger.info('[_massageProvidesConfig] begin');
this._provides = {};
for (var provided of _.values(this.serviceEntity.provides))
{
var hostPort = 0;
var block = null;
// if (this.getNetworkMode() == 'host' || provided.reserved) {
// hostPort = provided.port;
// block = { start: hostPort, end: hostPort };
// } else {
// block = this.clusterProcessor._portAllocator.allocate(this.name, provided.port);
// }
var envProvidedPortName = 'BERLIOZ_PROVIDED_PORT_' + provided.name.toUpperCase();
var envListenPortName = 'BERLIOZ_LISTEN_PORT_' + provided.name.toUpperCase();
this._logger.info('[_massageProvidesConfig] %s :: %s, source: %s, port block:', this.serviceEntity.id, provided.name, provided.port, block);
var info = {
providedEntity: provided,
name: provided.name,
port: provided.port,
exposedPort: provided.port,
protocol: provided.protocol,
networkProtocol: provided.networkProtocol,
reserved: provided.reserved,
loadBalance: false, //provided.loadBalance,
isPublic: provided.isPublic,
dns: provided.dns,
block: block,
hostPort: hostPort,
envProvidedPortName: envProvidedPortName,
envListenPortName: envListenPortName
};
if (provided.isPublic) {
info.loadBalance = true;
}
if (info.loadBalance)
{
if (provided.protocol == 'http' || provided.protocol == 'https')
{
info.exposedPort = 80;
}
}
this._provides[provided.name] = info;
}
this._logger.info('[_massageProvidesConfig] %s:', this.serviceEntity.id, _.keys(this._provides));
}
_massageVolumeConfig()
{
for (var store of this.serviceEntity.storage)
{
if (store.kind == 'volume')
{
if (store.permanent)
{
var name = store.path.replace(/\//gi,'_');
var volumeInfo = {
hostPath: '/volumes/' + this.serviceName + '/' + name,
name: name,
containerPath: store.path,
size: this._convertSizeToGb(store.size)
}
this._volumes.push(volumeInfo);
}
}
}
}
_convertSizeToGb(size)
{
size = _.lowerCase(size);
size = _.replace(size, 'gb', '');
size = parseInt(size);
return size;
}
}
module.exports = ServiceProcessor;