chore(xo-server): use @xen-orchestra/xapi/VM_{checkpoint,snapshot}
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user