2017-05-11 23:18:51 +03:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const Hoek = require('hoek');
|
|
|
|
const Penseur = require('penseur');
|
2017-05-16 18:54:39 +03:00
|
|
|
const DCClient = require('docker-compose-client');
|
2017-05-27 19:35:38 +03:00
|
|
|
const VAsync = require('vasync');
|
|
|
|
const Transform = require('./transform');
|
|
|
|
|
2017-05-11 23:18:51 +03:00
|
|
|
|
|
|
|
const internals = {
|
|
|
|
defaults: {
|
2017-05-25 23:03:39 +03:00
|
|
|
name: 'portal',
|
|
|
|
db: {
|
|
|
|
test: false
|
|
|
|
},
|
|
|
|
dockerHost: 'tcp://0.0.0.0:4242'
|
|
|
|
},
|
2017-05-27 19:35:38 +03:00
|
|
|
tables: {
|
|
|
|
'portals': { id: { type: 'uuid' } },
|
|
|
|
'datacenters': { id: { type: 'uuid' } },
|
|
|
|
'deployment_groups': { id: { type: 'uuid' } },
|
|
|
|
'versions': { id: { type: 'uuid' } },
|
|
|
|
'manifests': { id: { type: 'uuid' } },
|
|
|
|
'services': { id: { type: 'uuid' } },
|
|
|
|
'packages': { id: { type: 'uuid' } },
|
|
|
|
'instances': { id: { type: 'uuid' } }
|
|
|
|
}
|
2017-05-11 23:18:51 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = class Data {
|
2017-05-25 23:03:39 +03:00
|
|
|
constructor (options) {
|
2017-05-11 23:18:51 +03:00
|
|
|
const settings = Hoek.applyToDefaults(options || {}, internals.defaults);
|
|
|
|
|
|
|
|
// Penseur will assert that the options are correct
|
2017-05-25 23:03:39 +03:00
|
|
|
this._db = new Penseur.Db(settings.name, settings.db);
|
2017-05-16 18:54:39 +03:00
|
|
|
this._docker = new DCClient(settings.dockerHost);
|
|
|
|
}
|
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
connect (cb) {
|
|
|
|
this._db.establish(internals.tables, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// portals
|
|
|
|
|
|
|
|
createPortal (clientPortal, cb) {
|
|
|
|
const portal = Transform.toPortal(clientPortal);
|
|
|
|
this._db.portals.insert(portal, (err, key) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
portal.id = key;
|
|
|
|
cb(null, Transform.fromPortal({ portal }));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getPortal (cb) {
|
|
|
|
this._db.portals.all((err, portals) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
const portal = portals[0];
|
|
|
|
VAsync.parallel({
|
|
|
|
funcs: [
|
|
|
|
(next) => {
|
|
|
|
this.getDatacenter({ id: portal.datacenter_id }, next);
|
|
|
|
},
|
|
|
|
(next) => {
|
2017-05-31 01:08:06 +03:00
|
|
|
this.getDeploymentGroups({ ids: portal.deployment_group_ids }, next);
|
2017-05-27 19:35:38 +03:00
|
|
|
}
|
|
|
|
]
|
|
|
|
}, (err, results) => {
|
2017-05-25 23:03:39 +03:00
|
|
|
if (err) {
|
2017-05-27 19:35:38 +03:00
|
|
|
return cb(err);
|
2017-05-25 23:03:39 +03:00
|
|
|
}
|
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
cb(null, Transform.fromPortal({ portal, datacenter: results.successes[0], deploymentGroups: results.successes[1] }));
|
2017-05-25 23:03:39 +03:00
|
|
|
});
|
|
|
|
});
|
2017-05-16 18:54:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
// datacenters
|
2017-05-11 23:18:51 +03:00
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
createDatacenter (datacenter, cb) {
|
|
|
|
this._db.datacenters.insert(datacenter, (err, key) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
2017-05-11 23:18:51 +03:00
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
datacenter.id = key;
|
|
|
|
cb(null, datacenter);
|
|
|
|
});
|
2017-05-11 23:18:51 +03:00
|
|
|
}
|
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
getDatacenters (cb) {
|
|
|
|
this._db.datacenters.all(cb);
|
2017-05-11 23:18:51 +03:00
|
|
|
}
|
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
getDatacenter ({ id, region }, cb) {
|
|
|
|
Hoek.assert(id || region, 'id or region are required to retrieve a datacenter');
|
2017-05-11 23:18:51 +03:00
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
if (region) {
|
|
|
|
return this._db.datacenters.single({ region }, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._db.datacenters.single({ id }, cb);
|
2017-05-11 23:18:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
// deployment_groups
|
|
|
|
|
2017-05-31 01:08:06 +03:00
|
|
|
createDeploymentGroup (clientDeploymentGroup, cb) {
|
2017-05-27 19:35:38 +03:00
|
|
|
// trigger deployment
|
|
|
|
// create deployment queue (we should think about what is a deployment queue)
|
|
|
|
// create the ConvergencePlans
|
|
|
|
// create a DeploymentPlan
|
|
|
|
// create a Version
|
|
|
|
// update the DeploymentGroup
|
|
|
|
|
2017-05-31 01:08:06 +03:00
|
|
|
const deploymentGroup = Transform.toDeploymentGroup(clientDeploymentGroup);
|
|
|
|
this._db.deployment_groups.insert(deploymentGroup, (err, key) => {
|
2017-05-27 19:35:38 +03:00
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
2017-05-31 01:08:06 +03:00
|
|
|
deploymentGroup.id = key;
|
|
|
|
cb(null, Transform.fromDeploymentGroup(deploymentGroup));
|
2017-05-11 23:18:51 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
updateDeploymentGroup ({ id, name }, cb) {
|
|
|
|
this._db.deployment_groups.update(id, { name }, (err) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
2017-05-11 23:18:51 +03:00
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
cb(null, Transform.fromDeploymentGroup({ id, name }));
|
|
|
|
});
|
2017-05-12 22:59:37 +03:00
|
|
|
}
|
|
|
|
|
2017-05-31 01:08:06 +03:00
|
|
|
getDeploymentGroups ({ ids, name, slug }, cb) {
|
|
|
|
const finish = (err, deploymentGroups) => {
|
2017-05-27 19:35:38 +03:00
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
2017-05-16 18:54:39 +03:00
|
|
|
}
|
2017-05-11 23:18:51 +03:00
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
deploymentGroups = deploymentGroups || [];
|
|
|
|
cb(null, deploymentGroups.map(Transform.fromDeploymentGroup));
|
2017-05-31 01:08:06 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
if (ids) {
|
|
|
|
return this._db.deployment_groups.get(ids, finish);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name) {
|
|
|
|
return this._db.deployment_groups.query({ name }, finish);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._db.deployment_groups.query({ slug }, finish);
|
2017-05-11 23:18:51 +03:00
|
|
|
}
|
2017-05-12 22:59:37 +03:00
|
|
|
|
2017-05-31 01:08:06 +03:00
|
|
|
getDeploymentGroup (query, cb) {
|
|
|
|
this._db.deployment_groups.single(query, (err, deploymentGroup) => {
|
2017-05-27 19:35:38 +03:00
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(null, Transform.fromDeploymentGroup(deploymentGroup || {}));
|
|
|
|
});
|
2017-05-16 18:54:39 +03:00
|
|
|
}
|
2017-05-11 23:18:51 +03:00
|
|
|
|
|
|
|
|
2017-05-27 19:35:38 +03:00
|
|
|
// versions
|
|
|
|
|
|
|
|
createVersion (clientVersion, cb) {
|
2017-05-31 01:08:06 +03:00
|
|
|
Hoek.assert(clientVersion && clientVersion.manifestId, 'manifestId is required');
|
|
|
|
|
|
|
|
// go get the manifest to find the deployment group id so we can update it
|
|
|
|
this.getManifest({ id: clientVersion.manifestId }, (err, manifest) => {
|
2017-05-27 19:35:38 +03:00
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
2017-05-16 18:54:39 +03:00
|
|
|
}
|
2017-05-12 22:59:37 +03:00
|
|
|
|
2017-05-31 01:08:06 +03:00
|
|
|
if (!manifest) {
|
|
|
|
return cb(new Error('manifest not found for version'));
|
|
|
|
}
|
|
|
|
|
|
|
|
const version = Transform.toVersion(clientVersion);
|
|
|
|
this._db.versions.insert(version, (err, key) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._db.deployment_groups.update(manifest.deploymentGroupId, { history_version_ids: this._db.append(key) }, (err) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
version.id = key;
|
|
|
|
cb(null, Transform.fromVersion(version));
|
|
|
|
});
|
|
|
|
});
|
2017-05-11 23:18:51 +03:00
|
|
|
});
|
|
|
|
}
|
2017-05-12 22:59:37 +03:00
|
|
|
|
2017-05-31 01:08:06 +03:00
|
|
|
getVersion ({ id, manifestId }, cb) {
|
|
|
|
const query = id ? { id } : { manifest_id: manifestId };
|
|
|
|
this._db.versions.single(query, (err, version) => {
|
2017-05-27 19:35:38 +03:00
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(null, Transform.fromVersion(version));
|
|
|
|
});
|
2017-05-12 22:59:37 +03:00
|
|
|
}
|
2017-05-31 01:08:06 +03:00
|
|
|
|
|
|
|
getVersions ({ manifestId, deploymentGroupId }, cb) {
|
|
|
|
const finish = (err, versions) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
versions = versions || [];
|
|
|
|
cb(null, versions.map(Transform.fromVersion));
|
|
|
|
};
|
|
|
|
|
|
|
|
if (manifestId) {
|
|
|
|
return this._db.versions.query({ manifest_id: manifestId }, finish);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.getDeploymentGroup({ id: deploymentGroupId }, (err, deploymentGroup) => {
|
|
|
|
if (err) {
|
|
|
|
return finish(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._db.versions.get(deploymentGroup.history, finish);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// manifests
|
|
|
|
|
|
|
|
provisionManifest (clientManifest, cb) {
|
|
|
|
this._db.manifests.insert(Transform.toManifest(clientManifest), (err, key) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.getManifest({ id: key }, cb);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getManifest ({ id }, cb) {
|
|
|
|
this._db.manifests.single({ id }, (err, manifest) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(null, Transform.fromManifest(manifest || {}));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getManifests ({ type, deploymentGroupId }, cb) {
|
|
|
|
const query = type ? { type } : { deployment_group_id: deploymentGroupId };
|
|
|
|
this._db.manifests.query(query, (err, manifests) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
manifests = manifests || [];
|
|
|
|
cb(null, manifests.map(Transform.fromManifest));
|
|
|
|
});
|
|
|
|
}
|
2017-05-31 22:27:53 +03:00
|
|
|
|
|
|
|
|
|
|
|
// services
|
|
|
|
|
|
|
|
createService (clientService, cb) {
|
|
|
|
this._db.services.insert(Transform.toService(clientService), (err, key) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.getService({ id: key }, cb);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getService ({ id, hash }, cb) {
|
|
|
|
const query = id ? { id } : { version_hash: hash };
|
|
|
|
this._db.services.single(query, (err, service) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
VAsync.parallel({
|
|
|
|
funcs: [
|
|
|
|
(next) => {
|
|
|
|
this._db.instances.get(service.instance_ids, next);
|
|
|
|
},
|
|
|
|
(next) => {
|
|
|
|
this._db.packages.single({ id: service.package_id }, next);
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}, (err, results) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(null, Transform.fromService({ service, instances: results.successes[0], package: results.successes[1] }));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: get services with join/merge
|
|
|
|
|
|
|
|
|
|
|
|
// instances
|
|
|
|
|
|
|
|
createInstance (clientInstance, cb) {
|
|
|
|
this._db.instances.insert(Transform.toInstance(clientInstance), (err, key) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
clientInstance.id = key;
|
|
|
|
cb(null, clientInstance);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getInstance ({ id }, cb) {
|
|
|
|
this._db.instances.single({ id }, (err, instance) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(null, instance ? Transform.fromInstance(instance) : {});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// packages
|
|
|
|
|
|
|
|
createPackage (clientPackage, cb) {
|
|
|
|
this._db.packages.insert(Transform.toPackage(clientPackage), (err, key) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
clientPackage.id = key;
|
|
|
|
cb(null, clientPackage);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getPackage ({ id }, cb) {
|
|
|
|
this._db.packages.single({ id }, (err, dbPackage) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(null, dbPackage ? Transform.fromPackage(dbPackage) : {});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getPackages ({ name, type }, cb) {
|
|
|
|
const query = name ? { name } : { type };
|
|
|
|
this._db.packages.query(query, (err, dbPackages) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(null, dbPackages ? dbPackages.map(Transform.fromPackage) : []);
|
|
|
|
});
|
|
|
|
}
|
2017-05-11 23:18:51 +03:00
|
|
|
};
|