Merge pull request #90 from vatesfr/better-vm-migration
Better VM migration.
This commit is contained in:
commit
693af532a2
@ -175,14 +175,8 @@ exports.insertCd = insertCd
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
migrate = $coroutine ({vm, host}) ->
|
migrate = $coroutine ({vm, host}) ->
|
||||||
unless $isVMRunning vm
|
yield @getXAPI(vm).migrateVm(vm.id, @getXAPI(host), host.id)
|
||||||
@throw 'INVALID_PARAMS', 'The VM can only be migrated when running'
|
return
|
||||||
|
|
||||||
xapi = @getXAPI vm
|
|
||||||
|
|
||||||
yield xapi.call 'VM.pool_migrate', vm.ref, host.ref, {'force': 'true'}
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
migrate.params = {
|
migrate.params = {
|
||||||
# Identifier of the VM to migrate.
|
# Identifier of the VM to migrate.
|
||||||
@ -202,62 +196,18 @@ exports.migrate = migrate
|
|||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
migratePool = $coroutine ({
|
migratePool = $coroutine ({
|
||||||
vm: VM,
|
vm,
|
||||||
host
|
host
|
||||||
sr: SR
|
sr
|
||||||
network
|
network
|
||||||
migrationNetwork
|
migrationNetwork
|
||||||
}) ->
|
}) ->
|
||||||
# TODO: map multiple VDI and VIF
|
yield @getXAPI(vm).migrateVm(vm.id, @getXAPI(host), host.id, {
|
||||||
|
migrationNetworkId: migrationNetwork?.id
|
||||||
# Optional parameters
|
networkId: network?.id,
|
||||||
# if no network given, try to use the management network
|
srId: sr?.id,
|
||||||
unless network
|
})
|
||||||
PIF = $findWhere (@getObjects host.$PIFs), management: true
|
return
|
||||||
network = @getObject PIF.$network, 'network'
|
|
||||||
|
|
||||||
# if no migrationNetwork, use the network
|
|
||||||
migrationNetwork ?= network
|
|
||||||
|
|
||||||
# if no sr is given, try to find the default Pool SR
|
|
||||||
unless SR
|
|
||||||
pool = @getObject host.poolRef, 'pool'
|
|
||||||
target_sr_id = pool.default_SR
|
|
||||||
SR = @getObject target_sr_id, 'SR'
|
|
||||||
|
|
||||||
unless $isVMRunning VM
|
|
||||||
@throw 'INVALID_PARAMS', 'The VM can only be migrated when running'
|
|
||||||
|
|
||||||
vdiMap = {}
|
|
||||||
for vbdId in VM.$VBDs
|
|
||||||
VBD = @getObject vbdId, 'VBD'
|
|
||||||
continue if VBD.is_cd_drive
|
|
||||||
VDI = @getObject VBD.VDI, 'VDI'
|
|
||||||
vdiMap[VDI.ref] = SR.ref
|
|
||||||
|
|
||||||
vifMap = {}
|
|
||||||
for vifId in VM.VIFs
|
|
||||||
VIF = @getObject vifId, 'VIF'
|
|
||||||
vifMap[VIF.ref] = network.ref
|
|
||||||
|
|
||||||
token = yield (@getXAPI host).call(
|
|
||||||
'host.migrate_receive'
|
|
||||||
host.ref
|
|
||||||
migrationNetwork.ref
|
|
||||||
{} # Other parameters
|
|
||||||
)
|
|
||||||
|
|
||||||
yield (@getXAPI VM).call(
|
|
||||||
'VM.migrate_send'
|
|
||||||
VM.ref
|
|
||||||
token
|
|
||||||
true # Live migration
|
|
||||||
vdiMap
|
|
||||||
vifMap
|
|
||||||
{'force': 'true'} # Force migration even if CPUs are different
|
|
||||||
)
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
migratePool.params = {
|
migratePool.params = {
|
||||||
|
|
||||||
|
82
src/xapi.js
82
src/xapi.js
@ -662,6 +662,88 @@ export default class Xapi extends XapiBase {
|
|||||||
return stream
|
return stream
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = {}
|
||||||
|
}) {
|
||||||
|
const vdis = {}
|
||||||
|
for (const vbd of vm.$VBDs) {
|
||||||
|
if (vbd.type !== 'CD') {
|
||||||
|
vdis[vbd.$VDI.$ref] = sr.$ref
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = await hostXapi.call(
|
||||||
|
'host.migrate_receive',
|
||||||
|
host.$ref,
|
||||||
|
migrationNetwork.$ref,
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
await this.call(
|
||||||
|
'VM.migrate_send',
|
||||||
|
vm.$ref,
|
||||||
|
token,
|
||||||
|
true, // Live migration.
|
||||||
|
vdis,
|
||||||
|
vifsMap,
|
||||||
|
{
|
||||||
|
force: 'true'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async migrateVm (vmId, hostXapi, hostId, {
|
||||||
|
migrationNetworkId,
|
||||||
|
networkId,
|
||||||
|
srId
|
||||||
|
} = {}) {
|
||||||
|
const vm = this.getObject(vmId)
|
||||||
|
if (!isVmRunning(vm)) {
|
||||||
|
throw new Error('cannot migrate a non-running VM')
|
||||||
|
}
|
||||||
|
|
||||||
|
const host = hostXapi.getObject(hostId)
|
||||||
|
|
||||||
|
const accrossPools = vm.$pool !== host.$pool
|
||||||
|
const useStorageMotion = (
|
||||||
|
accrossPools ||
|
||||||
|
migrationNetworkId ||
|
||||||
|
networkId ||
|
||||||
|
srId
|
||||||
|
)
|
||||||
|
|
||||||
|
if (useStorageMotion) {
|
||||||
|
const vifsMap = {}
|
||||||
|
if (accrossPools || networkId) {
|
||||||
|
const {$ref: networkRef} = networkId
|
||||||
|
? this.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, {
|
||||||
|
migrationNetwork: migrationNetworkId && this.getObject(migrationNetworkId),
|
||||||
|
sr: srId && this.getObject(srId),
|
||||||
|
vifsMap
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
await this.call('VM.pool_migrate', vm.$ref, host.$ref, { force: 'true' })
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code !== 'VM_REQUIRES_SR') {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry using motion storage.
|
||||||
|
await this._migrateVMWithStorageMotion(vm, hostXapi, host, {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async snapshotVm (vmId) {
|
async snapshotVm (vmId) {
|
||||||
return await this._getOrWaitObject(
|
return await this._getOrWaitObject(
|
||||||
await this._snapshotVm(
|
await this._snapshotVm(
|
||||||
|
Loading…
Reference in New Issue
Block a user