Properly remove objects for which xo.id !== xapi.$id
.
This commit is contained in:
parent
b55accd76f
commit
5ee11c7b6b
@ -51,13 +51,13 @@ function checkSelf ({ id }, permission) {
|
|||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
const checkAuthorizationByTypes = {
|
const checkAuthorizationByTypes = {
|
||||||
host: or(checkSelf, checkMember('$poolId')),
|
host: or(checkSelf, checkMember('$pool')),
|
||||||
|
|
||||||
message: checkMember('$object'),
|
message: checkMember('$object'),
|
||||||
|
|
||||||
network: or(checkSelf, checkMember('$poolId')),
|
network: or(checkSelf, checkMember('$pool')),
|
||||||
|
|
||||||
SR: or(checkSelf, checkMember('$poolId')),
|
SR: or(checkSelf, checkMember('$pool')),
|
||||||
|
|
||||||
task: checkMember('$host'),
|
task: checkMember('$host'),
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import {parseSize} from '../utils'
|
|||||||
export async function create ({name, size, sr}) {
|
export async function create ({name, size, sr}) {
|
||||||
const vdi = await this.getXAPI(sr).createVdi(parseSize(size), {
|
const vdi = await this.getXAPI(sr).createVdi(parseSize(size), {
|
||||||
name_label: name,
|
name_label: name,
|
||||||
sr: sr.id
|
sr: sr._xapiId
|
||||||
})
|
})
|
||||||
return vdi.$id
|
return vdi.$id
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export async function register ({vm}) {
|
export async function register ({vm}) {
|
||||||
await this.getXAPI(vm).registerDockerContainer(vm.id)
|
await this.getXAPI(vm).registerDockerContainer(vm._xapiId)
|
||||||
}
|
}
|
||||||
register.permission = 'admin'
|
register.permission = 'admin'
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ register.resolve = {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
export async function deregister ({vm}) {
|
export async function deregister ({vm}) {
|
||||||
await this.getXAPI(vm).unregisterDockerContainer(vm.id)
|
await this.getXAPI(vm).unregisterDockerContainer(vm._xapiId)
|
||||||
}
|
}
|
||||||
deregister.permission = 'admin'
|
deregister.permission = 'admin'
|
||||||
|
|
||||||
@ -33,23 +33,23 @@ deregister.resolve = {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
export async function start ({vm, container}) {
|
export async function start ({vm, container}) {
|
||||||
await this.getXAPI(vm).startDockerContainer(vm.id, container)
|
await this.getXAPI(vm).startDockerContainer(vm._xapiId, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function stop ({vm, container}) {
|
export async function stop ({vm, container}) {
|
||||||
await this.getXAPI(vm).stopDockerContainer(vm.id, container)
|
await this.getXAPI(vm).stopDockerContainer(vm._xapiId, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function restart ({vm, container}) {
|
export async function restart ({vm, container}) {
|
||||||
await this.getXAPI(vm).restartDockerContainer(vm.id, container)
|
await this.getXAPI(vm).restartDockerContainer(vm._xapiId, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function pause ({vm, container}) {
|
export async function pause ({vm, container}) {
|
||||||
await this.getXAPI(vm).pauseDockerContainer(vm.id, container)
|
await this.getXAPI(vm).pauseDockerContainer(vm._xapiId, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function unpause ({vm, container}) {
|
export async function unpause ({vm, container}) {
|
||||||
await this.getXAPI(vm).unpauseDockerContainer(vm.id, container)
|
await this.getXAPI(vm).unpauseDockerContainer(vm._xapiId, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let fn of [start, stop, restart, pause, unpause]) {
|
for (let fn of [start, stop, restart, pause, unpause]) {
|
||||||
|
@ -6,23 +6,18 @@ endsWith = require 'lodash.endswith'
|
|||||||
got = require('got')
|
got = require('got')
|
||||||
startsWith = require 'lodash.startswith'
|
startsWith = require 'lodash.startswith'
|
||||||
{coroutine: $coroutine} = require 'bluebird'
|
{coroutine: $coroutine} = require 'bluebird'
|
||||||
{parseXml, promisify} = require '../utils'
|
{
|
||||||
|
extractProperty,
|
||||||
|
parseXml,
|
||||||
|
promisify
|
||||||
|
} = require '../utils'
|
||||||
|
|
||||||
#=====================================================================
|
#=====================================================================
|
||||||
|
|
||||||
set = $coroutine (params) ->
|
set = (params) ->
|
||||||
{host} = params
|
host = extractProperty(params, 'host')
|
||||||
xapi = @getXAPI host
|
|
||||||
|
|
||||||
for param, field of {
|
return @getXAPI(host).setHostProperties(host._xapiId, params)
|
||||||
'name_label'
|
|
||||||
'name_description'
|
|
||||||
}
|
|
||||||
continue unless param of params
|
|
||||||
|
|
||||||
yield xapi.call "host.set_#{field}", host.ref, params[param]
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
set.description = 'changes the properties of an host'
|
set.description = 'changes the properties of an host'
|
||||||
|
|
||||||
@ -43,18 +38,19 @@ exports.set = set
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
restart = $coroutine ({host}) ->
|
# FIXME: set force to false per default when correctly implemented in
|
||||||
xapi = @getXAPI host
|
# UI.
|
||||||
|
restart = ({host, force = true}) ->
|
||||||
yield xapi.call 'host.disable', host.ref
|
return @getXAPI(host).rebootHost(host._xapiId, force)
|
||||||
yield xapi.call 'host.reboot', host.ref
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
restart.description = 'restart the host'
|
restart.description = 'restart the host'
|
||||||
|
|
||||||
restart.params = {
|
restart.params = {
|
||||||
id: { type: 'string' }
|
id: { type: 'string' },
|
||||||
|
force: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
restart.resolve = {
|
restart.resolve = {
|
||||||
@ -65,12 +61,8 @@ exports.restart = restart
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
restartAgent = $coroutine ({host}) ->
|
restartAgent = ({host}) ->
|
||||||
xapi = @getXAPI host
|
return @getXAPI(host).restartHostAgent(host._xapiId)
|
||||||
|
|
||||||
yield xapi.call 'host.restart_agent', host.ref
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
restartAgent.description = 'restart the Xen agent on the host'
|
restartAgent.description = 'restart the Xen agent on the host'
|
||||||
|
|
||||||
@ -79,7 +71,7 @@ restartAgent.params = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
restartAgent.resolve = {
|
restartAgent.resolve = {
|
||||||
host: ['id', 'host', 'operate'],
|
host: ['id', 'host', 'administrate'],
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO camel case
|
# TODO camel case
|
||||||
@ -87,12 +79,8 @@ exports.restart_agent = restartAgent
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
start = $coroutine ({host}) ->
|
start = ({host}) ->
|
||||||
xapi = @getXAPI host
|
return @getXAPI(host).powerOnHost(host._xapiId)
|
||||||
|
|
||||||
yield xapi.call 'host.power_on', host.ref
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
start.description = 'start the host'
|
start.description = 'start the host'
|
||||||
|
|
||||||
@ -108,13 +96,8 @@ exports.start = start
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
stop = $coroutine ({host}) ->
|
stop = ({host}) ->
|
||||||
xapi = @getXAPI host
|
return @getXAPI(host).shutdownHost(host._xapiId)
|
||||||
|
|
||||||
yield xapi.call 'host.disable', host.ref
|
|
||||||
yield xapi.call 'host.shutdown', host.ref
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
stop.description = 'stop the host'
|
stop.description = 'stop the host'
|
||||||
|
|
||||||
@ -130,12 +113,8 @@ exports.stop = stop
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
detach = $coroutine ({host}) ->
|
detach = ({host}) ->
|
||||||
xapi = @getXAPI host
|
return @getXAPI(host).ejectHostFromPool(host._xapiId)
|
||||||
|
|
||||||
yield xapi.call 'pool.eject', host.ref
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
detach.description = 'eject the host of a pool'
|
detach.description = 'eject the host of a pool'
|
||||||
|
|
||||||
@ -151,12 +130,8 @@ exports.detach = detach
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
enable = $coroutine ({host}) ->
|
enable = ({host}) ->
|
||||||
xapi = @getXAPI host
|
return @getXAPI(host).enableHost(host._xapiId)
|
||||||
|
|
||||||
yield xapi.call 'host.enable', host.ref
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
enable.description = 'enable to create VM on the host'
|
enable.description = 'enable to create VM on the host'
|
||||||
|
|
||||||
@ -172,12 +147,8 @@ exports.enable = enable
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
disable = $coroutine ({host}) ->
|
disable = ({host}) ->
|
||||||
xapi = @getXAPI host
|
return @getXAPI(host).disableHost(host._xapiId)
|
||||||
|
|
||||||
yield xapi.call 'host.disable', host.ref
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
disable.description = 'disable to create VM on the hsot'
|
disable.description = 'disable to create VM on the hsot'
|
||||||
|
|
||||||
@ -193,6 +164,7 @@ exports.disable = disable
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
|
# TODO: to test and to fix.
|
||||||
createNetwork = $coroutine ({host, name, description, pif, mtu, vlan}) ->
|
createNetwork = $coroutine ({host, name, description, pif, mtu, vlan}) ->
|
||||||
xapi = @getXAPI host
|
xapi = @getXAPI host
|
||||||
|
|
||||||
@ -208,7 +180,7 @@ createNetwork = $coroutine ({host, name, description, pif, mtu, vlan}) ->
|
|||||||
if pif?
|
if pif?
|
||||||
vlan = vlan ? '0'
|
vlan = vlan ? '0'
|
||||||
pif = @getObject pif, 'PIF'
|
pif = @getObject pif, 'PIF'
|
||||||
yield xapi.call 'pool.create_VLAN_from_PIF', pif.ref, network_ref, vlan
|
yield xapi.call 'pool.create_VLAN_from_PIF', pif._xapiRef, network_ref, vlan
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -233,7 +205,7 @@ exports.createNetwork = createNetwork
|
|||||||
# Throws an error if the host is not running the latest XS version
|
# Throws an error if the host is not running the latest XS version
|
||||||
|
|
||||||
listMissingPatches = ({host}) ->
|
listMissingPatches = ({host}) ->
|
||||||
return @getXAPI(host).listMissingPoolPatchesOnHost(host.id)
|
return @getXAPI(host).listMissingPoolPatchesOnHost(host._xapiId)
|
||||||
|
|
||||||
listMissingPatches.params = {
|
listMissingPatches.params = {
|
||||||
host: { type: 'string' }
|
host: { type: 'string' }
|
||||||
@ -250,7 +222,7 @@ listMissingPatches.description = 'return an array of missing new patches in the
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
installPatch = ({host, patch: patchUuid}) ->
|
installPatch = ({host, patch: patchUuid}) ->
|
||||||
return @getXAPI(host).installPoolPatchOnHost(patchUuid, host.id)
|
return @getXAPI(host).installPoolPatchOnHost(patchUuid, host._xapiId)
|
||||||
|
|
||||||
installPatch.description = 'install a patch on an host'
|
installPatch.description = 'install a patch on an host'
|
||||||
|
|
||||||
@ -268,7 +240,7 @@ exports.installPatch = installPatch
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
installAllPatches = ({host}) ->
|
installAllPatches = ({host}) ->
|
||||||
return @getXAPI(host).installAllPoolPatchesOnHost(host.id)
|
return @getXAPI(host).installAllPoolPatchesOnHost(host._xapiId)
|
||||||
|
|
||||||
installAllPatches.description = 'install all the missing patches on a host'
|
installAllPatches.description = 'install all the missing patches on a host'
|
||||||
|
|
||||||
@ -284,9 +256,8 @@ exports.installAllPatches = installAllPatches
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
stats = $coroutine ({host, granularity}) ->
|
stats = ({host, granularity}) ->
|
||||||
stats = yield @getXapiHostStats(host, granularity)
|
return @getXapiHostStats(host, granularity)
|
||||||
return stats
|
|
||||||
|
|
||||||
stats.description = 'returns statistic of the host'
|
stats.description = 'returns statistic of the host'
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
async function delete_ ({message}) {
|
async function delete_ ({ message }) {
|
||||||
await this.getXAPI(message).call('message.destroy', message.ref)
|
await this.getXAPI(message).call('message.destroy', message._xapiRef)
|
||||||
}
|
}
|
||||||
export {delete_ as delete}
|
export {delete_ as delete}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
async function delete_ ({PBD}) {
|
async function delete_ ({PBD}) {
|
||||||
// TODO: check if PBD is attached before
|
// TODO: check if PBD is attached before
|
||||||
await this.getXAPI(PBD).call('PBD.destroy', PBD.ref)
|
await this.getXAPI(PBD).call('PBD.destroy', PBD._xapiRef)
|
||||||
}
|
}
|
||||||
export {delete_ as delete}
|
export {delete_ as delete}
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ delete_.resolve = {
|
|||||||
|
|
||||||
export async function disconnect ({PBD}) {
|
export async function disconnect ({PBD}) {
|
||||||
// TODO: check if PBD is attached before
|
// TODO: check if PBD is attached before
|
||||||
await this.getXAPI(PBD).call('PBD.unplug', PBD.ref)
|
await this.getXAPI(PBD).call('PBD.unplug', PBD._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect.params = {
|
disconnect.params = {
|
||||||
@ -38,7 +38,7 @@ disconnect.resolve = {
|
|||||||
|
|
||||||
export async function connect ({PBD}) {
|
export async function connect ({PBD}) {
|
||||||
// TODO: check if PBD is attached before
|
// TODO: check if PBD is attached before
|
||||||
await this.getXAPI(PBD).call('PBD.plug', PBD.ref)
|
await this.getXAPI(PBD).call('PBD.plug', PBD._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
connect.params = {
|
connect.params = {
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
// TODO: too low level, move into host.
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// Delete
|
// Delete
|
||||||
|
|
||||||
async function delete_ ({PIF}) {
|
async function delete_ ({PIF}) {
|
||||||
// TODO: check if PIF is attached before
|
// TODO: check if PIF is attached before
|
||||||
await this.getXAPI(PIF).call('PIF.destroy', PIF.ref)
|
await this.getXAPI(PIF).call('PIF.destroy', PIF._xapiRef)
|
||||||
}
|
}
|
||||||
export {delete_ as delete}
|
export {delete_ as delete}
|
||||||
|
|
||||||
@ -20,7 +22,7 @@ delete_.resolve = {
|
|||||||
|
|
||||||
export async function disconnect ({PIF}) {
|
export async function disconnect ({PIF}) {
|
||||||
// TODO: check if PIF is attached before
|
// TODO: check if PIF is attached before
|
||||||
await this.getXAPI(PIF).call('PIF.unplug', PIF.ref)
|
await this.getXAPI(PIF).call('PIF.unplug', PIF._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect.params = {
|
disconnect.params = {
|
||||||
@ -35,7 +37,7 @@ disconnect.resolve = {
|
|||||||
|
|
||||||
export async function connect ({PIF}) {
|
export async function connect ({PIF}) {
|
||||||
// TODO: check if PIF is attached before
|
// TODO: check if PIF is attached before
|
||||||
await this.getXAPI(PIF).call('PIF.plug', PIF.ref)
|
await this.getXAPI(PIF).call('PIF.plug', PIF._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
connect.params = {
|
connect.params = {
|
||||||
|
@ -82,7 +82,7 @@ export {uploadPatch as patch}
|
|||||||
|
|
||||||
export async function mergeInto ({ source, target, force }) {
|
export async function mergeInto ({ source, target, force }) {
|
||||||
try {
|
try {
|
||||||
await this.mergeXenPools(source.id, target.id, force)
|
await this.mergeXenPools(source._xapiId, target._xapiId, force)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// FIXME: should we expose plain XAPI error messages?
|
// FIXME: should we expose plain XAPI error messages?
|
||||||
throw new JsonRpcError(e.message)
|
throw new JsonRpcError(e.message)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
ensureArray,
|
ensureArray,
|
||||||
|
extractProperty,
|
||||||
forEach,
|
forEach,
|
||||||
parseXml
|
parseXml
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
@ -7,10 +8,9 @@ import {
|
|||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
export async function set (params) {
|
export async function set (params) {
|
||||||
const {sr} = params
|
const sr = extractProperty(params, 'sr')
|
||||||
delete params.sr
|
|
||||||
|
|
||||||
await this.getXAPI(sr).setSrProperties(sr.id, params)
|
await this.getXAPI(sr).setSrProperties(sr._xapiId, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
set.params = {
|
set.params = {
|
||||||
@ -28,7 +28,7 @@ set.resolve = {
|
|||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
export async function scan ({SR}) {
|
export async function scan ({SR}) {
|
||||||
await this.getXAPI(SR).call('SR.scan', SR.ref)
|
await this.getXAPI(SR).call('SR.scan', SR._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
scan.params = {
|
scan.params = {
|
||||||
@ -43,7 +43,7 @@ scan.resolve = {
|
|||||||
|
|
||||||
// TODO: find a way to call this "delete" and not destroy
|
// TODO: find a way to call this "delete" and not destroy
|
||||||
export async function destroy ({SR}) {
|
export async function destroy ({SR}) {
|
||||||
await this.getXAPI(SR).call('SR.destroy', SR.ref)
|
await this.getXAPI(SR).call('SR.destroy', SR._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy.params = {
|
destroy.params = {
|
||||||
@ -57,7 +57,7 @@ destroy.resolve = {
|
|||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
export async function forget ({SR}) {
|
export async function forget ({SR}) {
|
||||||
await this.getXAPI(SR).call('SR.forget', SR.ref)
|
await this.getXAPI(SR).call('SR.forget', SR._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
forget.params = {
|
forget.params = {
|
||||||
@ -87,7 +87,7 @@ export async function createIso ({
|
|||||||
}
|
}
|
||||||
const srRef = await xapi.call(
|
const srRef = await xapi.call(
|
||||||
'SR.create',
|
'SR.create',
|
||||||
host.ref,
|
host._xapiRef,
|
||||||
deviceConfig,
|
deviceConfig,
|
||||||
'0', // SR size 0 because ISO
|
'0', // SR size 0 because ISO
|
||||||
nameLabel,
|
nameLabel,
|
||||||
@ -140,7 +140,7 @@ export async function createNfs ({
|
|||||||
|
|
||||||
const srRef = await xapi.call(
|
const srRef = await xapi.call(
|
||||||
'SR.create',
|
'SR.create',
|
||||||
host.ref,
|
host._xapiRef,
|
||||||
deviceConfig,
|
deviceConfig,
|
||||||
'0',
|
'0',
|
||||||
nameLabel,
|
nameLabel,
|
||||||
@ -187,7 +187,7 @@ export async function createLvm ({
|
|||||||
|
|
||||||
const srRef = await xapi.call(
|
const srRef = await xapi.call(
|
||||||
'SR.create',
|
'SR.create',
|
||||||
host.ref,
|
host._xapiRef,
|
||||||
deviceConfig,
|
deviceConfig,
|
||||||
'0',
|
'0',
|
||||||
nameLabel,
|
nameLabel,
|
||||||
@ -232,7 +232,7 @@ export async function probeNfs ({
|
|||||||
try {
|
try {
|
||||||
await xapi.call(
|
await xapi.call(
|
||||||
'SR.probe',
|
'SR.probe',
|
||||||
host.ref,
|
host._xapiRef,
|
||||||
deviceConfig,
|
deviceConfig,
|
||||||
'nfs',
|
'nfs',
|
||||||
{}
|
{}
|
||||||
@ -305,7 +305,7 @@ export async function createIscsi ({
|
|||||||
|
|
||||||
const srRef = await xapi.call(
|
const srRef = await xapi.call(
|
||||||
'SR.create',
|
'SR.create',
|
||||||
host.ref,
|
host._xapiRef,
|
||||||
deviceConfig,
|
deviceConfig,
|
||||||
'0',
|
'0',
|
||||||
nameLabel,
|
nameLabel,
|
||||||
@ -369,7 +369,7 @@ export async function probeIscsiIqns ({
|
|||||||
try {
|
try {
|
||||||
await xapi.call(
|
await xapi.call(
|
||||||
'SR.probe',
|
'SR.probe',
|
||||||
host.ref,
|
host._xapiRef,
|
||||||
deviceConfig,
|
deviceConfig,
|
||||||
'lvmoiscsi',
|
'lvmoiscsi',
|
||||||
{}
|
{}
|
||||||
@ -447,7 +447,7 @@ export async function probeIscsiLuns ({
|
|||||||
try {
|
try {
|
||||||
await xapi.call(
|
await xapi.call(
|
||||||
'SR.probe',
|
'SR.probe',
|
||||||
host.ref,
|
host._xapiRef,
|
||||||
deviceConfig,
|
deviceConfig,
|
||||||
'lvmoiscsi',
|
'lvmoiscsi',
|
||||||
{}
|
{}
|
||||||
@ -521,7 +521,7 @@ export async function probeIscsiExists ({
|
|||||||
deviceConfig.port = port
|
deviceConfig.port = port
|
||||||
}
|
}
|
||||||
|
|
||||||
const xml = parseXml(await xapi.call('SR.probe', host.ref, deviceConfig, 'lvmoiscsi', {}))
|
const xml = parseXml(await xapi.call('SR.probe', host._xapiRef, deviceConfig, 'lvmoiscsi', {}))
|
||||||
|
|
||||||
const srs = []
|
const srs = []
|
||||||
forEach(ensureArray(xml['SRlist'].SR), sr => {
|
forEach(ensureArray(xml['SRlist'].SR), sr => {
|
||||||
@ -562,7 +562,7 @@ export async function probeNfsExists ({
|
|||||||
serverpath: serverPath
|
serverpath: serverPath
|
||||||
}
|
}
|
||||||
|
|
||||||
const xml = parseXml(await xapi.call('SR.probe', host.ref, deviceConfig, 'nfs', {}))
|
const xml = parseXml(await xapi.call('SR.probe', host._xapiRef, deviceConfig, 'nfs', {}))
|
||||||
|
|
||||||
const srs = []
|
const srs = []
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export async function add ({tag, object}) {
|
export async function add ({tag, object}) {
|
||||||
await this.getXAPI(object).addTag(object.id, tag)
|
await this.getXAPI(object).addTag(object._xapiId, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
add.description = 'add a new tag to an object'
|
add.description = 'add a new tag to an object'
|
||||||
@ -16,7 +16,7 @@ add.params = {
|
|||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
export async function remove ({tag, object}) {
|
export async function remove ({tag, object}) {
|
||||||
await this.getXAPI(object).removeTag(object.id, tag)
|
await this.getXAPI(object).removeTag(object._xapiId, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
remove.description = 'remove an existing tag from an object'
|
remove.description = 'remove an existing tag from an object'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export async function cancel ({task}) {
|
export async function cancel ({task}) {
|
||||||
await this.getXAPI(task).call('task.cancel', task.ref)
|
await this.getXAPI(task).call('task.cancel', task._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel.params = {
|
cancel.params = {
|
||||||
@ -13,7 +13,7 @@ cancel.resolve = {
|
|||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
export async function destroy ({task}) {
|
export async function destroy ({task}) {
|
||||||
await this.getXAPI(task).call('task.destroy', task.ref)
|
await this.getXAPI(task).call('task.destroy', task._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy.params = {
|
destroy.params = {
|
||||||
|
@ -8,7 +8,7 @@ delete_ = $coroutine ({vbd}) ->
|
|||||||
xapi = @getXAPI vbd
|
xapi = @getXAPI vbd
|
||||||
|
|
||||||
# TODO: check if VBD is attached before
|
# TODO: check if VBD is attached before
|
||||||
yield xapi.call 'VBD.destroy', vbd.ref
|
yield xapi.call 'VBD.destroy', vbd._xapiRef
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ disconnect = $coroutine ({vbd}) ->
|
|||||||
xapi = @getXAPI vbd
|
xapi = @getXAPI vbd
|
||||||
|
|
||||||
# TODO: check if VBD is attached before
|
# TODO: check if VBD is attached before
|
||||||
yield xapi.call 'VBD.unplug_force', vbd.ref
|
yield xapi.call 'VBD.unplug_force', vbd._xapiRef
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ connect = $coroutine ({vbd}) ->
|
|||||||
xapi = @getXAPI vbd
|
xapi = @getXAPI vbd
|
||||||
|
|
||||||
# TODO: check if VBD is attached before
|
# TODO: check if VBD is attached before
|
||||||
yield xapi.call 'VBD.plug', vbd.ref
|
yield xapi.call 'VBD.plug', vbd._xapiRef
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ set = $coroutine (params) ->
|
|||||||
{vbd} = params
|
{vbd} = params
|
||||||
xapi = @getXAPI vbd
|
xapi = @getXAPI vbd
|
||||||
|
|
||||||
{ref} = vbd
|
{ _xapiRef: ref } = vbd
|
||||||
|
|
||||||
# VBD position
|
# VBD position
|
||||||
if 'position' of params
|
if 'position' of params
|
||||||
|
@ -9,7 +9,7 @@ $isArray = require 'lodash.isarray'
|
|||||||
#=====================================================================
|
#=====================================================================
|
||||||
|
|
||||||
delete_ = $coroutine ({vdi}) ->
|
delete_ = $coroutine ({vdi}) ->
|
||||||
yield @getXAPI(vdi).deleteVdi(vdi.id)
|
yield @getXAPI(vdi).deleteVdi(vdi._xapiId)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ set = $coroutine (params) ->
|
|||||||
{vdi} = params
|
{vdi} = params
|
||||||
xapi = @getXAPI vdi
|
xapi = @getXAPI vdi
|
||||||
|
|
||||||
{ref} = vdi
|
{_xapiRef: ref} = vdi
|
||||||
|
|
||||||
# Size.
|
# Size.
|
||||||
if 'size' of params
|
if 'size' of params
|
||||||
@ -79,7 +79,7 @@ migrate = $coroutine ({vdi, sr}) ->
|
|||||||
xapi = @getXAPI vdi
|
xapi = @getXAPI vdi
|
||||||
|
|
||||||
# TODO: check if VDI is attached before
|
# TODO: check if VDI is attached before
|
||||||
yield xapi.call 'VDI.pool_migrate', vdi.ref, sr.ref, {}
|
yield xapi.call 'VDI.pool_migrate', vdi._xapiRef, sr._xapiRef, {}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// TODO: move into vm and rename to removeInterface
|
// TODO: move into vm and rename to removeInterface
|
||||||
async function delete_ ({vif}) {
|
async function delete_ ({vif}) {
|
||||||
await this.getXAPI(vif).deleteVif(vif.id)
|
await this.getXAPI(vif).deleteVif(vif._xapiId)
|
||||||
}
|
}
|
||||||
export {delete_ as delete}
|
export {delete_ as delete}
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ delete_.resolve = {
|
|||||||
// TODO: move into vm and rename to disconnectInterface
|
// TODO: move into vm and rename to disconnectInterface
|
||||||
export async function disconnect ({vif}) {
|
export async function disconnect ({vif}) {
|
||||||
// TODO: check if VIF is attached before
|
// TODO: check if VIF is attached before
|
||||||
await this.getXAPI(vif).call('VIF.unplug_force', vif.ref)
|
await this.getXAPI(vif).call('VIF.unplug_force', vif._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect.params = {
|
disconnect.params = {
|
||||||
@ -31,7 +31,7 @@ disconnect.resolve = {
|
|||||||
// TODO: move into vm and rename to connectInterface
|
// TODO: move into vm and rename to connectInterface
|
||||||
export async function connect ({vif}) {
|
export async function connect ({vif}) {
|
||||||
// TODO: check if VIF is attached before
|
// TODO: check if VIF is attached before
|
||||||
await this.getXAPI(vif).call('VIF.plug', vif.ref)
|
await this.getXAPI(vif).call('VIF.plug', vif._xapiRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
connect.params = {
|
connect.params = {
|
||||||
|
@ -59,7 +59,7 @@ create = $coroutine ({
|
|||||||
VDIs
|
VDIs
|
||||||
VIFs
|
VIFs
|
||||||
}) ->
|
}) ->
|
||||||
vm = yield @getXAPI(template).createVm(template.id, {
|
vm = yield @getXAPI(template).createVm(template._xapiId, {
|
||||||
installRepository: installation && installation.repository,
|
installRepository: installation && installation.repository,
|
||||||
nameDescription: name_description,
|
nameDescription: name_description,
|
||||||
nameLabel: name_label,
|
nameLabel: name_label,
|
||||||
@ -138,7 +138,7 @@ exports.create = create
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
delete_ = ({vm, delete_disks: deleteDisks}) ->
|
delete_ = ({vm, delete_disks: deleteDisks}) ->
|
||||||
return @getXAPI(vm).deleteVm(vm.id, deleteDisks)
|
return @getXAPI(vm).deleteVm(vm._xapiId, deleteDisks)
|
||||||
|
|
||||||
delete_.params = {
|
delete_.params = {
|
||||||
id: { type: 'string' }
|
id: { type: 'string' }
|
||||||
@ -157,7 +157,7 @@ exports.delete = delete_
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
ejectCd = $coroutine ({vm}) ->
|
ejectCd = $coroutine ({vm}) ->
|
||||||
yield @getXAPI(vm).ejectCdFromVm(vm.id)
|
yield @getXAPI(vm).ejectCdFromVm(vm._xapiId)
|
||||||
return
|
return
|
||||||
|
|
||||||
ejectCd.params = {
|
ejectCd.params = {
|
||||||
@ -172,7 +172,7 @@ exports.ejectCd = ejectCd
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
insertCd = $coroutine ({vm, vdi, force}) ->
|
insertCd = $coroutine ({vm, vdi, force}) ->
|
||||||
yield @getXAPI(vm).insertCdIntoVm(vdi.id, vm.id, {force})
|
yield @getXAPI(vm).insertCdIntoVm(vdi._xapiId, vm._xapiId, {force})
|
||||||
return
|
return
|
||||||
|
|
||||||
insertCd.params = {
|
insertCd.params = {
|
||||||
@ -190,7 +190,7 @@ exports.insertCd = insertCd
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
migrate = $coroutine ({vm, host}) ->
|
migrate = $coroutine ({vm, host}) ->
|
||||||
yield @getXAPI(vm).migrateVm(vm.id, @getXAPI(host), host.id)
|
yield @getXAPI(vm).migrateVm(vm._xapiId, @getXAPI(host), host._xapiId)
|
||||||
return
|
return
|
||||||
|
|
||||||
migrate.params = {
|
migrate.params = {
|
||||||
@ -217,10 +217,10 @@ migratePool = $coroutine ({
|
|||||||
network
|
network
|
||||||
migrationNetwork
|
migrationNetwork
|
||||||
}) ->
|
}) ->
|
||||||
yield @getXAPI(vm).migrateVm(vm.id, @getXAPI(host), host.id, {
|
yield @getXAPI(vm).migrateVm(vm._xapiId, @getXAPI(host), host._xapiId, {
|
||||||
migrationNetworkId: migrationNetwork?.id
|
migrationNetworkId: migrationNetwork?._xapiId
|
||||||
networkId: network?.id,
|
networkId: network?._xapiId,
|
||||||
srId: sr?.id,
|
srId: sr?._xapiId,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -260,7 +260,7 @@ set = $coroutine (params) ->
|
|||||||
{VM} = params
|
{VM} = params
|
||||||
xapi = @getXAPI VM
|
xapi = @getXAPI VM
|
||||||
|
|
||||||
{ref} = VM
|
{_xapiRef: ref} = VM
|
||||||
|
|
||||||
# Memory.
|
# Memory.
|
||||||
if 'memory' of params
|
if 'memory' of params
|
||||||
@ -371,9 +371,9 @@ restart = $coroutine ({vm, force}) ->
|
|||||||
xapi = @getXAPI(vm)
|
xapi = @getXAPI(vm)
|
||||||
|
|
||||||
if force
|
if force
|
||||||
yield xapi.call 'VM.hard_reboot', vm.ref
|
yield xapi.call 'VM.hard_reboot', vm._xapiRef
|
||||||
else
|
else
|
||||||
yield xapi.call 'VM.clean_reboot', vm.ref
|
yield xapi.call 'VM.clean_reboot', vm._xapiRef
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -391,7 +391,7 @@ exports.restart = restart
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
clone = ({vm, name, full_copy}) ->
|
clone = ({vm, name, full_copy}) ->
|
||||||
return @getXAPI(vm).cloneVm(vm.ref, {
|
return @getXAPI(vm).cloneVm(vm._xapiRef, {
|
||||||
nameLabel: name,
|
nameLabel: name,
|
||||||
fast: not full_copy
|
fast: not full_copy
|
||||||
}).then((vm) -> vm.$id)
|
}).then((vm) -> vm.$id)
|
||||||
@ -417,15 +417,15 @@ copy = $coroutine ({
|
|||||||
sr,
|
sr,
|
||||||
vm
|
vm
|
||||||
}) ->
|
}) ->
|
||||||
if vm.$poolId == sr.$poolId
|
if vm.$pool == sr.$pool
|
||||||
if vm.power_state is 'Running'
|
if vm.power_state is 'Running'
|
||||||
yield checkPermissionsForSnapshot.call(this, vm)
|
yield checkPermissionsForSnapshot.call(this, vm)
|
||||||
|
|
||||||
return @getXAPI(vm).copyVm(vm.id, sr.id, {
|
return @getXAPI(vm).copyVm(vm._xapiId, sr._xapiId, {
|
||||||
nameLabel
|
nameLabel
|
||||||
}).then((vm) -> vm.$id)
|
}).then((vm) -> vm.$id)
|
||||||
|
|
||||||
return @getXAPI(vm).remoteCopyVm(vm.id, @getXAPI(sr), sr.id, {
|
return @getXAPI(vm).remoteCopyVm(vm._xapiId, @getXAPI(sr), sr._xapiId, {
|
||||||
compress,
|
compress,
|
||||||
nameLabel
|
nameLabel
|
||||||
}).then((vm) -> vm.$id)
|
}).then((vm) -> vm.$id)
|
||||||
@ -454,7 +454,7 @@ exports.copy = copy
|
|||||||
|
|
||||||
# TODO: rename convertToTemplate()
|
# TODO: rename convertToTemplate()
|
||||||
convert = $coroutine ({vm}) ->
|
convert = $coroutine ({vm}) ->
|
||||||
yield @getXAPI(vm).call 'VM.set_is_a_template', vm.ref, true
|
yield @getXAPI(vm).call 'VM.set_is_a_template', vm._xapiRef, true
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -472,7 +472,7 @@ exports.convert = convert
|
|||||||
snapshot = $coroutine ({vm, name}) ->
|
snapshot = $coroutine ({vm, name}) ->
|
||||||
yield checkPermissionsForSnapshot.call(this, vm)
|
yield checkPermissionsForSnapshot.call(this, vm)
|
||||||
|
|
||||||
snapshot = yield @getXAPI(vm).snapshotVm(vm.ref, name)
|
snapshot = yield @getXAPI(vm).snapshotVm(vm._xapiRef, name)
|
||||||
return snapshot.$id
|
return snapshot.$id
|
||||||
|
|
||||||
snapshot.params = {
|
snapshot.params = {
|
||||||
@ -559,7 +559,7 @@ exports.rollingBackup = rollingBackup
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
rollingDrCopy = ({vm, pool, tag, depth}) ->
|
rollingDrCopy = ({vm, pool, tag, depth}) ->
|
||||||
if vm.$poolId is pool.id
|
if vm.$pool is pool.id
|
||||||
throw new JsonRpcError('Disaster Recovery attempts to copy on the same pool')
|
throw new JsonRpcError('Disaster Recovery attempts to copy on the same pool')
|
||||||
return @rollingDrCopyVm({vm, sr: @getObject(pool.default_SR, 'SR'), tag, depth})
|
return @rollingDrCopyVm({vm, sr: @getObject(pool.default_SR, 'SR'), tag, depth})
|
||||||
|
|
||||||
@ -583,7 +583,7 @@ exports.rollingDrCopy = rollingDrCopy
|
|||||||
|
|
||||||
start = $coroutine ({vm}) ->
|
start = $coroutine ({vm}) ->
|
||||||
yield @getXAPI(vm).call(
|
yield @getXAPI(vm).call(
|
||||||
'VM.start', vm.ref
|
'VM.start', vm._xapiRef
|
||||||
false # Start paused?
|
false # Start paused?
|
||||||
false # Skips the pre-boot checks?
|
false # Skips the pre-boot checks?
|
||||||
)
|
)
|
||||||
@ -611,12 +611,12 @@ stop = $coroutine ({vm, force}) ->
|
|||||||
|
|
||||||
# Hard shutdown
|
# Hard shutdown
|
||||||
if force
|
if force
|
||||||
yield xapi.call 'VM.hard_shutdown', vm.ref
|
yield xapi.call 'VM.hard_shutdown', vm._xapiRef
|
||||||
return true
|
return true
|
||||||
|
|
||||||
# Clean shutdown
|
# Clean shutdown
|
||||||
try
|
try
|
||||||
yield xapi.call 'VM.clean_shutdown', vm.ref
|
yield xapi.call 'VM.clean_shutdown', vm._xapiRef
|
||||||
catch error
|
catch error
|
||||||
if error.code is 'VM_MISSING_PV_DRIVERS' or error.code is 'VM_LACKS_FEATURE_SHUTDOWN'
|
if error.code is 'VM_MISSING_PV_DRIVERS' or error.code is 'VM_LACKS_FEATURE_SHUTDOWN'
|
||||||
# TODO: Improve reporting: this message is unclear.
|
# TODO: Improve reporting: this message is unclear.
|
||||||
@ -640,7 +640,7 @@ exports.stop = stop
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
suspend = $coroutine ({vm}) ->
|
suspend = $coroutine ({vm}) ->
|
||||||
yield @getXAPI(vm).call 'VM.suspend', vm.ref
|
yield @getXAPI(vm).call 'VM.suspend', vm._xapiRef
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -660,7 +660,7 @@ resume = $coroutine ({vm, force}) ->
|
|||||||
if not force
|
if not force
|
||||||
force = true
|
force = true
|
||||||
|
|
||||||
yield @getXAPI(vm).call 'VM.resume', vm.ref, false, force
|
yield @getXAPI(vm).call 'VM.resume', vm._xapiRef, false, force
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -679,7 +679,7 @@ exports.resume = resume
|
|||||||
# revert a snapshot to its parent VM
|
# revert a snapshot to its parent VM
|
||||||
revert = $coroutine ({snapshot}) ->
|
revert = $coroutine ({snapshot}) ->
|
||||||
# Attempts a revert from this snapshot to its parent VM
|
# Attempts a revert from this snapshot to its parent VM
|
||||||
yield @getXAPI(snapshot).call 'VM.revert', snapshot.ref
|
yield @getXAPI(snapshot).call 'VM.revert', snapshot._xapiRef
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -713,7 +713,7 @@ export_ = $coroutine ({vm, compress, onlyMetadata}) ->
|
|||||||
if vm.power_state is 'Running'
|
if vm.power_state is 'Running'
|
||||||
yield checkPermissionsForSnapshot.call(this, vm)
|
yield checkPermissionsForSnapshot.call(this, vm)
|
||||||
|
|
||||||
stream = yield @getXAPI(vm).exportVm(vm.id, {
|
stream = yield @getXAPI(vm).exportVm(vm._xapiId, {
|
||||||
compress: compress ? true,
|
compress: compress ? true,
|
||||||
onlyMetadata: onlyMetadata ? false
|
onlyMetadata: onlyMetadata ? false
|
||||||
})
|
})
|
||||||
@ -779,7 +779,7 @@ exports.import = import_
|
|||||||
# FIXME: if position is used, all other disks after this position
|
# FIXME: if position is used, all other disks after this position
|
||||||
# should be shifted.
|
# should be shifted.
|
||||||
attachDisk = $coroutine ({vm, vdi, position, mode, bootable}) ->
|
attachDisk = $coroutine ({vm, vdi, position, mode, bootable}) ->
|
||||||
yield @getXAPI(vm).attachVdiToVm(vdi.id, vm.id, {
|
yield @getXAPI(vm).attachVdiToVm(vdi._xapiId, vm._xapiId, {
|
||||||
bootable,
|
bootable,
|
||||||
position,
|
position,
|
||||||
readOnly: mode is 'RO'
|
readOnly: mode is 'RO'
|
||||||
@ -808,7 +808,7 @@ exports.attachDisk = attachDisk
|
|||||||
# FIXME: position should be optional and default to last.
|
# FIXME: position should be optional and default to last.
|
||||||
|
|
||||||
createInterface = $coroutine ({vm, network, position, mtu, mac}) ->
|
createInterface = $coroutine ({vm, network, position, mtu, mac}) ->
|
||||||
vif = yield @getXAPI(vm).createVif(vm.id, network.id, {
|
vif = yield @getXAPI(vm).createVif(vm._xapiId, network._xapiId, {
|
||||||
mac,
|
mac,
|
||||||
mtu,
|
mtu,
|
||||||
position
|
position
|
||||||
@ -835,7 +835,7 @@ exports.createInterface = createInterface
|
|||||||
attachPci = $coroutine ({vm, pciId}) ->
|
attachPci = $coroutine ({vm, pciId}) ->
|
||||||
xapi = @getXAPI vm
|
xapi = @getXAPI vm
|
||||||
|
|
||||||
yield xapi.call 'VM.add_to_other_config', vm.ref, 'pci', pciId
|
yield xapi.call 'VM.add_to_other_config', vm._xapiRef, 'pci', pciId
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -855,7 +855,7 @@ exports.attachPci = attachPci
|
|||||||
detachPci = $coroutine ({vm}) ->
|
detachPci = $coroutine ({vm}) ->
|
||||||
xapi = @getXAPI vm
|
xapi = @getXAPI vm
|
||||||
|
|
||||||
yield xapi.call 'VM.remove_from_other_config', vm.ref, 'pci'
|
yield xapi.call 'VM.remove_from_other_config', vm._xapiRef, 'pci'
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@ -899,7 +899,7 @@ bootOrder = $coroutine ({vm, order}) ->
|
|||||||
|
|
||||||
order = {order: order}
|
order = {order: order}
|
||||||
|
|
||||||
yield xapi.call 'VM.set_HVM_boot_params', vm.ref, order
|
yield xapi.call 'VM.set_HVM_boot_params', vm._xapiRef, order
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
592
src/xapi-object-to-xo.js
Normal file
592
src/xapi-object-to-xo.js
Normal file
@ -0,0 +1,592 @@
|
|||||||
|
import isArray from 'lodash.isarray'
|
||||||
|
|
||||||
|
import {
|
||||||
|
ensureArray,
|
||||||
|
extractProperty,
|
||||||
|
forEach,
|
||||||
|
mapToArray,
|
||||||
|
parseXml
|
||||||
|
} from './utils'
|
||||||
|
import {
|
||||||
|
isHostRunning,
|
||||||
|
isVmHvm,
|
||||||
|
isVmRunning,
|
||||||
|
parseDateTime
|
||||||
|
} from './xapi'
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
const {
|
||||||
|
defineProperties,
|
||||||
|
freeze
|
||||||
|
} = Object
|
||||||
|
|
||||||
|
function link (obj, prop, idField = '$id') {
|
||||||
|
const dynamicValue = obj[`$${prop}`]
|
||||||
|
if (dynamicValue == null) {
|
||||||
|
return dynamicValue // Properly handles null and undefined.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArray(dynamicValue)) {
|
||||||
|
return mapToArray(dynamicValue, idField)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dynamicValue[idField]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a string date time to a Unix timestamp (in seconds).
|
||||||
|
//
|
||||||
|
// If there are no data or if the timestamp is 0, returns null.
|
||||||
|
function toTimestamp (date) {
|
||||||
|
if (!date) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const ms = parseDateTime(date).getTime()
|
||||||
|
if (!ms) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.round(ms / 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
const TRANSFORMS = {
|
||||||
|
pool (obj) {
|
||||||
|
return {
|
||||||
|
default_SR: link(obj, 'default_SR'),
|
||||||
|
HA_enabled: Boolean(obj.ha_enabled),
|
||||||
|
master: link(obj, 'master'),
|
||||||
|
tags: obj.tags,
|
||||||
|
name_description: obj.name_description,
|
||||||
|
name_label: obj.name_label || obj.$master.name_label
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// - ? networks = networksByPool.items[pool.id] (network.$pool.id)
|
||||||
|
// - hosts = hostsByPool.items[pool.id] (host.$pool.$id)
|
||||||
|
// - patches = poolPatchesByPool.items[pool.id] (poolPatch.$pool.id)
|
||||||
|
// - SRs = srsByContainer.items[pool.id] (sr.$container.id)
|
||||||
|
// - templates = vmTemplatesByContainer.items[pool.id] (vmTemplate.$container.$id)
|
||||||
|
// - VMs = vmsByContainer.items[pool.id] (vm.$container.id)
|
||||||
|
// - $running_hosts = runningHostsByPool.items[pool.id] (runningHost.$pool.id)
|
||||||
|
// - $running_VMs = runningVmsByPool.items[pool.id] (runningHost.$pool.id)
|
||||||
|
// - $VMs = vmsByPool.items[pool.id] (vm.$pool.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
host (obj) {
|
||||||
|
const {
|
||||||
|
$metrics: metrics,
|
||||||
|
other_config: otherConfig
|
||||||
|
} = obj
|
||||||
|
|
||||||
|
const isRunning = isHostRunning(obj)
|
||||||
|
|
||||||
|
return {
|
||||||
|
address: obj.address,
|
||||||
|
bios_strings: obj.bios_strings,
|
||||||
|
build: obj.software_version.build_number,
|
||||||
|
CPUs: obj.cpu_info,
|
||||||
|
enabled: Boolean(obj.enabled),
|
||||||
|
current_operations: obj.current_operations,
|
||||||
|
hostname: obj.hostname,
|
||||||
|
iSCSI_name: otherConfig.iscsi_iqn || null,
|
||||||
|
name_description: obj.name_description,
|
||||||
|
name_label: obj.name_label,
|
||||||
|
memory: (function () {
|
||||||
|
if (metrics) {
|
||||||
|
const free = +metrics.memory_free
|
||||||
|
const total = +metrics.memory_total
|
||||||
|
|
||||||
|
return {
|
||||||
|
usage: total - free,
|
||||||
|
size: total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
usage: 0,
|
||||||
|
total: 0
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
patches: link(obj, 'patches'),
|
||||||
|
powerOnMode: obj.power_on_mode,
|
||||||
|
power_state: isRunning ? 'Running' : 'Halted',
|
||||||
|
tags: obj.tags,
|
||||||
|
version: obj.software_version.product_version,
|
||||||
|
|
||||||
|
// TODO: dedupe.
|
||||||
|
PIFs: link(obj, 'PIFs'),
|
||||||
|
$PIFs: link(obj, 'PIFs'),
|
||||||
|
PCIs: link(obj, 'PCIs'),
|
||||||
|
$PCIs: link(obj, 'PCIs'),
|
||||||
|
PGPUs: link(obj, 'PGPUs'),
|
||||||
|
$PGPUs: link(obj, 'PGPUs'),
|
||||||
|
|
||||||
|
$PBDs: link(obj, 'PBDs')
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - controller = vmControllersByContainer.items[host.id]
|
||||||
|
// - SRs = srsByContainer.items[host.id]
|
||||||
|
// - tasks = tasksByHost.items[host.id]
|
||||||
|
// - templates = vmTemplatesByContainer.items[host.id]
|
||||||
|
// - VMs = vmsByContainer.items[host.id]
|
||||||
|
// - $vCPUs = sum(host.VMs, vm => host.CPUs.number)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
vm (obj) {
|
||||||
|
const {
|
||||||
|
$guest_metrics: guestMetrics,
|
||||||
|
$metrics: metrics,
|
||||||
|
other_config: otherConfig
|
||||||
|
} = obj
|
||||||
|
|
||||||
|
const isHvm = isVmHvm(obj)
|
||||||
|
const isRunning = isVmRunning(obj)
|
||||||
|
|
||||||
|
const vm = {
|
||||||
|
// type is redefined after for controllers/, templates &
|
||||||
|
// snapshots.
|
||||||
|
type: 'VM',
|
||||||
|
|
||||||
|
addresses: guestMetrics && guestMetrics.networks || null,
|
||||||
|
auto_poweron: Boolean(otherConfig.auto_poweron),
|
||||||
|
boot: obj.HVM_boot_params,
|
||||||
|
CPUs: {
|
||||||
|
max: +obj.VCPUs_max,
|
||||||
|
number: (
|
||||||
|
isRunning && metrics
|
||||||
|
? +metrics.VCPUs_number
|
||||||
|
: +obj.VCPUs_at_startup
|
||||||
|
)
|
||||||
|
},
|
||||||
|
current_operations: obj.current_operations,
|
||||||
|
docker: (function () {
|
||||||
|
const monitor = otherConfig['xscontainer-monitor']
|
||||||
|
if (!monitor) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor === 'False') {
|
||||||
|
return {
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
docker_ps: process,
|
||||||
|
docker_info: info,
|
||||||
|
docker_version: version
|
||||||
|
} = otherConfig
|
||||||
|
|
||||||
|
return {
|
||||||
|
enabled: true,
|
||||||
|
info: info && parseXml(info).docker_info,
|
||||||
|
process: process && parseXml(process).docker_ps,
|
||||||
|
version: version && parseXml(version).docker_version
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
|
||||||
|
// TODO: there is two possible value: "best-effort" and "restart"
|
||||||
|
high_availability: Boolean(obj.ha_restart_priority),
|
||||||
|
|
||||||
|
memory: (function () {
|
||||||
|
const dynamicMin = +obj.memory_dynamic_min
|
||||||
|
const dynamicMax = +obj.memory_dynamic_max
|
||||||
|
const staticMin = +obj.memory_static_min
|
||||||
|
const staticMax = +obj.memory_static_max
|
||||||
|
|
||||||
|
const memory = {
|
||||||
|
dynamic: [ dynamicMin, dynamicMax ],
|
||||||
|
static: [ staticMin, staticMax ]
|
||||||
|
}
|
||||||
|
|
||||||
|
const gmMemory = guestMetrics && guestMetrics.memory
|
||||||
|
|
||||||
|
if (!isRunning) {
|
||||||
|
memory.size = dynamicMax
|
||||||
|
} else if (gmMemory && gmMemory.used) {
|
||||||
|
memory.usage = +gmMemory.used
|
||||||
|
memory.size = +gmMemory.total
|
||||||
|
} else if (metrics) {
|
||||||
|
memory.size = +metrics.memory_actual
|
||||||
|
} else {
|
||||||
|
memory.size = dynamicMax
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory
|
||||||
|
})(),
|
||||||
|
name_description: obj.name_description,
|
||||||
|
name_label: obj.name_label,
|
||||||
|
other: otherConfig,
|
||||||
|
os_version: guestMetrics && guestMetrics.os_version || null,
|
||||||
|
power_state: obj.power_state,
|
||||||
|
snapshot_time: toTimestamp(obj.snapshot_time),
|
||||||
|
snapshots: link(obj, 'snapshots'),
|
||||||
|
tags: obj.tags,
|
||||||
|
VIFs: link(obj, 'VIFs'),
|
||||||
|
virtualizationMode: isHvm ? 'hvm' : 'pv',
|
||||||
|
|
||||||
|
// <=> Are the Xen Server tools installed?
|
||||||
|
//
|
||||||
|
// - undefined: unknown status
|
||||||
|
// - false: not optimized
|
||||||
|
// - 'out of date': optimized but drivers should be updated
|
||||||
|
// - 'up to date': optimized
|
||||||
|
xenTools: (() => {
|
||||||
|
if (!isRunning || !metrics) {
|
||||||
|
// Unknown status, returns nothing.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!guestMetrics) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const { PV_drivers_version: { major, minor } } = guestMetrics
|
||||||
|
if (major === undefined || minor === undefined) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return guestMetrics.PV_drivers_up_to_date
|
||||||
|
? 'up to date'
|
||||||
|
: 'out of date'
|
||||||
|
})(),
|
||||||
|
|
||||||
|
$container: (
|
||||||
|
isRunning
|
||||||
|
? link(obj, 'resident_on')
|
||||||
|
: link(obj, 'pool') // TODO: handle local VMs (`VM.get_possible_hosts()`).
|
||||||
|
),
|
||||||
|
$VBDs: link(obj, 'VBDs'),
|
||||||
|
|
||||||
|
// TODO: dedupe
|
||||||
|
VGPUs: link(obj, 'VGPUs'),
|
||||||
|
$VGPUs: link(obj, 'VGPUs')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.is_control_domain) {
|
||||||
|
vm.type += '-controller'
|
||||||
|
} else if (obj.is_a_snapshot) {
|
||||||
|
vm.type += '-snapshot'
|
||||||
|
|
||||||
|
vm.$snapshot_of = link(obj, 'snapshot_of')
|
||||||
|
} else if (obj.is_a_template) {
|
||||||
|
vm.type += '-template'
|
||||||
|
|
||||||
|
vm.CPUs.number = +obj.VCPUs_at_startup
|
||||||
|
vm.template_info = {
|
||||||
|
arch: otherConfig['install-arch'],
|
||||||
|
disks: (function () {
|
||||||
|
const {disks: xml} = otherConfig
|
||||||
|
let data
|
||||||
|
if (!xml || !(data = parseXml(xml)).provision) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const disks = ensureArray(data.provision.disk)
|
||||||
|
forEach(disks, function normalize (disk) {
|
||||||
|
disk.bootable = disk.bootable === 'true'
|
||||||
|
disk.size = +disk.size
|
||||||
|
disk.SR = extractProperty(disk, 'sr')
|
||||||
|
})
|
||||||
|
|
||||||
|
return disks
|
||||||
|
})(),
|
||||||
|
install_methods: (function () {
|
||||||
|
const {['install-methods']: methods} = otherConfig
|
||||||
|
|
||||||
|
return methods ? methods.split(',') : []
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isHvm) {
|
||||||
|
vm.PV_args = obj.PV_args
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
sr (obj) {
|
||||||
|
return {
|
||||||
|
type: 'SR',
|
||||||
|
|
||||||
|
content_type: obj.content_type,
|
||||||
|
name_description: obj.name_description,
|
||||||
|
name_label: obj.name_label,
|
||||||
|
physical_usage: +obj.physical_utilisation,
|
||||||
|
size: +obj.physical_size,
|
||||||
|
SR_type: obj.type,
|
||||||
|
tags: obj.tags,
|
||||||
|
usage: +obj.virtual_allocation,
|
||||||
|
VDIs: link(obj, 'VDIs'),
|
||||||
|
|
||||||
|
$container: (
|
||||||
|
obj.shared
|
||||||
|
? link(obj, 'pool')
|
||||||
|
: obj.$PBDs[0] && link(obj.$PBDs[0], 'host')
|
||||||
|
),
|
||||||
|
$PBDs: link(obj, 'PBDs')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
pbd (obj) {
|
||||||
|
return {
|
||||||
|
type: 'PBD',
|
||||||
|
|
||||||
|
attached: obj.currently_attached,
|
||||||
|
host: link(obj, 'host'),
|
||||||
|
SR: link(obj, 'SR')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
pif (obj) {
|
||||||
|
return {
|
||||||
|
type: 'PIF',
|
||||||
|
|
||||||
|
attached: Boolean(obj.currently_attached),
|
||||||
|
device: obj.device,
|
||||||
|
IP: obj.IP,
|
||||||
|
MAC: obj.MAC,
|
||||||
|
management: Boolean(obj.management), // TODO: find a better name.
|
||||||
|
mode: obj.ip_configuration_mode,
|
||||||
|
MTU: +obj.MTU,
|
||||||
|
netmask: obj.netmask,
|
||||||
|
vlan: +obj.VLAN,
|
||||||
|
|
||||||
|
// TODO: What is it?
|
||||||
|
//
|
||||||
|
// Could it mean “is this a physical interface?”.
|
||||||
|
// How could a PIF not be physical?
|
||||||
|
// physical: obj.physical,
|
||||||
|
|
||||||
|
$host: link(obj, 'host'),
|
||||||
|
$network: link(obj, 'network')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
// TODO: should we have a VDI-snapshot type like we have with VMs?
|
||||||
|
vdi (obj) {
|
||||||
|
if (!obj.managed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'VDI',
|
||||||
|
|
||||||
|
name_description: obj.name_description,
|
||||||
|
name_label: obj.name_label,
|
||||||
|
size: +obj.virtual_size,
|
||||||
|
snapshots: link(obj, 'snapshots'),
|
||||||
|
snapshot_time: toTimestamp(obj.snapshot_time),
|
||||||
|
tags: obj.tags,
|
||||||
|
usage: +obj.physical_utilisation,
|
||||||
|
|
||||||
|
$snapshot_of: link(obj, 'snapshot_of'),
|
||||||
|
$SR: link(obj, 'SR'),
|
||||||
|
$VBDs: link(obj, 'VBDs')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
vbd (obj) {
|
||||||
|
return {
|
||||||
|
type: 'VBD',
|
||||||
|
|
||||||
|
attached: Boolean(obj.currently_attached),
|
||||||
|
bootable: Boolean(obj.bootable),
|
||||||
|
is_cd_drive: obj.type === 'CD',
|
||||||
|
position: obj.userdevice,
|
||||||
|
read_only: obj.mode === 'RO',
|
||||||
|
VDI: link(obj, 'VDI'),
|
||||||
|
VM: link(obj, 'VM')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
vif (obj) {
|
||||||
|
return {
|
||||||
|
type: 'VIF',
|
||||||
|
|
||||||
|
attached: Boolean(obj.currently_attached),
|
||||||
|
device: obj.device, // TODO: should it be cast to a number?
|
||||||
|
MAC: obj.MAC,
|
||||||
|
MTU: +obj.MTU,
|
||||||
|
|
||||||
|
$network: link(obj, 'network'),
|
||||||
|
$VM: link(obj, 'VM')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
network (obj) {
|
||||||
|
return {
|
||||||
|
bridge: obj.bridge,
|
||||||
|
MTU: +obj.MTU,
|
||||||
|
name_description: obj.name_description,
|
||||||
|
name_label: obj.name_label,
|
||||||
|
tags: obj.tags,
|
||||||
|
PIFs: link(obj, 'PIFs'),
|
||||||
|
VIFs: link(obj, 'VIFs')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
message (obj) {
|
||||||
|
return {
|
||||||
|
body: obj.body,
|
||||||
|
name: obj.name,
|
||||||
|
time: toTimestamp(obj.timestamp),
|
||||||
|
|
||||||
|
$object: obj.obj_uuid // Special link as it is already an UUID.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
task (obj) {
|
||||||
|
return {
|
||||||
|
created: toTimestamp(obj.created),
|
||||||
|
current_operations: obj.current_operations,
|
||||||
|
finished: toTimestamp(obj.finished),
|
||||||
|
name_description: obj.name_description,
|
||||||
|
name_label: obj.name_label,
|
||||||
|
progress: +obj.progress,
|
||||||
|
result: obj.result,
|
||||||
|
status: obj.status,
|
||||||
|
|
||||||
|
$host: link(obj, 'resident_on')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
host_patch (obj) {
|
||||||
|
return {
|
||||||
|
applied: Boolean(obj.applied),
|
||||||
|
time: toTimestamp(obj.timestamp_applied),
|
||||||
|
pool_patch: link(obj, 'pool_patch', '$ref'),
|
||||||
|
|
||||||
|
$host: link(obj, 'host')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
pool_patch (obj) {
|
||||||
|
return {
|
||||||
|
id: obj.$ref,
|
||||||
|
|
||||||
|
applied: Boolean(obj.pool_applied),
|
||||||
|
description: obj.name_description,
|
||||||
|
guidance: obj.after_apply_guidance,
|
||||||
|
name: obj.name_label,
|
||||||
|
size: +obj.size,
|
||||||
|
uuid: obj.uuid,
|
||||||
|
|
||||||
|
// TODO: what does it mean, should we handle it?
|
||||||
|
// version: obj.version,
|
||||||
|
|
||||||
|
// TODO: host.[$]pool_patches ←→ pool.[$]host_patches
|
||||||
|
$host_patches: link(obj, 'host_patches')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
pci (obj) {
|
||||||
|
return {
|
||||||
|
type: 'PCI',
|
||||||
|
|
||||||
|
class_name: obj.class_name,
|
||||||
|
device_name: obj.device_name,
|
||||||
|
pci_id: obj.pci_id,
|
||||||
|
|
||||||
|
$host: link(obj, 'host')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
pgpu (obj) {
|
||||||
|
return {
|
||||||
|
type: 'PGPU',
|
||||||
|
|
||||||
|
pci: link(obj, 'PCI'),
|
||||||
|
|
||||||
|
// TODO: dedupe.
|
||||||
|
host: link(obj, 'host'),
|
||||||
|
$host: link(obj, 'host'),
|
||||||
|
vgpus: link(obj, 'resident_VGPUs'),
|
||||||
|
$vgpus: link(obj, 'resident_VGPUs')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
vgpu (obj) {
|
||||||
|
return {
|
||||||
|
type: 'VGPU',
|
||||||
|
|
||||||
|
currentlyAttached: Boolean(obj.currently_attached),
|
||||||
|
device: obj.device,
|
||||||
|
resident_on: link(obj, 'resident_on'),
|
||||||
|
vm: link(obj, 'VM')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
export default xapiObj => {
|
||||||
|
const transform = TRANSFORMS[xapiObj.$type.toLowerCase()]
|
||||||
|
if (!transform) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const xoObj = transform(xapiObj)
|
||||||
|
if (!xoObj) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!('id' in xoObj)) {
|
||||||
|
xoObj.id = xapiObj.$id
|
||||||
|
}
|
||||||
|
if (!('type' in xoObj)) {
|
||||||
|
xoObj.type = xapiObj.$type
|
||||||
|
}
|
||||||
|
xoObj.$pool = xapiObj.$pool.$id
|
||||||
|
xoObj.$poolId = xoObj.$pool // TODO: deprecated, remove when no longer used in xo-web
|
||||||
|
|
||||||
|
// Internal properties.
|
||||||
|
defineProperties(xoObj, {
|
||||||
|
_xapiId: {
|
||||||
|
value: xapiObj.$id
|
||||||
|
},
|
||||||
|
_xapiRef: {
|
||||||
|
value: xapiObj.$ref
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Freezes and returns the new object.
|
||||||
|
return freeze(xoObj)
|
||||||
|
}
|
@ -1,549 +0,0 @@
|
|||||||
import isArray from 'lodash.isarray'
|
|
||||||
|
|
||||||
import {
|
|
||||||
ensureArray,
|
|
||||||
extractProperty,
|
|
||||||
forEach,
|
|
||||||
mapToArray,
|
|
||||||
parseXml
|
|
||||||
} from './utils'
|
|
||||||
import {
|
|
||||||
isHostRunning,
|
|
||||||
isVmHvm,
|
|
||||||
isVmRunning,
|
|
||||||
parseDateTime
|
|
||||||
} from './xapi'
|
|
||||||
|
|
||||||
// ===================================================================
|
|
||||||
|
|
||||||
function link (obj, prop, idField = '$id') {
|
|
||||||
const dynamicValue = obj[`$${prop}`]
|
|
||||||
if (dynamicValue == null) {
|
|
||||||
return dynamicValue // Properly handles null and undefined.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isArray(dynamicValue)) {
|
|
||||||
return mapToArray(dynamicValue, idField)
|
|
||||||
}
|
|
||||||
|
|
||||||
return dynamicValue[idField]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse a string date time to a Unix timestamp (in seconds).
|
|
||||||
//
|
|
||||||
// If there are no data or if the timestamp is 0, returns null.
|
|
||||||
function toTimestamp (date) {
|
|
||||||
if (!date) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const ms = parseDateTime(date).getTime()
|
|
||||||
if (!ms) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.round(ms / 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===================================================================
|
|
||||||
|
|
||||||
export function pool (obj) {
|
|
||||||
return {
|
|
||||||
default_SR: link(obj, 'default_SR'),
|
|
||||||
HA_enabled: Boolean(obj.ha_enabled),
|
|
||||||
master: link(obj, 'master'),
|
|
||||||
tags: obj.tags,
|
|
||||||
name_description: obj.name_description,
|
|
||||||
name_label: obj.name_label || obj.$master.name_label
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// - ? networks = networksByPool.items[pool.id] (network.$pool.id)
|
|
||||||
// - hosts = hostsByPool.items[pool.id] (host.$pool.$id)
|
|
||||||
// - patches = poolPatchesByPool.items[pool.id] (poolPatch.$pool.id)
|
|
||||||
// - SRs = srsByContainer.items[pool.id] (sr.$container.id)
|
|
||||||
// - templates = vmTemplatesByContainer.items[pool.id] (vmTemplate.$container.$id)
|
|
||||||
// - VMs = vmsByContainer.items[pool.id] (vm.$container.id)
|
|
||||||
// - $running_hosts = runningHostsByPool.items[pool.id] (runningHost.$pool.id)
|
|
||||||
// - $running_VMs = runningVmsByPool.items[pool.id] (runningHost.$pool.id)
|
|
||||||
// - $VMs = vmsByPool.items[pool.id] (vm.$pool.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function host (obj) {
|
|
||||||
const {
|
|
||||||
$metrics: metrics,
|
|
||||||
other_config: otherConfig
|
|
||||||
} = obj
|
|
||||||
|
|
||||||
const isRunning = isHostRunning(obj)
|
|
||||||
|
|
||||||
return {
|
|
||||||
address: obj.address,
|
|
||||||
bios_strings: obj.bios_strings,
|
|
||||||
build: obj.software_version.build_number,
|
|
||||||
CPUs: obj.cpu_info,
|
|
||||||
enabled: Boolean(obj.enabled),
|
|
||||||
current_operations: obj.current_operations,
|
|
||||||
hostname: obj.hostname,
|
|
||||||
iSCSI_name: otherConfig.iscsi_iqn || null,
|
|
||||||
name_description: obj.name_description,
|
|
||||||
name_label: obj.name_label,
|
|
||||||
memory: (function () {
|
|
||||||
if (metrics) {
|
|
||||||
const free = +metrics.memory_free
|
|
||||||
const total = +metrics.memory_total
|
|
||||||
|
|
||||||
return {
|
|
||||||
usage: total - free,
|
|
||||||
size: total
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
usage: 0,
|
|
||||||
total: 0
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
patches: link(obj, 'patches'),
|
|
||||||
powerOnMode: obj.power_on_mode,
|
|
||||||
power_state: isRunning ? 'Running' : 'Halted',
|
|
||||||
tags: obj.tags,
|
|
||||||
version: obj.software_version.product_version,
|
|
||||||
|
|
||||||
// TODO: dedupe.
|
|
||||||
PIFs: link(obj, 'PIFs'),
|
|
||||||
$PIFs: link(obj, 'PIFs'),
|
|
||||||
PCIs: link(obj, 'PCIs'),
|
|
||||||
$PCIs: link(obj, 'PCIs'),
|
|
||||||
PGPUs: link(obj, 'PGPUs'),
|
|
||||||
$PGPUs: link(obj, 'PGPUs'),
|
|
||||||
|
|
||||||
$PBDs: link(obj, 'PBDs')
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// - controller = vmControllersByContainer.items[host.id]
|
|
||||||
// - SRs = srsByContainer.items[host.id]
|
|
||||||
// - tasks = tasksByHost.items[host.id]
|
|
||||||
// - templates = vmTemplatesByContainer.items[host.id]
|
|
||||||
// - VMs = vmsByContainer.items[host.id]
|
|
||||||
// - $vCPUs = sum(host.VMs, vm => host.CPUs.number)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function vm (obj) {
|
|
||||||
const {
|
|
||||||
$guest_metrics: guestMetrics,
|
|
||||||
$metrics: metrics,
|
|
||||||
other_config: otherConfig
|
|
||||||
} = obj
|
|
||||||
|
|
||||||
const isHvm = isVmHvm(obj)
|
|
||||||
const isRunning = isVmRunning(obj)
|
|
||||||
|
|
||||||
const vm = {
|
|
||||||
// type is redefined after for controllers/, templates &
|
|
||||||
// snapshots.
|
|
||||||
type: 'VM',
|
|
||||||
|
|
||||||
addresses: guestMetrics && guestMetrics.networks || null,
|
|
||||||
auto_poweron: Boolean(otherConfig.auto_poweron),
|
|
||||||
boot: obj.HVM_boot_params,
|
|
||||||
CPUs: {
|
|
||||||
max: +obj.VCPUs_max,
|
|
||||||
number: (
|
|
||||||
isRunning && metrics
|
|
||||||
? +metrics.VCPUs_number
|
|
||||||
: +obj.VCPUs_at_startup
|
|
||||||
)
|
|
||||||
},
|
|
||||||
current_operations: obj.current_operations,
|
|
||||||
docker: (function () {
|
|
||||||
const monitor = otherConfig['xscontainer-monitor']
|
|
||||||
if (!monitor) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monitor === 'False') {
|
|
||||||
return {
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
docker_ps: process,
|
|
||||||
docker_info: info,
|
|
||||||
docker_version: version
|
|
||||||
} = otherConfig
|
|
||||||
|
|
||||||
return {
|
|
||||||
enabled: true,
|
|
||||||
info: info && parseXml(info).docker_info,
|
|
||||||
process: process && parseXml(process).docker_ps,
|
|
||||||
version: version && parseXml(version).docker_version
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
|
|
||||||
// TODO: there is two possible value: "best-effort" and "restart"
|
|
||||||
high_availability: Boolean(obj.ha_restart_priority),
|
|
||||||
|
|
||||||
memory: (function () {
|
|
||||||
const dynamicMin = +obj.memory_dynamic_min
|
|
||||||
const dynamicMax = +obj.memory_dynamic_max
|
|
||||||
const staticMin = +obj.memory_static_min
|
|
||||||
const staticMax = +obj.memory_static_max
|
|
||||||
|
|
||||||
const memory = {
|
|
||||||
dynamic: [ dynamicMin, dynamicMax ],
|
|
||||||
static: [ staticMin, staticMax ]
|
|
||||||
}
|
|
||||||
|
|
||||||
const gmMemory = guestMetrics && guestMetrics.memory
|
|
||||||
|
|
||||||
if (!isRunning) {
|
|
||||||
memory.size = dynamicMax
|
|
||||||
} else if (gmMemory && gmMemory.used) {
|
|
||||||
memory.usage = +gmMemory.used
|
|
||||||
memory.size = +gmMemory.total
|
|
||||||
} else if (metrics) {
|
|
||||||
memory.size = +metrics.memory_actual
|
|
||||||
} else {
|
|
||||||
memory.size = dynamicMax
|
|
||||||
}
|
|
||||||
|
|
||||||
return memory
|
|
||||||
})(),
|
|
||||||
name_description: obj.name_description,
|
|
||||||
name_label: obj.name_label,
|
|
||||||
other: otherConfig,
|
|
||||||
os_version: guestMetrics && guestMetrics.os_version || null,
|
|
||||||
power_state: obj.power_state,
|
|
||||||
snapshot_time: toTimestamp(obj.snapshot_time),
|
|
||||||
snapshots: link(obj, 'snapshots'),
|
|
||||||
tags: obj.tags,
|
|
||||||
VIFs: link(obj, 'VIFs'),
|
|
||||||
virtualizationMode: isHvm ? 'hvm' : 'pv',
|
|
||||||
|
|
||||||
// <=> Are the Xen Server tools installed?
|
|
||||||
//
|
|
||||||
// - undefined: unknown status
|
|
||||||
// - false: not optimized
|
|
||||||
// - 'out of date': optimized but drivers should be updated
|
|
||||||
// - 'up to date': optimized
|
|
||||||
xenTools: (() => {
|
|
||||||
if (!isRunning || !metrics) {
|
|
||||||
// Unknown status, returns nothing.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!guestMetrics) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const { PV_drivers_version: { major, minor } } = guestMetrics
|
|
||||||
if (major === undefined || minor === undefined) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return guestMetrics.PV_drivers_up_to_date
|
|
||||||
? 'up to date'
|
|
||||||
: 'out of date'
|
|
||||||
})(),
|
|
||||||
|
|
||||||
$container: (
|
|
||||||
isRunning
|
|
||||||
? link(obj, 'resident_on')
|
|
||||||
: link(obj, 'pool') // TODO: handle local VMs (`VM.get_possible_hosts()`).
|
|
||||||
),
|
|
||||||
$VBDs: link(obj, 'VBDs'),
|
|
||||||
|
|
||||||
// TODO: dedupe
|
|
||||||
VGPUs: link(obj, 'VGPUs'),
|
|
||||||
$VGPUs: link(obj, 'VGPUs')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.is_control_domain) {
|
|
||||||
vm.type += '-controller'
|
|
||||||
} else if (obj.is_a_snapshot) {
|
|
||||||
vm.type += '-snapshot'
|
|
||||||
|
|
||||||
vm.$snapshot_of = link(obj, 'snapshot_of')
|
|
||||||
} else if (obj.is_a_template) {
|
|
||||||
vm.type += '-template'
|
|
||||||
|
|
||||||
vm.CPUs.number = +obj.VCPUs_at_startup
|
|
||||||
vm.template_info = {
|
|
||||||
arch: otherConfig['install-arch'],
|
|
||||||
disks: (function () {
|
|
||||||
const {disks: xml} = otherConfig
|
|
||||||
let data
|
|
||||||
if (!xml || !(data = parseXml(xml)).provision) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const disks = ensureArray(data.provision.disk)
|
|
||||||
forEach(disks, function normalize (disk) {
|
|
||||||
disk.bootable = disk.bootable === 'true'
|
|
||||||
disk.size = +disk.size
|
|
||||||
disk.SR = extractProperty(disk, 'sr')
|
|
||||||
})
|
|
||||||
|
|
||||||
return disks
|
|
||||||
})(),
|
|
||||||
install_methods: (function () {
|
|
||||||
const {['install-methods']: methods} = otherConfig
|
|
||||||
|
|
||||||
return methods ? methods.split(',') : []
|
|
||||||
})()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isHvm) {
|
|
||||||
vm.PV_args = obj.PV_args
|
|
||||||
}
|
|
||||||
|
|
||||||
return vm
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function sr (obj) {
|
|
||||||
return {
|
|
||||||
type: 'SR',
|
|
||||||
|
|
||||||
content_type: obj.content_type,
|
|
||||||
name_description: obj.name_description,
|
|
||||||
name_label: obj.name_label,
|
|
||||||
physical_usage: +obj.physical_utilisation,
|
|
||||||
size: +obj.physical_size,
|
|
||||||
SR_type: obj.type,
|
|
||||||
tags: obj.tags,
|
|
||||||
usage: +obj.virtual_allocation,
|
|
||||||
VDIs: link(obj, 'VDIs'),
|
|
||||||
|
|
||||||
$container: (
|
|
||||||
obj.shared
|
|
||||||
? link(obj, 'pool')
|
|
||||||
: obj.$PBDs[0] && link(obj.$PBDs[0], 'host')
|
|
||||||
),
|
|
||||||
$PBDs: link(obj, 'PBDs')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function pbd (obj) {
|
|
||||||
return {
|
|
||||||
type: 'PBD',
|
|
||||||
|
|
||||||
attached: obj.currently_attached,
|
|
||||||
host: link(obj, 'host'),
|
|
||||||
SR: link(obj, 'SR')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function pif (obj) {
|
|
||||||
return {
|
|
||||||
type: 'PIF',
|
|
||||||
|
|
||||||
attached: Boolean(obj.currently_attached),
|
|
||||||
device: obj.device,
|
|
||||||
IP: obj.IP,
|
|
||||||
MAC: obj.MAC,
|
|
||||||
management: Boolean(obj.management), // TODO: find a better name.
|
|
||||||
mode: obj.ip_configuration_mode,
|
|
||||||
MTU: +obj.MTU,
|
|
||||||
netmask: obj.netmask,
|
|
||||||
vlan: +obj.VLAN,
|
|
||||||
|
|
||||||
// TODO: What is it?
|
|
||||||
//
|
|
||||||
// Could it mean “is this a physical interface?”.
|
|
||||||
// How could a PIF not be physical?
|
|
||||||
// physical: obj.physical,
|
|
||||||
|
|
||||||
$host: link(obj, 'host'),
|
|
||||||
$network: link(obj, 'network')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
// TODO: should we have a VDI-snapshot type like we have with VMs?
|
|
||||||
export function vdi (obj) {
|
|
||||||
if (!obj.managed) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: 'VDI',
|
|
||||||
|
|
||||||
name_description: obj.name_description,
|
|
||||||
name_label: obj.name_label,
|
|
||||||
size: +obj.virtual_size,
|
|
||||||
snapshots: link(obj, 'snapshots'),
|
|
||||||
snapshot_time: toTimestamp(obj.snapshot_time),
|
|
||||||
tags: obj.tags,
|
|
||||||
usage: +obj.physical_utilisation,
|
|
||||||
|
|
||||||
$snapshot_of: link(obj, 'snapshot_of'),
|
|
||||||
$SR: link(obj, 'SR'),
|
|
||||||
$VBDs: link(obj, 'VBDs')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function vbd (obj) {
|
|
||||||
return {
|
|
||||||
type: 'VBD',
|
|
||||||
|
|
||||||
attached: Boolean(obj.currently_attached),
|
|
||||||
bootable: Boolean(obj.bootable),
|
|
||||||
is_cd_drive: obj.type === 'CD',
|
|
||||||
position: obj.userdevice,
|
|
||||||
read_only: obj.mode === 'RO',
|
|
||||||
VDI: link(obj, 'VDI'),
|
|
||||||
VM: link(obj, 'VM')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function vif (obj) {
|
|
||||||
return {
|
|
||||||
type: 'VIF',
|
|
||||||
|
|
||||||
attached: Boolean(obj.currently_attached),
|
|
||||||
device: obj.device, // TODO: should it be cast to a number?
|
|
||||||
MAC: obj.MAC,
|
|
||||||
MTU: +obj.MTU,
|
|
||||||
|
|
||||||
$network: link(obj, 'network'),
|
|
||||||
$VM: link(obj, 'VM')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function network (obj) {
|
|
||||||
return {
|
|
||||||
bridge: obj.bridge,
|
|
||||||
MTU: +obj.MTU,
|
|
||||||
name_description: obj.name_description,
|
|
||||||
name_label: obj.name_label,
|
|
||||||
tags: obj.tags,
|
|
||||||
PIFs: link(obj, 'PIFs'),
|
|
||||||
VIFs: link(obj, 'VIFs')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function message (obj) {
|
|
||||||
return {
|
|
||||||
body: obj.body,
|
|
||||||
name: obj.name,
|
|
||||||
time: toTimestamp(obj.timestamp),
|
|
||||||
|
|
||||||
$object: obj.obj_uuid // Special link as it is already an UUID.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function task (obj) {
|
|
||||||
return {
|
|
||||||
created: toTimestamp(obj.created),
|
|
||||||
current_operations: obj.current_operations,
|
|
||||||
finished: toTimestamp(obj.finished),
|
|
||||||
name_description: obj.name_description,
|
|
||||||
name_label: obj.name_label,
|
|
||||||
progress: +obj.progress,
|
|
||||||
result: obj.result,
|
|
||||||
status: obj.status,
|
|
||||||
|
|
||||||
$host: link(obj, 'resident_on')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function host_patch (obj) {
|
|
||||||
return {
|
|
||||||
applied: Boolean(obj.applied),
|
|
||||||
time: toTimestamp(obj.timestamp_applied),
|
|
||||||
pool_patch: link(obj, 'pool_patch', '$ref'),
|
|
||||||
|
|
||||||
$host: link(obj, 'host')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function pool_patch (obj) {
|
|
||||||
return {
|
|
||||||
id: obj.$ref,
|
|
||||||
|
|
||||||
applied: Boolean(obj.pool_applied),
|
|
||||||
description: obj.name_description,
|
|
||||||
guidance: obj.after_apply_guidance,
|
|
||||||
name: obj.name_label,
|
|
||||||
size: +obj.size,
|
|
||||||
uuid: obj.uuid,
|
|
||||||
|
|
||||||
// TODO: what does it mean, should we handle it?
|
|
||||||
// version: obj.version,
|
|
||||||
|
|
||||||
// TODO: host.[$]pool_patches ←→ pool.[$]host_patches
|
|
||||||
$host_patches: link(obj, 'host_patches')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function pci (obj) {
|
|
||||||
return {
|
|
||||||
type: 'PCI',
|
|
||||||
|
|
||||||
class_name: obj.class_name,
|
|
||||||
device_name: obj.device_name,
|
|
||||||
pci_id: obj.pci_id,
|
|
||||||
|
|
||||||
$host: link(obj, 'host')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function pgpu (obj) {
|
|
||||||
return {
|
|
||||||
type: 'PGPU',
|
|
||||||
|
|
||||||
pci: link(obj, 'PCI'),
|
|
||||||
|
|
||||||
// TODO: dedupe.
|
|
||||||
host: link(obj, 'host'),
|
|
||||||
$host: link(obj, 'host'),
|
|
||||||
vgpus: link(obj, 'resident_VGPUs'),
|
|
||||||
$vgpus: link(obj, 'resident_VGPUs')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function vgpu (obj) {
|
|
||||||
return {
|
|
||||||
type: 'VGPU',
|
|
||||||
|
|
||||||
currentlyAttached: Boolean(obj.currently_attached),
|
|
||||||
device: obj.device,
|
|
||||||
resident_on: link(obj, 'resident_on'),
|
|
||||||
vm: link(obj, 'VM')
|
|
||||||
}
|
|
||||||
}
|
|
66
src/xapi.js
66
src/xapi.js
@ -77,7 +77,7 @@ const getNamespaceForType = (type) => typeToNamespace[type] || type
|
|||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
// Format a date (pseudo ISO 8601) from one XenServer get by
|
// Format a date (pseudo ISO 8601) from one XenServer get by
|
||||||
// xapi.call('host.get_servertime', host.ref) for example
|
// xapi.call('host.get_servertime', host.$ref) for example
|
||||||
export const formatDateTime = d3TimeFormat.utcFormat('%Y%m%dT%H:%M:%SZ')
|
export const formatDateTime = d3TimeFormat.utcFormat('%Y%m%dT%H:%M:%SZ')
|
||||||
|
|
||||||
export const parseDateTime = formatDateTime.parse
|
export const parseDateTime = formatDateTime.parse
|
||||||
@ -232,6 +232,16 @@ export default class Xapi extends XapiBase {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setHostProperties (id, {
|
||||||
|
name_label,
|
||||||
|
name_description
|
||||||
|
}) {
|
||||||
|
await this._setObjectProperties(this.getObject(id), {
|
||||||
|
name_label,
|
||||||
|
name_description
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async setPoolProperties ({
|
async setPoolProperties ({
|
||||||
name_label,
|
name_label,
|
||||||
name_description
|
name_description
|
||||||
@ -552,6 +562,60 @@ export default class Xapi extends XapiBase {
|
|||||||
|
|
||||||
// =================================================================
|
// =================================================================
|
||||||
|
|
||||||
|
// Disable the host and evacuate all its VMs.
|
||||||
|
//
|
||||||
|
// If `force` is false and the evacuation failed, the host is re-
|
||||||
|
// enabled and the error is thrown.
|
||||||
|
async _clearHost ({ $ref, ref }, force) {
|
||||||
|
await this.call('host.disable', ref)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.call('host.evacuate', ref)
|
||||||
|
} catch (error) {
|
||||||
|
if (!force) {
|
||||||
|
await this.call('host.enabled', ref)
|
||||||
|
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async disableHost (hostId) {
|
||||||
|
await this.call('host.disable', this.getObject(hostId).$ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
async ejectHostFromPool (hostId) {
|
||||||
|
await this.call('pool.eject', this.getObject(hostId).$ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
async enableHost (hostId) {
|
||||||
|
await this.call('host.enable', this.getObject(hostId).$ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
async powerOnHost (hostId) {
|
||||||
|
await this.call('host.power_on', this.getObject(hostId).$ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
async rebootHost (hostId, force = false) {
|
||||||
|
const host = this.getObject(hostId)
|
||||||
|
|
||||||
|
await this._clearHost(host, force)
|
||||||
|
await this.call('host.reboot', host.$ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
async restartHostAgent (hostId) {
|
||||||
|
await this.call('host.restart_agent', this.getObject(hostId).$ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
async shutdownHost (hostId, force = false) {
|
||||||
|
const host = this.getObject(hostId)
|
||||||
|
|
||||||
|
await this._clearHost(host, force)
|
||||||
|
await this.call('host.shutdown', host.$ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
// =================================================================
|
||||||
|
|
||||||
// Clone a VM: make a fast copy by fast copying each of its VDIs
|
// Clone a VM: make a fast copy by fast copying each of its VDIs
|
||||||
// (using snapshots where possible) on the same SRs.
|
// (using snapshots where possible) on the same SRs.
|
||||||
async _cloneVm (vm, nameLabel = vm.name_label) {
|
async _cloneVm (vm, nameLabel = vm.name_label) {
|
||||||
|
129
src/xo.js
129
src/xo.js
@ -21,14 +21,13 @@ import {
|
|||||||
verify
|
verify
|
||||||
} from 'hashy'
|
} from 'hashy'
|
||||||
|
|
||||||
import * as xapiObjectsToXo from './xapi-objects-to-xo'
|
|
||||||
import checkAuthorization from './acl'
|
import checkAuthorization from './acl'
|
||||||
import Connection from './connection'
|
import Connection from './connection'
|
||||||
import LevelDbLogger from './loggers/leveldb'
|
import LevelDbLogger from './loggers/leveldb'
|
||||||
import Xapi from './xapi'
|
import Xapi from './xapi'
|
||||||
|
import xapiObjectToXo from './xapi-object-to-xo'
|
||||||
import XapiStats from './xapi-stats'
|
import XapiStats from './xapi-stats'
|
||||||
import {Acls} from './models/acl'
|
import {Acls} from './models/acl'
|
||||||
import {autobind} from './decorators'
|
|
||||||
import {
|
import {
|
||||||
createRawObject,
|
createRawObject,
|
||||||
forEach,
|
forEach,
|
||||||
@ -110,7 +109,7 @@ export default class Xo extends EventEmitter {
|
|||||||
super()
|
super()
|
||||||
|
|
||||||
this._objects = new XoCollection()
|
this._objects = new XoCollection()
|
||||||
this._objects.createIndex('byRef', new XoUniqueIndex('ref'))
|
this._objects.createIndex('byRef', new XoUniqueIndex('_xapiRef'))
|
||||||
|
|
||||||
// These will be initialized in start()
|
// These will be initialized in start()
|
||||||
//
|
//
|
||||||
@ -788,7 +787,7 @@ export default class Xo extends EventEmitter {
|
|||||||
const targetStream = fs.createWriteStream(pathToFile, { flags: 'wx' })
|
const targetStream = fs.createWriteStream(pathToFile, { flags: 'wx' })
|
||||||
const promise = eventToPromise(targetStream, 'finish')
|
const promise = eventToPromise(targetStream, 'finish')
|
||||||
|
|
||||||
const sourceStream = await this.getXAPI(vm).exportVm(vm.id, {
|
const sourceStream = await this.getXAPI(vm).exportVm(vm._xapiId, {
|
||||||
compress,
|
compress,
|
||||||
onlyMetadata: onlyMetadata || false
|
onlyMetadata: onlyMetadata || false
|
||||||
})
|
})
|
||||||
@ -821,7 +820,7 @@ export default class Xo extends EventEmitter {
|
|||||||
|
|
||||||
async rollingSnapshotVm (vm, tag, depth) {
|
async rollingSnapshotVm (vm, tag, depth) {
|
||||||
const xapi = this.getXAPI(vm)
|
const xapi = this.getXAPI(vm)
|
||||||
vm = xapi.getObject(vm.id)
|
vm = xapi.getObject(vm._xapiId)
|
||||||
|
|
||||||
const reg = new RegExp('^rollingSnapshot_[^_]+_' + escapeStringRegexp(tag) + '_')
|
const reg = new RegExp('^rollingSnapshot_[^_]+_' + escapeStringRegexp(tag) + '_')
|
||||||
const snapshots = sortBy(filter(vm.$snapshots, snapshot => reg.test(snapshot.name_label)), 'name_label')
|
const snapshots = sortBy(filter(vm.$snapshots, snapshot => reg.test(snapshot.name_label)), 'name_label')
|
||||||
@ -842,9 +841,9 @@ export default class Xo extends EventEmitter {
|
|||||||
const reg = new RegExp('^' + escapeStringRegexp(`${vm.name_label}_${tag}_`) + '[0-9]{8}T[0-9]{6}Z$')
|
const reg = new RegExp('^' + escapeStringRegexp(`${vm.name_label}_${tag}_`) + '[0-9]{8}T[0-9]{6}Z$')
|
||||||
|
|
||||||
const targetXapi = this.getXAPI(sr)
|
const targetXapi = this.getXAPI(sr)
|
||||||
sr = targetXapi.getObject(sr.id)
|
sr = targetXapi.getObject(sr._xapiId)
|
||||||
const sourceXapi = this.getXAPI(vm)
|
const sourceXapi = this.getXAPI(vm)
|
||||||
vm = sourceXapi.getObject(vm.id)
|
vm = sourceXapi.getObject(vm._xapiId)
|
||||||
|
|
||||||
const vms = []
|
const vms = []
|
||||||
forEach(sr.$VDIs, vdi => {
|
forEach(sr.$VDIs, vdi => {
|
||||||
@ -934,48 +933,28 @@ export default class Xo extends EventEmitter {
|
|||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
_onXenAdd (xapiObjects, xapiIdsToXo) {
|
||||||
_onXenAdd (xapiObjects) {
|
|
||||||
const {_objects: objects} = this
|
const {_objects: objects} = this
|
||||||
forEach(xapiObjects, (xapiObject, id) => {
|
forEach(xapiObjects, (xapiObject, xapiId) => {
|
||||||
const transform = xapiObjectsToXo[xapiObject.$type]
|
const xoObject = xapiObjectToXo(xapiObject)
|
||||||
if (!transform) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const xoObject = transform(xapiObject)
|
if (xoObject) {
|
||||||
if (!xoObject) {
|
xapiIdsToXo[xapiId] = xoObject.id
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!xoObject.id) {
|
objects.set(xoObject)
|
||||||
xoObject.id = id
|
|
||||||
}
|
}
|
||||||
xoObject.ref = xapiObject.$ref
|
|
||||||
if (!xoObject.type) {
|
|
||||||
xoObject.type = xapiObject.$type
|
|
||||||
}
|
|
||||||
|
|
||||||
const {$pool: pool} = xapiObject
|
|
||||||
Object.defineProperties(xoObject, {
|
|
||||||
poolRef: { value: pool.$ref },
|
|
||||||
$poolId: {
|
|
||||||
enumerable: true,
|
|
||||||
value: pool.$id
|
|
||||||
},
|
|
||||||
ref: { value: xapiObject.$ref }
|
|
||||||
})
|
|
||||||
|
|
||||||
objects.set(xoObject)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
_onXenRemove (xapiObjects, xapiIdsToXo) {
|
||||||
_onXenRemove (xapiObjects) {
|
|
||||||
const {_objects: objects} = this
|
const {_objects: objects} = this
|
||||||
forEach(xapiObjects, (_, id) => {
|
forEach(xapiObjects, (_, xapiId) => {
|
||||||
if (objects.has(id)) {
|
const xoId = xapiIdsToXo[xapiId]
|
||||||
objects.remove(id)
|
|
||||||
|
if (xoId) {
|
||||||
|
delete xapiIdsToXo[xapiId]
|
||||||
|
|
||||||
|
objects.unset(xoId)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -992,16 +971,41 @@ export default class Xo extends EventEmitter {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const {objects} = xapi
|
xapi.xo = (() => {
|
||||||
objects.on('add', this._onXenAdd)
|
const xapiIdsToXo = createRawObject()
|
||||||
objects.on('update', this._onXenAdd)
|
const onAddOrUpdate = objects => {
|
||||||
objects.on('remove', this._onXenRemove)
|
this._onXenAdd(objects, xapiIdsToXo)
|
||||||
|
}
|
||||||
|
const onRemove = objects => {
|
||||||
|
this._onXenRemove(objects, xapiIdsToXo)
|
||||||
|
}
|
||||||
|
const onFinish = () => {
|
||||||
|
this._xapis[xapi.pool.$id] = xapi
|
||||||
|
}
|
||||||
|
|
||||||
// Each time objects are refreshed, registers the connection with
|
const { objects } = xapi
|
||||||
// the pool identifier.
|
|
||||||
objects.on('finish', () => {
|
return {
|
||||||
this._xapis[xapi.pool.$id] = xapi
|
install () {
|
||||||
})
|
objects.on('add', onAddOrUpdate)
|
||||||
|
objects.on('update', onAddOrUpdate)
|
||||||
|
objects.on('remove', onRemove)
|
||||||
|
objects.on('finish', onFinish)
|
||||||
|
|
||||||
|
onAddOrUpdate(objects.all)
|
||||||
|
},
|
||||||
|
uninstall () {
|
||||||
|
objects.removeListener('add', onAddOrUpdate)
|
||||||
|
objects.removeListener('update', onAddOrUpdate)
|
||||||
|
objects.removeListener('remove', onRemove)
|
||||||
|
objects.removeListener('finish', onFinish)
|
||||||
|
|
||||||
|
onRemove(objects.all)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
xapi.xo.install()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await xapi.connect()
|
await xapi.connect()
|
||||||
@ -1028,6 +1032,7 @@ export default class Xo extends EventEmitter {
|
|||||||
delete this._xapis[xapi.pool.id]
|
delete this._xapis[xapi.pool.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xapi.xo.uninstall()
|
||||||
return xapi.disconnect()
|
return xapi.disconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1037,7 +1042,7 @@ export default class Xo extends EventEmitter {
|
|||||||
object = this.getObject(object, type)
|
object = this.getObject(object, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
const {$poolId: poolId} = object
|
const { $pool: poolId } = object
|
||||||
if (!poolId) {
|
if (!poolId) {
|
||||||
throw new Error(`object ${object.id} does not belong to a pool`)
|
throw new Error(`object ${object.id} does not belong to a pool`)
|
||||||
}
|
}
|
||||||
@ -1052,12 +1057,12 @@ export default class Xo extends EventEmitter {
|
|||||||
|
|
||||||
getXapiVmStats (vm, granularity) {
|
getXapiVmStats (vm, granularity) {
|
||||||
const xapi = this.getXAPI(vm)
|
const xapi = this.getXAPI(vm)
|
||||||
return this._xapiStats.getVmPoints(xapi, vm.id, granularity)
|
return this._xapiStats.getVmPoints(xapi, vm._xapiId, granularity)
|
||||||
}
|
}
|
||||||
|
|
||||||
getXapiHostStats (host, granularity) {
|
getXapiHostStats (host, granularity) {
|
||||||
const xapi = this.getXAPI(host)
|
const xapi = this.getXAPI(host)
|
||||||
return this._xapiStats.getHostPoints(xapi, host.id, granularity)
|
return this._xapiStats.getHostPoints(xapi, host._xapiId, granularity)
|
||||||
}
|
}
|
||||||
|
|
||||||
async mergeXenPools (sourceId, targetId, force = false) {
|
async mergeXenPools (sourceId, targetId, force = false) {
|
||||||
@ -1069,26 +1074,12 @@ export default class Xo extends EventEmitter {
|
|||||||
|
|
||||||
// We don't want the events of the source XAPI to interfere with
|
// We don't want the events of the source XAPI to interfere with
|
||||||
// the events of the new XAPI.
|
// the events of the new XAPI.
|
||||||
{
|
sourceXapi.xo.uninstall()
|
||||||
const {objects} = sourceXapi
|
|
||||||
|
|
||||||
objects.removeListener('add', this._onXenAdd)
|
|
||||||
objects.removeListener('update', this._onXenAdd)
|
|
||||||
objects.removeListener('remove', this._onXenRemove)
|
|
||||||
|
|
||||||
this._onXenRemove(objects.all)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await sourceXapi.joinPool(hostname, user, password, force)
|
await sourceXapi.joinPool(hostname, user, password, force)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const {objects} = sourceXapi
|
sourceXapi.xo.install()
|
||||||
|
|
||||||
objects.on('add', this._onXenAdd)
|
|
||||||
objects.on('update', this._onXenAdd)
|
|
||||||
objects.on('remove', this._onXenRemove)
|
|
||||||
|
|
||||||
this._onXenAdd(objects.all)
|
|
||||||
|
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user