feat(portal-data): instance sub-query, start/delete services

This commit is contained in:
geek 2017-06-08 15:50:12 -05:00 committed by Sérgio Ramos
parent 1e157641b2
commit 3c1763ceb4
3 changed files with 275 additions and 20 deletions

View File

@ -491,10 +491,11 @@ module.exports = class Data extends EventEmitter {
manifest: manifest.raw
};
options.services[service.name] = replicas;
this._dockerCompose.scale(options, (err) => {
this._dockerCompose.scale(options, (err, res) => {
if (err) {
return cb(err);
}
console.log(JSON.stringify(res, null, ' '));
finish();
});
}
@ -592,9 +593,11 @@ module.exports = class Data extends EventEmitter {
VAsync.forEachPipeline({
func: (serviceName, next) => {
const manifestService = manifestServices[serviceName];
const container = provisionRes[serviceName].plan.containers[0];
const clientInstance = {
name: serviceName,
machineId: provisionRes[serviceName].plan.containers[0].id,
machineId: container ? container.id : `${deploymentGroup.name}_${serviceName}_1`,
status: 'CREATED'
};
this.createInstance(clientInstance, (err, createdInstance) => {
@ -698,21 +701,12 @@ module.exports = class Data extends EventEmitter {
return cb(null, null);
}
VAsync.parallel({
funcs: [
(next) => {
this._db.instances.get(service.instance_ids, next);
},
(next) => {
this._db.packages.single({ id: service.package_id }, next);
}
]
}, (err, results) => {
this._db.packages.single({ id: service.package_id }, (err, packages) => {
if (err) {
return cb(err);
}
cb(null, Transform.fromService({ service, instances: results.successes[0], package: results.successes[1] }));
cb(null, Transform.fromService({ service, instances: this._instancesFilter(service.instance_ids), packages }));
});
});
}
@ -749,11 +743,45 @@ module.exports = class Data extends EventEmitter {
}
return cb(null, services.map((service) => {
return Transform.fromService({ service });
return Transform.fromService({ service, instances: this._instancesFilter(service.instance_ids) });
}));
});
}
_instancesFilter (instanceIds) {
return ({ name, machineId, status }) => {
return new Promise((resolve, reject) => {
const query = {
id: this._db.or(instanceIds)
};
if (name) {
query.name = name;
}
if (machineId) {
query.machine_id = machineId;
}
if (status) {
query.status = status;
}
this._db.instances.query(query, (err, instances) => {
if (err) {
return reject(err);
}
if (!instances || !instances.length) {
return resolve([]);
}
resolve(instances.map(Transform.fromInstance));
});
});
};
}
stopServices ({ ids }, cb) {
this._db.services.get(ids, (err, services) => {
if (err) {
@ -799,15 +827,138 @@ module.exports = class Data extends EventEmitter {
}
startServices ({ ids }, cb) {
this._db.services.get(ids, (err, services) => {
if (err) {
return cb(err);
}
if (!services || !services.length) {
return cb();
}
let instanceIds = [];
services.forEach((service) => {
instanceIds = instanceIds.concat(service.instance_ids);
});
VAsync.forEachParallel({
func: (instanceId, next) => {
this._db.instances.get(instanceId, (err, instance) => {
if (err) {
return next(err);
}
const container = this._docker.getContainer(instance.machine_id);
container.start((err) => {
if (err) {
return next(err);
}
this.updateInstance({ id: instance.id, status: 'RUNNING' }, next);
});
});
},
inputs: instanceIds
}, (err, results) => {
if (err) {
return cb(err);
}
this.getServices({ ids }, cb);
});
});
}
restartServices ({ ids }, cb) {
this._db.services.get(ids, (err, services) => {
if (err) {
return cb(err);
}
if (!services || !services.length) {
return cb();
}
let instanceIds = [];
services.forEach((service) => {
instanceIds = instanceIds.concat(service.instance_ids);
});
VAsync.forEachParallel({
func: (instanceId, next) => {
this._db.instances.get(instanceId, (err, instance) => {
if (err) {
return next(err);
}
this.updateInstance({ id: instance.id, status: 'RESTARTING' }, () => {
const container = this._docker.getContainer(instance.machine_id);
container.restart((err) => {
if (err) {
return next(err);
}
this.updateInstance({ id: instance.id, status: 'RUNNING' }, next);
});
});
});
},
inputs: instanceIds
}, (err, results) => {
if (err) {
return cb(err);
}
this.getServices({ ids }, cb);
});
});
}
deleteServices ({ ids }, cb) {
this._db.services.get(ids, (err, services) => {
if (err) {
return cb(err);
}
if (!services || !services.length) {
return cb();
}
let instanceIds = [];
services.forEach((service) => {
instanceIds = instanceIds.concat(service.instance_ids);
});
VAsync.forEachParallel({
func: (instanceId, next) => {
this._db.instances.get(instanceId, (err, instance) => {
if (err) {
return next(err);
}
const container = this._docker.getContainer(instance.machine_id);
// Use force in case the container is running. TODO: should we keep force?
container.remove({ force: true }, (err) => {
if (err) {
return next(err);
}
this.updateInstance({ id: instance.id, status: 'DELETED' }, next);
});
});
},
inputs: instanceIds
}, (err, results) => {
if (err) {
return cb(err);
}
this.getServices({ ids }, cb);
});
});
}

View File

@ -53,7 +53,7 @@ exports.fromService = function ({ service, instances, packages }) {
name: service.name,
slug: service.slug,
environment: service.environment || [],
instances: instances ? instances.map(exports.fromInstance) : [],
instances,
currentMetrics: [],
connections: service.service_dependency_ids,
package: packages ? exports.fromPackage(packages) : {},

View File

@ -691,11 +691,13 @@ describe.skip('scale()', () => {
setTimeout(() => {
data.getDeploymentGroup({ id: deploymentGroup.id }, (err, deploymentGroup) => {
expect(err).to.not.exist();
data.scale({ id: deploymentGroup.services[0].id, replicas: 3 }, (err, version) => {
expect(err).to.not.exist();
expect(version).to.exist();
expect(version.scales[0].replicas).to.equal(3);
done();
deploymentGroup.services().then((deploymentGroupServices) => {
data.scale({ id: deploymentGroupServices[0].id, replicas: 3 }, (err, version) => {
expect(err).to.not.exist();
expect(version).to.exist();
expect(version.scales[0].replicas).to.equal(3);
done();
});
});
});
}, 80000);
@ -739,3 +741,105 @@ describe.skip('stopServices()', () => {
});
});
});
// skipping by default since it takes so long
describe.skip('startServices()', () => {
it('starts all instances of a service', { timeout: 180000 }, (done) => {
const data = new PortalData(internals.options);
data.connect((err) => {
expect(err).to.not.exist();
data.createDeploymentGroup({ name: 'something' }, (err, deploymentGroup) => {
expect(err).to.not.exist();
const clientManifest = {
deploymentGroupId: deploymentGroup.id,
type: 'compose',
format: 'yml',
raw: internals.composeFile
};
data.provisionManifest(clientManifest, (err, manifest) => {
expect(err).to.not.exist();
setTimeout(() => {
data.getDeploymentGroup({ id: deploymentGroup.id }, (err, deploymentGroup) => {
expect(err).to.not.exist();
deploymentGroup.services().then((deploymentGroupServices) => {
data.startServices({ ids: [deploymentGroupServices[0].id] }, (err, services) => {
expect(err).to.not.exist();
expect(services).to.exist();
done();
});
});
});
}, 80000);
});
});
});
});
});
// skipping by default since it takes so long
describe.skip('restartServices()', () => {
it('restarts all instances of a service', { timeout: 180000 }, (done) => {
const data = new PortalData(internals.options);
data.connect((err) => {
expect(err).to.not.exist();
data.createDeploymentGroup({ name: 'something' }, (err, deploymentGroup) => {
expect(err).to.not.exist();
const clientManifest = {
deploymentGroupId: deploymentGroup.id,
type: 'compose',
format: 'yml',
raw: internals.composeFile
};
data.provisionManifest(clientManifest, (err, manifest) => {
expect(err).to.not.exist();
setTimeout(() => {
data.getDeploymentGroup({ id: deploymentGroup.id }, (err, deploymentGroup) => {
expect(err).to.not.exist();
deploymentGroup.services().then((deploymentGroupServices) => {
data.restartServices({ ids: [deploymentGroupServices[0].id] }, (err, services) => {
expect(err).to.not.exist();
expect(services).to.exist();
done();
});
});
});
}, 80000);
});
});
});
});
});
// skipping by default since it takes so long
describe.skip('deleteServices()', () => {
it('deletes all instances of a service', { timeout: 180000 }, (done) => {
const data = new PortalData(internals.options);
data.connect((err) => {
expect(err).to.not.exist();
data.createDeploymentGroup({ name: 'something' }, (err, deploymentGroup) => {
expect(err).to.not.exist();
const clientManifest = {
deploymentGroupId: deploymentGroup.id,
type: 'compose',
format: 'yml',
raw: internals.composeFile
};
data.provisionManifest(clientManifest, (err, manifest) => {
expect(err).to.not.exist();
setTimeout(() => {
data.getDeploymentGroup({ id: deploymentGroup.id }, (err, deploymentGroup) => {
expect(err).to.not.exist();
deploymentGroup.services().then((deploymentGroupServices) => {
data.deleteServices({ ids: [deploymentGroupServices[0].id] }, (err, services) => {
expect(err).to.not.exist();
expect(services).to.exist();
done();
});
});
});
}, 80000);
});
});
});
});
});