chore(xo-server/snapshotVm): eventless implementation (#3992)

Previous implementation relied on events but had issues where it did not correctly detect and remove broken quiesced snapshot.

The new implementation is less magical and does not rely on events at all.
This commit is contained in:
Julien Fontanet 2019-02-26 14:41:55 +01:00 committed by Pierre Donias
parent 420f1c77a1
commit 3931c4cf4c

View File

@ -679,17 +679,17 @@ export default class Xapi extends XapiBase {
}
async _deleteVm(
vm,
vmOrRef,
deleteDisks = true,
force = false,
forceDeleteDefaultTemplate = false
) {
log.debug(`Deleting VM ${vm.name_label}`)
const { $ref } = vm
const $ref = typeof vmOrRef === 'string' ? vmOrRef : vmOrRef.$ref
// ensure the vm record is up-to-date
vm = await this.barrier($ref)
const vm = await this.barrier($ref)
log.debug(`Deleting VM ${vm.name_label}`)
if (!force && 'destroy' in vm.blocked_operations) {
throw forbiddenOperation('destroy', vm.blocked_operations.destroy.reason)
@ -1541,19 +1541,22 @@ export default class Xapi extends XapiBase {
@concurrency(2)
@cancelable
async _snapshotVm($cancelToken, vm, nameLabel = vm.name_label) {
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}` : ''
}`
)
const vmRef = vm.$ref
let ref
do {
if (!vm.tags.includes('xo-disable-quiesce')) {
try {
vm = await this.barrier(vmRef)
ref = await pRetry(
async bail => {
try {
@ -1573,12 +1576,11 @@ export default class Xapi extends XapiBase {
// see https://github.com/vatesfr/xen-orchestra/issues/3936
const prevSnapshotRefs = new Set(vm.snapshots)
const snapshotNameLabelPrefix = `Snapshot of ${vm.uuid} [`
vm = await this.barrier(vmRef)
const createdSnapshots = vm.$snapshots.filter(
_ =>
!prevSnapshotRefs.has(_.$ref) &&
_.name_label.startsWith(snapshotNameLabelPrefix)
)
vm.snapshots = await this.getField('VM', vmRef, 'snapshots')
const createdSnapshots = (await this.getRecords(
'VM',
vm.snapshots.filter(_ => !prevSnapshotRefs.has(_))
)).filter(_ => _.name_label.startsWith(snapshotNameLabelPrefix))
// be safe: only delete if there was a single match
if (createdSnapshots.length === 1) {
@ -1593,7 +1595,7 @@ export default class Xapi extends XapiBase {
tries: 3,
}
).then(extractOpaqueRef)
this.addTag(ref, 'quiesce')::ignoreErrors()
ignoreErrors.call(this.call('VM.add_tags', ref, 'quiesce'))
break
} catch (error) {
@ -1618,14 +1620,9 @@ export default class Xapi extends XapiBase {
).then(extractOpaqueRef)
} while (false)
// Convert the template to a VM and wait to have receive the up-
// to-date object.
const [, snapshot] = await Promise.all([
this.call('VM.set_is_a_template', ref, false),
this.barrier(ref),
])
await this.setField('VM', ref, 'is_a_template', false)
return snapshot
return this.getRecord('VM', ref)
}
async snapshotVm(vmId, nameLabel = undefined) {