Various updates.

This commit is contained in:
Julien Fontanet 2013-07-31 18:50:20 +02:00
parent 35a06a4364
commit 8ae74ee4fe
3 changed files with 314 additions and 265 deletions

View File

@ -592,4 +592,33 @@ Api.fn.xapi = {
return this.xo[match[1] +'s'].get();
},
'vm': {
'pause': function (session, req) {
var p_id = req.params.id;
if (!p_id)
{
throw Api.err.INVALID_PARAMS;
}
var xo = this.xo;
var vm;
return this.checkPermission(session, 'write').then(function () {
return xo.vms.first(p_id);
}).then(function (tmp) {
vm = tmp;
if (!vm)
{
throw Api.err.NO_SUCH_OBJECT;
}
return xo.pools.first(vm.get('pool_uuid'));
}).then(function (pool) {
var xapi = xo.connections[pool.get('uuid')];
return xapi.call('VM.pause', vm.get('ref'));
}).thenResolve(true);
},
},
};

View File

@ -25,7 +25,7 @@ Collection.prototype.model = require('./model');
/**
* Adds new models to this collection.
*/
Collection.prototype.add = function (models) {
Collection.prototype.add = function (models, options) {
var array = true;
if (!_.isArray(models))
{
@ -33,6 +33,9 @@ Collection.prototype.add = function (models) {
array = false;
}
// @todo Temporary mesure, implement “set()” instead.
var replace = !!(options && options.replace);
for (var i = 0, n = models.length; i < n; ++i)
{
var model = models[i];
@ -58,7 +61,7 @@ Collection.prototype.add = function (models) {
}
// Existing models are ignored.
if (this.models[id])
if (!replace && this.models[id])
{
return Q.reject('cannot add existing models!');
}

543
src/xo.js
View File

@ -228,6 +228,280 @@ var VDIs = Collection.extend({
//////////////////////////////////////////////////////////////////////
// @todo Really ugly.
function refresh(xo, xapi)
{
var get_records = function (classes) {
var promises = [];
for (var i = 0, n = classes.length; i < n; i++)
{
!function (klass) {
promises.push(
xapi.call(klass +'.get_all_records')
.fail(function (error) {
console.error(klass, error);
return {};
})
);
}(classes[i]);
}
return Q.all(promises);
};
return get_records([
// Main classes.
'pool',
'host',
'VM',
'network',
'SR',
'VDI',
'PIF',
'VIF',
// Associated classes (e.g. metrics).
'console',
'crashdump',
'DR_task',
'host_cpu',
'host_crashdump',
'host_metrics',
'host_patch',
'message',
'PBD',
'PCI',
'PGPU',
'PIF_metrics',
'VBD',
'VGPU',
'VIF_metrics',
'VM_appliance',
'VM_metrics',
'VM_guest_metrics',
'VMPP',
'VTPM',
]).spread(function (
pools,
hosts,
vms,
networks,
srs,
vdis,
pifs,
vifs,
consoles,
crashdumps,
dr_tasks,
host_cpus,
host_crashdumps,
host_metrics,
host_patches,
messages,
pbds,
pcis,
pgpus,
pif_metrics,
vbds,
vgpus,
vif_metrics,
vm_appliances,
vm_metrics,
vm_guest_metrics,
vmpps,
vtpms
) {
// Special case for pools.
pools = _.values(pools);
var pool_uuid = pools[0].id = pools[0].uuid;
xo.connections[pool_uuid] = xapi;
// @todo Remove: security concerns.
pools[0].sessionId = xapi.sessionId;
var resolve = function (model, collection, props, include) {
/* jshint laxbreak: true */
if (!_.isArray(props))
{
props = [props];
}
var helper;
if (include)
{
helper = function (ref) {
return collection[ref] || null;
};
}
else
{
helper = function (ref) {
var model = collection[ref];
return model && model.uuid || null;
};
}
var map = function (list, iterator) {
var result = _.isArray(list) ? [] : {};
_.each(list, function (value, key) {
result[key] = iterator(value);
});
return result;
};
for (var i = 0, n = props.length; i < n; ++i)
{
var prop = props[i];
var ref = model[prop];
model[prop] = _.isArray(ref)
? map(ref, helper)
: helper(ref);
}
};
// @todo Messages are linked differently.
messages = _.groupBy(messages, 'obj_uuid');
// @todo Cast numerical/boolean properties to correct types.
// Resolves dependencies.
//
// 1. Associated objects are included.
// 2. Linked objects are relinked using their uuid instead of
// their reference.
_.each(pools, function (pool) {
// @todo Blobs?
resolve(pool, srs, [
'crash_dump_SR',
'default_SR',
'suspend_image_SR',
]);
resolve(pool, hosts, 'master');
resolve(pool, vdis, [
'metadata_VDIs',
'redo_log_vdi',
]);
});
_.each(hosts, function (host) {
// @todo Blobs?
resolve(host, srs, [
'crash_dump_sr',
'local_cache_sr',
'suspend_image_SR',
]);
resolve(host, host_crashdumps, 'host_crashdumps', true);
resolve(host, host_cpus, 'host_CPUs', true);
resolve(host, host_metrics, 'metrics', true);
resolve(host, host_patches, 'patches', true);
resolve(host, pbds, 'PBDs', true);
resolve(host, pcis, 'PCIs', true);
resolve(host, pgpus, 'PGPUs', true);
resolve(host, pifs, 'PIFs');
resolve(host, vms, 'resident_VMs');
});
_.each(vms, function (vm) {
// @todo Blobs?
resolve(vm, hosts, [
'affinity',
'resident_on',
]);
resolve(vm, vm_appliances, 'appliance', true);
resolve(vm, pcis, 'attached_PCIs', true);
resolve(vm, vms, [
'children', // Snapshots?
'parent',
'snapshot_of',
]);
resolve(vm, consoles, 'consoles', true);
resolve(vm, crashdumps, 'crash_dumps', true);
resolve(vm, vm_guest_metrics, 'guest_metrics', true);
vm.messages = messages[vm.uuid] || []; // @todo
resolve(vm, vm_metrics, 'metrics', true);
resolve(vm, vmpps, 'protection_policy', true);
resolve(vm, srs, 'suspend_SR');
resolve(vm, vdis, 'suspend_VDI');
resolve(vm, vbds, 'VBDs');
resolve(vm, vgpus, 'VGPUs');
resolve(vm, vifs, 'VIFs');
resolve(vm, vtpms, 'VTPMs');
});
_.each(networks, function (network) {
// @todo Blobs?
resolve(network, pifs, 'PIFs');
resolve(network, vifs, 'VIFs');
});
_.each(srs, function (sr) {
// @todo Blobs?
resolve(sr, dr_tasks, 'introduced_by'); // @todo.
resolve(sr, pbds, 'PBDs');
resolve(sr, vdis, 'VDIs');
});
_.each(vdis, function (vdi) {
resolve(vdi, crashdumps, 'crash_dumps', true);
resolve(vdi, pools, 'metadata_of_pool');
resolve(vdi, vdis, [
'parent',
'snapshot_of',
'snapshots',
]);
resolve(vdi, srs, 'SR');
resolve(vdi, vbds, 'VBDs');
});
_.each(pifs, function (pif) {
// @todo Bonds, tunnels & VLANs.
resolve(pif, hosts, 'host');
resolve(pif, pif_metrics, 'metrics');
resolve(pif, networks, 'network');
});
_.each(vifs, function (vif) {
resolve(vif, vif_metrics, 'metrics');
resolve(vif, networks, 'network');
resolve(vif, vms, 'VM');
});
// Normalizes the collections.
//
// 1. The collection is converted to an array.
// 2. For each object, an identifier based on its uuid is
// created.
var normalize = function (items) {
return _.map(items, function (item, ref) {
item.id = item.uuid;
item.pool_uuid = pool_uuid;
item.ref = ref;
return item;
});
};
var opts = {
'replace': true,
};
return Q.all([
xo.pools.add(pools, opts), // Special case.
xo.hosts.add(normalize(hosts), opts),
xo.vms.add(normalize(vms), opts),
xo.networks.add(normalize(networks), opts),
xo.srs.add(normalize(srs), opts),
xo.vdis.add(normalize(vdis), opts),
]);
});
}
function Xo()
{
if ( !(this instanceof Xo) )
@ -248,271 +522,14 @@ function Xo()
xo.servers.on('add', function (servers) {
_.each(servers, function (server) {
var xapi = new Xapi(server.host);
xo.connections[server.id] = xapi;
xapi.connect(server.username, server.password).then(function () {
var get_records = function (classes) {
var promises = [];
for (var i = 0, n = classes.length; i < n; i++)
{
!function (klass) {
promises.push(
xapi.call(klass +'.get_all_records')
.fail(function (error) {
console.error(klass, error);
return {};
})
);
}(classes[i]);
}
return Q.all(promises);
};
return get_records([
// Main classes.
'pool',
'host',
'VM',
'network',
'SR',
'VDI',
'PIF',
'VIF',
// Associated classes (e.g. metrics).
'console',
'crashdump',
'DR_task',
'host_cpu',
'host_crashdump',
'host_metrics',
'host_patch',
'message',
'PBD',
'PCI',
'PGPU',
'PIF_metrics',
'VBD',
'VGPU',
'VIF_metrics',
'VM_appliance',
'VM_metrics',
'VM_guest_metrics',
'VMPP',
'VTPM',
]);
}).spread(function (
pools,
hosts,
vms,
networks,
srs,
vdis,
pifs,
vifs,
consoles,
crashdumps,
dr_tasks,
host_cpus,
host_crashdumps,
host_metrics,
host_patches,
messages,
pbds,
pcis,
pgpus,
pif_metrics,
vbds,
vgpus,
vif_metrics,
vm_appliances,
vm_metrics,
vm_guest_metrics,
vmpps,
vtpms
) {
// Special case for pools.
pools = _.values(pools);
var pool_uuid = pools[0].id = pools[0].uuid;
// @todo Remove: security concerns.
pools[0].sessionId = xapi.sessionId;
var resolve = function (model, collection, props, include) {
/* jshint laxbreak: true */
if (!_.isArray(props))
{
props = [props];
}
var helper;
if (include)
{
helper = function (ref) {
return collection[ref] || null;
};
}
else
{
helper = function (ref) {
var model = collection[ref];
return model && model.uuid || null;
};
}
var map = function (list, iterator) {
var result = _.isArray(list) ? [] : {};
_.each(list, function (value, key) {
result[key] = iterator(value);
});
return result;
};
for (var i = 0, n = props.length; i < n; ++i)
{
var prop = props[i];
var ref = model[prop];
model[prop] = _.isArray(ref)
? map(ref, helper)
: helper(ref);
}
};
// @todo Messages are linked differently.
messages = _.groupBy(messages, 'obj_uuid');
// @todo Cast numerical/boolean properties to correct types.
// Resolves dependencies.
//
// 1. Associated objects are included.
// 2. Linked objects are relinked using their uuid instead of
// their reference.
_.each(pools, function (pool) {
// @todo Blobs?
resolve(pool, srs, [
'crash_dump_SR',
'default_SR',
'suspend_image_SR',
]);
resolve(pool, hosts, 'master');
resolve(pool, vdis, [
'metadata_VDIs',
'redo_log_vdi',
]);
});
_.each(hosts, function (host) {
// @todo Blobs?
resolve(host, srs, [
'crash_dump_sr',
'local_cache_sr',
'suspend_image_SR',
]);
resolve(host, host_crashdumps, 'host_crashdumps', true);
resolve(host, host_cpus, 'host_CPUs', true);
resolve(host, host_metrics, 'metrics', true);
resolve(host, host_patches, 'patches', true);
resolve(host, pbds, 'PBDs', true);
resolve(host, pcis, 'PCIs', true);
resolve(host, pgpus, 'PGPUs', true);
resolve(host, pifs, 'PIFs');
resolve(host, vms, 'resident_VMs');
});
_.each(vms, function (vm) {
// @todo Blobs?
resolve(vm, hosts, [
'affinity',
'resident_on',
]);
resolve(vm, vm_appliances, 'appliance', true);
resolve(vm, pcis, 'attached_PCIs', true);
resolve(vm, vms, [
'children', // Snapshots?
'parent',
'snapshot_of',
]);
resolve(vm, consoles, 'consoles', true);
resolve(vm, crashdumps, 'crash_dumps', true);
resolve(vm, vm_guest_metrics, 'guest_metrics', true);
vm.messages = messages[vm.uuid] || []; // @todo
resolve(vm, vm_metrics, 'metrics', true);
resolve(vm, vmpps, 'protection_policy', true);
resolve(vm, srs, 'suspend_SR');
resolve(vm, vdis, 'suspend_VDI');
resolve(vm, vbds, 'VBDs');
resolve(vm, vgpus, 'VGPUs');
resolve(vm, vifs, 'VIFs');
resolve(vm, vtpms, 'VTPMs');
});
_.each(networks, function (network) {
// @todo Blobs?
resolve(network, pifs, 'PIFs');
resolve(network, vifs, 'VIFs');
});
_.each(srs, function (sr) {
// @todo Blobs?
resolve(sr, dr_tasks, 'introduced_by'); // @todo.
resolve(sr, pbds, 'PBDs');
resolve(sr, vdis, 'VDIs');
});
_.each(vdis, function (vdi) {
resolve(vdi, crashdumps, 'crash_dumps', true);
resolve(vdi, pools, 'metadata_of_pool');
resolve(vdi, vdis, [
'parent',
'snapshot_of',
'snapshots',
]);
resolve(vdi, srs, 'SR');
resolve(vdi, vbds, 'VBDs');
});
_.each(pifs, function (pif) {
// @todo Bonds, tunnels & VLANs.
resolve(pif, hosts, 'host');
resolve(pif, pif_metrics, 'metrics');
resolve(pif, networks, 'network');
});
_.each(vifs, function (vif) {
resolve(vif, vif_metrics, 'metrics');
resolve(vif, networks, 'network');
resolve(vif, vms, 'VM');
});
// Normalizes the collections.
//
// 1. The collection is converted to an array.
// 2. For each object, an identifier based on its uuid is
// created.
var normalize = function (items) {
return _.map(items, function (item) {
item.id = item.uuid;
item.pool_uuid = pool_uuid;
return item;
});
};
return Q.all([
xo.pools.add(pools), // Special case.
xo.hosts.add(normalize(hosts)),
xo.vms.add(normalize(vms)),
xo.networks.add(normalize(networks)),
xo.srs.add(normalize(srs)),
xo.vdis.add(normalize(vdis)),
]);
// @todo Use events.
!function helper() {
refresh(xo, xapi).then(function () {
setTimeout(helper, 5000);
}).done();
}();
}).done();
});
});