1
0
mirror of https://github.com/yldio/copilot.git synced 2024-12-01 07:30:07 +02:00

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 manifest: manifest.raw
}; };
options.services[service.name] = replicas; options.services[service.name] = replicas;
this._dockerCompose.scale(options, (err) => { this._dockerCompose.scale(options, (err, res) => {
if (err) { if (err) {
return cb(err); return cb(err);
} }
console.log(JSON.stringify(res, null, ' '));
finish(); finish();
}); });
} }
@ -592,9 +593,11 @@ module.exports = class Data extends EventEmitter {
VAsync.forEachPipeline({ VAsync.forEachPipeline({
func: (serviceName, next) => { func: (serviceName, next) => {
const manifestService = manifestServices[serviceName]; const manifestService = manifestServices[serviceName];
const container = provisionRes[serviceName].plan.containers[0];
const clientInstance = { const clientInstance = {
name: serviceName, name: serviceName,
machineId: provisionRes[serviceName].plan.containers[0].id, machineId: container ? container.id : `${deploymentGroup.name}_${serviceName}_1`,
status: 'CREATED' status: 'CREATED'
}; };
this.createInstance(clientInstance, (err, createdInstance) => { this.createInstance(clientInstance, (err, createdInstance) => {
@ -698,21 +701,12 @@ module.exports = class Data extends EventEmitter {
return cb(null, null); return cb(null, null);
} }
VAsync.parallel({ this._db.packages.single({ id: service.package_id }, (err, packages) => {
funcs: [
(next) => {
this._db.instances.get(service.instance_ids, next);
},
(next) => {
this._db.packages.single({ id: service.package_id }, next);
}
]
}, (err, results) => {
if (err) { if (err) {
return cb(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 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) { stopServices ({ ids }, cb) {
this._db.services.get(ids, (err, services) => { this._db.services.get(ids, (err, services) => {
if (err) { if (err) {
@ -799,15 +827,138 @@ module.exports = class Data extends EventEmitter {
} }
startServices ({ ids }, cb) { 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) { 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) { 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, name: service.name,
slug: service.slug, slug: service.slug,
environment: service.environment || [], environment: service.environment || [],
instances: instances ? instances.map(exports.fromInstance) : [], instances,
currentMetrics: [], currentMetrics: [],
connections: service.service_dependency_ids, connections: service.service_dependency_ids,
package: packages ? exports.fromPackage(packages) : {}, package: packages ? exports.fromPackage(packages) : {},

View File

@ -691,13 +691,15 @@ describe.skip('scale()', () => {
setTimeout(() => { setTimeout(() => {
data.getDeploymentGroup({ id: deploymentGroup.id }, (err, deploymentGroup) => { data.getDeploymentGroup({ id: deploymentGroup.id }, (err, deploymentGroup) => {
expect(err).to.not.exist(); expect(err).to.not.exist();
data.scale({ id: deploymentGroup.services[0].id, replicas: 3 }, (err, version) => { deploymentGroup.services().then((deploymentGroupServices) => {
data.scale({ id: deploymentGroupServices[0].id, replicas: 3 }, (err, version) => {
expect(err).to.not.exist(); expect(err).to.not.exist();
expect(version).to.exist(); expect(version).to.exist();
expect(version.scales[0].replicas).to.equal(3); expect(version.scales[0].replicas).to.equal(3);
done(); done();
}); });
}); });
});
}, 80000); }, 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);
});
});
});
});
});