2017-06-09 07:26:25 +03:00
|
|
|
const { v4: uuid } = require('uuid');
|
|
|
|
const paramCase = require('param-case');
|
|
|
|
const camelCase = require('camel-case');
|
|
|
|
const yaml = require('js-yaml');
|
|
|
|
|
2017-05-18 21:21:33 +03:00
|
|
|
const {
|
|
|
|
datacenter,
|
|
|
|
portal,
|
|
|
|
deploymentGroups,
|
|
|
|
services,
|
|
|
|
instances
|
|
|
|
} = require('./data.json');
|
|
|
|
|
|
|
|
const find = (query = {}) => item =>
|
|
|
|
Object.keys(query).every(key => item[key] === query[key]);
|
|
|
|
|
|
|
|
const cleanQuery = (q = {}) => JSON.parse(JSON.stringify(q));
|
|
|
|
|
2017-06-26 15:25:46 +03:00
|
|
|
const getInstances = query => {
|
|
|
|
return Promise.resolve(instances.filter(find(cleanQuery(query))));
|
|
|
|
};
|
2017-06-08 00:15:48 +03:00
|
|
|
|
2017-06-26 15:25:46 +03:00
|
|
|
const getUnfilteredServices = query => {
|
2017-06-08 00:15:48 +03:00
|
|
|
const instancesResolver = ({ id }) => query =>
|
|
|
|
getInstances(
|
|
|
|
Object.assign({}, query, {
|
|
|
|
serviceId: id
|
2017-05-18 21:21:33 +03:00
|
|
|
})
|
2017-06-08 00:15:48 +03:00
|
|
|
);
|
2017-05-18 21:21:33 +03:00
|
|
|
|
2017-06-08 00:15:48 +03:00
|
|
|
const addNestedResolvers = service =>
|
|
|
|
Object.assign({}, service, {
|
|
|
|
instances: instancesResolver(service)
|
|
|
|
});
|
2017-05-18 21:21:33 +03:00
|
|
|
|
2017-06-08 00:15:48 +03:00
|
|
|
return Promise.resolve(
|
|
|
|
services.filter(find(cleanQuery(query))).map(addNestedResolvers)
|
|
|
|
);
|
|
|
|
};
|
2017-05-18 21:21:33 +03:00
|
|
|
|
2017-06-26 15:25:46 +03:00
|
|
|
const getServices = query => {
|
|
|
|
const services = getUnfilteredServices(query)
|
|
|
|
.then(services => {
|
|
|
|
// loop through services and for each of them get all services that's parent id is the service
|
|
|
|
// once done - this will be a Promise all - need to remove any duplicates from the services list - the original
|
|
|
|
// then we can do below...
|
|
|
|
return (
|
|
|
|
Promise.all(
|
|
|
|
services.map(service => getUnfilteredServices({ parent: service.id }))
|
|
|
|
)
|
|
|
|
// this is going to be an array of arrays of services
|
|
|
|
.then(childServices => {
|
|
|
|
return childServices.reduce((childServices, childService) => {
|
|
|
|
return childServices.concat(childService);
|
|
|
|
}, []);
|
|
|
|
})
|
|
|
|
// now it's at least flat
|
|
|
|
.then(childServices => {
|
|
|
|
return services.concat(
|
|
|
|
childServices.reduce((childServices, childService) => {
|
|
|
|
const exists = services.filter(
|
|
|
|
service => service.id === childService.id
|
|
|
|
).length;
|
|
|
|
if (!exists) {
|
|
|
|
childServices.push(childService);
|
|
|
|
}
|
|
|
|
return childServices;
|
|
|
|
}, [])
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.then(services => {
|
|
|
|
return Promise.all(
|
|
|
|
services.map(service => service.instances())
|
|
|
|
).then(instances => {
|
|
|
|
return { services, instances };
|
|
|
|
});
|
|
|
|
})
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.then(({ services, instances }) => {
|
|
|
|
const activeServices = services.reduce((services, service, index) => {
|
|
|
|
const active = instances[index].filter(
|
|
|
|
instance =>
|
|
|
|
instance.status !== 'DELETED' && instance.status !== 'EXITED'
|
|
|
|
).length;
|
|
|
|
if (active) {
|
|
|
|
services.push(service);
|
|
|
|
}
|
|
|
|
return services;
|
|
|
|
}, []);
|
|
|
|
const allServices = activeServices.reduce((allServices, service) => {
|
|
|
|
if (service.parent) {
|
|
|
|
const parentService = services.filter(s => s.id === service.parent);
|
|
|
|
const exists = allServices.filter(s => s.id === service.parent)
|
|
|
|
.length;
|
|
|
|
if (!exists && parentService) {
|
|
|
|
allServices.push(parentService[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
allServices.push(service);
|
|
|
|
return allServices;
|
|
|
|
}, []);
|
|
|
|
return allServices;
|
|
|
|
});
|
|
|
|
|
|
|
|
return Promise.resolve(services);
|
|
|
|
};
|
|
|
|
|
2017-06-08 00:15:48 +03:00
|
|
|
const getDeploymentGroups = query => {
|
|
|
|
const servicesResolver = ({ id }) => query =>
|
|
|
|
getServices(
|
|
|
|
Object.assign({}, query, {
|
|
|
|
deploymentGroupId: id
|
|
|
|
})
|
|
|
|
);
|
2017-05-18 21:21:33 +03:00
|
|
|
|
2017-06-08 00:15:48 +03:00
|
|
|
const addNestedResolvers = dg =>
|
|
|
|
Object.assign({}, dg, {
|
|
|
|
services: servicesResolver(dg)
|
|
|
|
});
|
|
|
|
|
|
|
|
return Promise.resolve(
|
|
|
|
deploymentGroups.filter(find(cleanQuery(query))).map(addNestedResolvers)
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const getPortal = () =>
|
|
|
|
Promise.resolve(
|
|
|
|
Object.assign({}, portal, {
|
|
|
|
datacenter,
|
|
|
|
deploymentGroups: getDeploymentGroups
|
|
|
|
})
|
|
|
|
);
|
2017-05-18 21:21:33 +03:00
|
|
|
|
2017-06-09 07:26:25 +03:00
|
|
|
const createDeploymentGroup = ({ name }) => {
|
|
|
|
const dg = {
|
|
|
|
id: uuid(),
|
|
|
|
slug: paramCase(name),
|
|
|
|
name
|
|
|
|
};
|
|
|
|
|
|
|
|
deploymentGroups.push(dg);
|
|
|
|
|
|
|
|
return Promise.resolve(dg);
|
|
|
|
};
|
|
|
|
|
|
|
|
const createServicesFromManifest = ({ deploymentGroupId, raw }) => {
|
|
|
|
const manifest = yaml.safeLoad(raw);
|
|
|
|
|
|
|
|
Object.keys(manifest).forEach(name => {
|
|
|
|
const service = {
|
|
|
|
id: uuid(),
|
|
|
|
deploymentGroup: deploymentGroupId,
|
|
|
|
slug: paramCase(name),
|
|
|
|
name
|
|
|
|
};
|
|
|
|
|
|
|
|
const instance = {
|
|
|
|
id: uuid(),
|
|
|
|
name: camelCase(`${service.slug}_01`),
|
|
|
|
service: service.id,
|
|
|
|
deploymentGroup: deploymentGroupId
|
|
|
|
};
|
|
|
|
|
|
|
|
services.push(service);
|
|
|
|
instances.push(instance);
|
|
|
|
});
|
|
|
|
|
|
|
|
return Promise.resolve(undefined);
|
|
|
|
};
|
|
|
|
|
2017-06-16 17:12:28 +03:00
|
|
|
const scale = options => {
|
|
|
|
const service = getServices({ id: options.serviceId })[0];
|
2017-06-19 15:10:57 +03:00
|
|
|
|
2017-06-16 17:12:28 +03:00
|
|
|
return {
|
|
|
|
scale: [
|
|
|
|
{
|
|
|
|
id: service.id,
|
|
|
|
serviceName: service.name,
|
|
|
|
replicas: 2
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2017-06-26 15:25:46 +03:00
|
|
|
const updateInstancesStatus = (is, status) => {
|
|
|
|
is.forEach(i => {
|
|
|
|
const instance = instances.filter(instance => instance.id === i.id)[0];
|
|
|
|
instance.status = status;
|
|
|
|
});
|
2017-07-06 13:10:10 +03:00
|
|
|
return null;
|
2017-06-26 15:25:46 +03:00
|
|
|
};
|
|
|
|
|
2017-07-06 18:28:05 +03:00
|
|
|
const updateServiceStatus = (ss, status) => {
|
|
|
|
ss.forEach(s => {
|
|
|
|
const service = services.filter(service => service.id === s.id)[0];
|
|
|
|
service.status = status;
|
|
|
|
});
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const updateServiceAndInstancesStatus = (serviceId, serviceStatus, instancesStatus) => {
|
|
|
|
return Promise.all([
|
|
|
|
getServices({ id: serviceId }),
|
|
|
|
getServices({ parentId: serviceId })
|
|
|
|
])
|
2017-07-06 13:10:10 +03:00
|
|
|
.then(services => services.reduce((services, service) =>
|
|
|
|
services.concat(service), []))
|
2017-07-06 18:28:05 +03:00
|
|
|
.then(services => {
|
|
|
|
updateServiceStatus(services, serviceStatus);
|
|
|
|
return Promise.all(
|
|
|
|
services.reduce((instances, service) =>
|
|
|
|
service.instances ? instances.concat(service.instances()) : instances, []))
|
|
|
|
.then(instances => updateInstancesStatus(instances.reduce((is, i) =>
|
|
|
|
is.concat(i), []), instancesStatus))
|
|
|
|
})
|
2017-07-06 13:10:10 +03:00
|
|
|
.then(() => Promise.all([
|
2017-07-06 18:28:05 +03:00
|
|
|
getUnfilteredServices({ id: serviceId }),
|
|
|
|
getUnfilteredServices({ parentId: serviceId })
|
|
|
|
]))
|
2017-07-06 13:10:10 +03:00
|
|
|
.then(services => services.reduce((services, service) =>
|
|
|
|
services.concat(service), []));
|
2017-06-26 15:25:46 +03:00
|
|
|
};
|
|
|
|
|
2017-07-06 18:28:05 +03:00
|
|
|
const handleStatusUpdateRequest = (serviceId,
|
|
|
|
transitionalServiceStatus, transitionalInstancesStatus,
|
|
|
|
serviceStatus, instancesStatus) => {
|
|
|
|
// this is what we need to delay
|
|
|
|
const timeout = setTimeout(() => {
|
|
|
|
updateServiceAndInstancesStatus(serviceId,
|
|
|
|
serviceStatus, instancesStatus);
|
|
|
|
}, 5000);
|
|
|
|
// this is what we'll need to return
|
|
|
|
return updateServiceAndInstancesStatus(serviceId,
|
|
|
|
transitionalServiceStatus, transitionalInstancesStatus);
|
|
|
|
}
|
2017-06-26 15:25:46 +03:00
|
|
|
|
2017-07-06 18:28:05 +03:00
|
|
|
const deleteServices = options => {
|
|
|
|
// service transitional 'DELETING'
|
|
|
|
// instances transitional 'STOPPING'
|
|
|
|
// service 'DELETED'
|
|
|
|
// instances 'DELETED'
|
|
|
|
const deleteService = handleStatusUpdateRequest(options.ids[0],
|
|
|
|
'DELETING', 'STOPPING', 'DELETED', 'DELETED');
|
2017-06-26 15:25:46 +03:00
|
|
|
return Promise.resolve(deleteService);
|
|
|
|
};
|
|
|
|
|
2017-06-19 15:10:57 +03:00
|
|
|
const stopServices = options => {
|
2017-07-06 18:28:05 +03:00
|
|
|
// service transitional 'STOPPING'
|
|
|
|
// instances transitional 'STOPPING'
|
|
|
|
// service 'STOPPED'
|
|
|
|
// instances 'STOPPED'
|
|
|
|
const stopService = handleStatusUpdateRequest(options.ids[0],
|
|
|
|
'STOPPING', 'STOPPING', 'STOPPED', 'STOPPED');
|
2017-06-26 15:25:46 +03:00
|
|
|
return Promise.resolve(stopService);
|
2017-06-19 15:10:57 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
const startServices = options => {
|
2017-07-06 18:28:05 +03:00
|
|
|
// service transitional ...
|
|
|
|
// instances transitional ...
|
|
|
|
// service 'ACTIVE'
|
|
|
|
// instances 'RUNNING'
|
|
|
|
const startService = handleStatusUpdateRequest(options.ids[0],
|
|
|
|
'PROVISIONING', 'PROVISIONING', 'ACTIVE', 'RUNNING');
|
2017-06-26 15:25:46 +03:00
|
|
|
return Promise.resolve(startService);
|
2017-06-19 15:10:57 +03:00
|
|
|
};
|
|
|
|
|
2017-07-06 18:28:05 +03:00
|
|
|
const restartServices = options => {
|
|
|
|
// service transitional 'RESTARTING'
|
|
|
|
// instances transitional 'STOPPING'
|
|
|
|
// service 'ACTIVE'
|
|
|
|
// instances 'RUNNING'
|
|
|
|
const restartService = handleStatusUpdateRequest(options.ids[0],
|
|
|
|
'RESTARTING', 'STOPPING', 'ACTIVE', 'RUNNING');
|
|
|
|
return Promise.resolve(restartService);
|
|
|
|
};
|
|
|
|
|
2017-05-18 21:21:33 +03:00
|
|
|
module.exports = {
|
2017-06-08 00:15:48 +03:00
|
|
|
portal: getPortal,
|
|
|
|
deploymentGroups: getDeploymentGroups,
|
2017-06-16 15:41:30 +03:00
|
|
|
deploymentGroup: query => getDeploymentGroups(query).then(dgs => dgs.shift()),
|
2017-06-08 00:15:48 +03:00
|
|
|
services: getServices,
|
|
|
|
service: query => getServices(query).then(services => services.shift()),
|
|
|
|
instances: getInstances,
|
2017-06-09 07:26:25 +03:00
|
|
|
instance: query => getInstances(query).then(instances => instances.shift()),
|
|
|
|
createDeploymentGroup,
|
|
|
|
provisionManifest: options =>
|
|
|
|
createServicesFromManifest(options).then(() => ({
|
|
|
|
id: uuid(),
|
|
|
|
type: options.type,
|
|
|
|
format: options.format
|
2017-06-16 17:12:28 +03:00
|
|
|
})),
|
|
|
|
deleteServices: (options, request, fn) => fn(null, deleteServices(options)),
|
2017-06-19 15:10:57 +03:00
|
|
|
scale: (options, reguest, fn) => fn(null, scale(options)),
|
|
|
|
restartServices: (options, request, fn) => fn(null, restartServices(options)),
|
|
|
|
stopServices: (options, request, fn) => fn(null, stopServices(options)),
|
|
|
|
startServices: (options, request, fn) => fn(null, startServices(options))
|
2017-05-18 21:21:33 +03:00
|
|
|
};
|