chore(xo-server): use @xen-orchestra/xapi/VM_{checkpoint,snapshot}

This commit is contained in:
Julien Fontanet
2022-03-16 12:59:34 +01:00
parent eee4981d4c
commit 6aa5ec6eb6
4 changed files with 22 additions and 94 deletions

View File

@@ -1220,9 +1220,7 @@ export class Xapi extends EventEmitter {
// dont trigger getters (eg sessionId)
const fn = Object.getOwnPropertyDescriptor(object, name).value
if (typeof fn === 'function' && name.startsWith(type + '_')) {
const key = '$' + name.slice(type.length + 1)
assert.strictEqual(props[key], undefined)
props[key] = function (...args) {
props['$' + name.slice(type.length + 1)] = function (...args) {
return xapi[name](this.$ref, ...args)
}
}

View File

@@ -827,11 +827,11 @@ export const snapshot = defer(async function (
}
const xapi = this.getXapi(vm)
const { $id: snapshotId, $ref: snapshotRef } = await (saveMemory
? xapi.checkpointVm(vm._xapiRef, name)
: xapi.snapshotVm(vm._xapiRef, name))
const snapshotRef = await xapi['VM_' + (saveMemory ? 'checkpoint' : 'snapshot')](vm._xapiRef, { name_label: name })
$defer.onFailure(() => xapi.VM_destroy(snapshotRef))
const snapshotId = await xapi.getField('VM', snapshotRef, 'uuid')
if (description !== undefined) {
await xapi.editVm(snapshotId, { name_description: description })
}

View File

@@ -105,7 +105,7 @@ export default class Xapi extends XapiBase {
this.exportVm = limitConcurrency(vmExportConcurrency, waitStreamEnd)(this.exportVm)
this._migrateVmWithStorageMotion = limitConcurrency(vmMigrationConcurrency)(this._migrateVmWithStorageMotion)
this._snapshotVm = limitConcurrency(vmSnapshotConcurrency)(this._snapshotVm)
this.VM_snapshot = limitConcurrency(vmSnapshotConcurrency)(this.VM_snapshot)
// Patch getObject to resolve _xapiId property.
this.getObject = (
@@ -339,9 +339,9 @@ export default class Xapi extends XapiBase {
// If a SR is specified, it will contains the copies of the VDIs,
// otherwise they will use the SRs they are on.
async _copyVm(vm, nameLabel = vm.name_label, sr = undefined) {
let snapshot
let snapshotRef
if (isVmRunning(vm)) {
snapshot = await this._snapshotVm(vm)
snapshotRef = await this.VM_snapshot(vm.$ref)
}
log.debug(
@@ -351,10 +351,10 @@ export default class Xapi extends XapiBase {
)
try {
return await this.call('VM.copy', snapshot ? snapshot.$ref : vm.$ref, nameLabel, sr ? sr.$ref : '')
return await this.call('VM.copy', snapshotRef || vm.$ref, nameLabel, sr ? sr.$ref : '')
} finally {
if (snapshot) {
await this.VM_destroy(snapshot.$ref)
if (snapshotRef) {
await this.VM_destroy(snapshotRef)
}
}
}
@@ -528,7 +528,12 @@ export default class Xapi extends XapiBase {
async exportVm($cancelToken, vmId, { compress = false } = {}) {
const vm = this.getObject(vmId)
const useSnapshot = isVmRunning(vm)
const exportedVm = useSnapshot ? await this._snapshotVm($cancelToken, vm, `[XO Export] ${vm.name_label}`) : vm
const exportedVm = useSnapshot
? await this.getRecord(
await this.VM_snapshot(vm.$ref, { cancelToken: $cancelToken, name_label: `[XO Export] ${vm.name_label}` }),
'VM'
)
: vm
const promise = this.getResource($cancelToken, '/export/', {
query: {
@@ -580,7 +585,10 @@ export default class Xapi extends XapiBase {
await this.VM_assertHealthyVdiChains(vm.$ref)
}
vm = await this._snapshotVm($cancelToken, vm, snapshotNameLabel)
vm = await this.getRecord(
await this.VM_snapshot(vm.$ref, { cancelToken: $cancelToken, name_label: snapshotNameLabel }),
'VM'
)
$defer.onFailure(() => this.VM_destroy(vm.$ref))
}
@@ -1259,64 +1267,6 @@ export default class Xapi extends XapiBase {
}
}
@cancelable
async _snapshotVm($cancelToken, { $ref: vmRef }, nameLabel) {
const vm = await this.getRecord('VM', vmRef)
if (nameLabel === undefined) {
nameLabel = vm.name_label
}
log.debug(`Snapshotting VM ${vm.name_label}${nameLabel !== vm.name_label ? ` as ${nameLabel}` : ''}`)
// see https://github.com/vatesfr/xen-orchestra/issues/4074
const snapshotNameLabelPrefix = `Snapshot of ${vm.uuid} [`
ignoreErrors.call(
Promise.all(
vm.snapshots.map(async ref => {
const nameLabel = await this.getField('VM', ref, 'name_label')
if (nameLabel.startsWith(snapshotNameLabelPrefix)) {
return this.VM_destroy(ref)
}
})
)
)
let ref
do {
if (!vm.tags.includes('xo-disable-quiesce')) {
try {
ref = await this.callAsync($cancelToken, 'VM.snapshot_with_quiesce', vmRef, nameLabel).then(extractOpaqueRef)
ignoreErrors.call(this.call('VM.add_tags', ref, 'quiesce'))
break
} catch (error) {
const { code } = error
if (
// removed in CH 8.1
code !== 'MESSAGE_REMOVED' &&
code !== 'VM_SNAPSHOT_WITH_QUIESCE_NOT_SUPPORTED' &&
// quiesce only work on a running VM
code !== 'VM_BAD_POWER_STATE' &&
// quiesce failed, fallback on standard snapshot
// TODO: emit warning
code !== 'VM_SNAPSHOT_WITH_QUIESCE_FAILED'
) {
throw error
}
}
}
ref = await this.callAsync($cancelToken, 'VM.snapshot', vmRef, nameLabel).then(extractOpaqueRef)
} while (false)
await this.setField('VM', ref, 'is_a_template', false)
return this.getRecord('VM', ref)
}
async snapshotVm(vmId, nameLabel = undefined) {
return /* await */ this._snapshotVm(this.getObject(vmId), nameLabel)
}
async _startVm(vm, { force = false, bypassMacAddressesCheck = force, hostId } = {}) {
if (!bypassMacAddressesCheck) {
const vmMacAddresses = vm.$VIFs.map(vif => vif.MAC)

View File

@@ -8,12 +8,12 @@ import mapValues from 'lodash/mapValues.js'
import noop from 'lodash/noop.js'
import { decorateWith } from '@vates/decorate-with'
import { defer as deferrable } from 'golike-defer'
import { cancelable, ignoreErrors, pCatch } from 'promise-toolbox'
import { ignoreErrors, pCatch } from 'promise-toolbox'
import { Ref } from 'xen-api'
import { forEach, parseSize } from '../../utils.mjs'
import { extractOpaqueRef, isVmHvm, isVmRunning, makeEditObject } from '../utils.mjs'
import { isVmHvm, isVmRunning, makeEditObject } from '../utils.mjs'
// According to: https://xenserver.org/blog/entry/vga-over-cirrus-in-xenserver-6-2.html.
const XEN_VGA_VALUES = ['std', 'cirrus']
@@ -23,26 +23,6 @@ const XEN_VIDEORAM_VALUES = [1, 2, 4, 8, 16]
const isMemoryConstraintError = e => e.code.startsWith('MEMORY_CONSTRAINT_VIOLATION')
export default {
// https://xapi-project.github.io/xen-api/classes/vm.html#checkpoint
@cancelable
async checkpointVm($cancelToken, vmId, nameLabel) {
const vm = this.getObject(vmId)
try {
const ref = await this.callAsync(
$cancelToken,
'VM.checkpoint',
vm.$ref,
nameLabel != null ? nameLabel : vm.name_label
).then(extractOpaqueRef)
return this.barrier(ref)
} catch (error) {
if (error.code === 'VM_BAD_POWER_STATE') {
return this._snapshotVm($cancelToken, vm, nameLabel)
}
throw error
}
},
// TODO: clean up on error.
@decorateWith(deferrable)
async createVm(