Merge pull request #208 from vatesfr/pierre-vm-migration-details

Custom VM migration. (See vatesfr/xo-web#567)
This commit is contained in:
Olivier Lambert 2016-01-28 17:02:28 +01:00
commit 7f9c49cbc4
2 changed files with 72 additions and 66 deletions

View File

@ -191,69 +191,71 @@ exports.insertCd = insertCd
#---------------------------------------------------------------------
migrate = $coroutine ({vm, host}) ->
yield @getXapi(vm).migrateVm(vm._xapiId, @getXapi(host), host._xapiId)
return
migrate.params = {
# Identifier of the VM to migrate.
id: { type: 'string' }
# Identifier of the host to migrate to.
host_id: { type: 'string' }
}
migrate.resolve = {
vm: ['id', 'VM']
host: ['host_id', 'host', 'administrate']
}
exports.migrate = migrate
#---------------------------------------------------------------------
migratePool = $coroutine ({
migrate = $coroutine ({
vm,
host
sr
network
host,
mapVdisSrs,
mapVifsNetworks,
migrationNetwork
}) ->
mapVdisSrsXapi = {}
forEach mapVdisSrs, (srId, vdiId) =>
vdiXapiId = @getObject(vdiId, 'VDI')._xapiId
mapVdisSrsXapi[vdiXapiId] = @getObject(srId, 'SR')._xapiId
mapVifsNetworksXapi = {}
forEach mapVifsNetworks, (networkId, vifId) =>
vifXapiId = @getObject(vifId, 'VIF')._xapiId
mapVifsNetworksXapi[vifXapiId] = @getObject(networkId, 'network')._xapiId
permissions = []
for vif, network of mapVifsNetworks
permissions.push([
network,
'administrate'
])
for vdi, sr of mapVdisSrs
permissions.push([
sr,
'administrate'
])
unless yield @hasPermissions(@session.get('user_id'), permissions)
throw new Unauthorized()
yield @getXapi(vm).migrateVm(vm._xapiId, @getXapi(host), host._xapiId, {
migrationNetworkId: migrationNetwork?._xapiId
networkId: network?._xapiId,
srId: sr?._xapiId,
mapVifsNetworksXapi,
mapVdisSrsXapi,
})
return
migratePool.params = {
migrate.params = {
# Identifier of the VM to migrate.
id: { type: 'string' }
vm: { type: 'string' }
# Identifier of the host to migrate to.
target_host_id: { type: 'string' }
targetHost: { type: 'string' }
# Identifier of the target SR
target_sr_id: { type: 'string', optional: true }
# Map VDIs IDs --> SRs IDs
mapVdisSrs: { type: 'object', optional: true }
# Identifier of the target Network
target_network_id: { type: 'string', optional: true }
# Map VIFs IDs --> Networks IDs
mapVifsNetworks: { type: 'object', optional: true }
# Identifier of the Network use for the migration
migration_network_id: { type: 'string', optional: true }
migrationNetwork: { type: 'string', optional: true }
}
migratePool.resolve = {
vm: ['id', 'VM', 'administrate'],
host: ['target_host_id', 'host', 'administrate'],
sr: ['target_sr_id', 'SR', 'administrate'],
network: ['target_network_id', 'network', 'administrate'],
migrationNetwork: ['migration_network_id', 'network', 'administrate'],
migrate.resolve = {
vm: ['vm', 'VM', 'administrate'],
host: ['targetHost', 'host', 'administrate'],
migrationNetwork: ['migrationNetwork', 'network', 'administrate'],
}
# TODO: camel case.
exports.migrate_pool = migratePool
exports.migrate = migrate
#---------------------------------------------------------------------

View File

@ -1504,18 +1504,32 @@ export default class Xapi extends XapiBase {
return vm
}
async _migrateVMWithStorageMotion (vm, hostXapi, host, {
async _migrateVmWithStorageMotion (vm, hostXapi, host, {
migrationNetwork = find(host.$PIFs, pif => pif.management).$network, // TODO: handle not found
sr = host.$pool.$default_SR, // TODO: handle not found
vifsMap = {}
mapVdisSrs,
mapVifsNetworks
}) {
// VDIs/SRs mapping
const vdis = {}
const defaultSrRef = host.$pool.$default_SR.$ref
for (const vbd of vm.$VBDs) {
if (vbd.type !== 'CD') {
vdis[vbd.$VDI.$ref] = sr.$ref
const vdi = vbd.$VDI
if (vbd.type === 'Disk') {
vdis[vdi.$ref] = mapVdisSrs && mapVdisSrs[vdi.$id]
? hostXapi.getObject(mapVdisSrs[vdi.$id]).$ref
: defaultSrRef
}
}
// VIFs/Networks mapping
const vifsMap = {}
const defaultNetworkRef = find(host.$PIFs, pif => pif.management).$network.$ref
for (const vif of vm.$VIFs) {
vifsMap[vif.$ref] = mapVifsNetworks && mapVifsNetworks[vif.$id]
? hostXapi.getObject(mapVifsNetworks[vif.$id]).$ref
: defaultNetworkRef
}
const token = await hostXapi.call(
'host.migrate_receive',
host.$ref,
@ -1596,8 +1610,8 @@ export default class Xapi extends XapiBase {
async migrateVm (vmId, hostXapi, hostId, {
migrationNetworkId,
networkId,
srId
mapVifsNetworks,
mapVdisSrs
} = {}) {
const vm = this.getObject(vmId)
if (!isVmRunning(vm)) {
@ -1610,25 +1624,15 @@ export default class Xapi extends XapiBase {
const useStorageMotion = (
accrossPools ||
migrationNetworkId ||
networkId ||
srId
mapVifsNetworks ||
mapVdisSrs
)
if (useStorageMotion) {
const vifsMap = {}
if (accrossPools || networkId) {
const {$ref: networkRef} = networkId
? hostXapi.getObject(networkId)
: find(host.$PIFs, pif => pif.management).$network
for (const vif of vm.$VIFs) {
vifsMap[vif.$ref] = networkRef
}
}
await this._migrateVMWithStorageMotion(vm, hostXapi, host, {
await this._migrateVmWithStorageMotion(vm, hostXapi, host, {
migrationNetwork: migrationNetworkId && hostXapi.getObject(migrationNetworkId),
sr: srId && hostXapi.getObject(srId),
vifsMap
mapVdisSrs,
mapVifsNetworks
})
} else {
try {
@ -1639,7 +1643,7 @@ export default class Xapi extends XapiBase {
}
// Retry using motion storage.
await this._migrateVMWithStorageMotion(vm, hostXapi, host, {})
await this._migrateVmWithStorageMotion(vm, hostXapi, host, {})
}
}
}