chore(xo-server): remove unused {export,import}DeltaVm functions

This commit is contained in:
Julien Fontanet 2022-05-12 15:09:17 +02:00
parent c92b371d9e
commit 4bed50b4ed
2 changed files with 0 additions and 367 deletions

View File

@ -62,17 +62,6 @@ export async function copyVm({ vm, sr }) {
console.log('import full VM...')
await tgtXapi.VM_destroy((await tgtXapi.importVm(input, { srId: sr })).$ref)
}
// delta
{
console.log('export delta VM...')
const input = await srcXapi.exportDeltaVm(vm)
console.log('import delta VM...')
const { vm: copyVm } = await tgtXapi.importDeltaVm(input, {
srId: sr,
})
await tgtXapi.VM_destroy(copyVm.$ref)
}
}
copyVm.description = 'export/import full/delta VM'

View File

@ -6,7 +6,6 @@ import filter from 'lodash/filter.js'
import find from 'lodash/find.js'
import flatMap from 'lodash/flatMap.js'
import flatten from 'lodash/flatten.js'
import groupBy from 'lodash/groupBy.js'
import identity from 'lodash/identity.js'
import includes from 'lodash/includes.js'
import isEmpty from 'lodash/isEmpty.js'
@ -14,9 +13,7 @@ import mapToArray from 'lodash/map.js'
import mixin from '@xen-orchestra/mixin/legacy.js'
import ms from 'ms'
import noop from 'lodash/noop.js'
import omit from 'lodash/omit.js'
import once from 'lodash/once.js'
import semver from 'semver'
import tarStream from 'tar-stream'
import uniq from 'lodash/uniq.js'
import { asyncMap } from '@xen-orchestra/async-map'
@ -33,9 +30,7 @@ import { Xapi as XapiBase } from '@xen-orchestra/xapi'
import { Ref } from 'xen-api'
import { synchronized } from 'decorator-synchronized'
import ensureArray from '../_ensureArray.mjs'
import fatfsBuffer, { init as fatfsBufferInit } from '../fatfs-buffer.mjs'
import { asyncMapValues } from '../_asyncMapValues.mjs'
import { camelToSnakeCase, forEach, map, parseSize, pDelay, promisifyAll } from '../utils.mjs'
import mixins from './mixins/index.mjs'
@ -65,11 +60,6 @@ class AggregateError extends Error {
// ===================================================================
const TAG_BASE_DELTA = 'xo:base_delta'
export const TAG_COPY_SRC = 'xo:copy_of'
// ===================================================================
export * from './utils.mjs'
// VDI formats. (Raw is not available for delta vdi.)
@ -593,352 +583,6 @@ export default class Xapi extends XapiBase {
return writeStream
}
// Create a snapshot (if necessary) of the VM and returns a delta export
// object.
@cancelable
@decorateWith(deferrable)
async exportDeltaVm(
$defer,
$cancelToken,
vmId,
baseVmId,
{
bypassVdiChainsCheck = false,
// Contains a vdi.$id set of vmId.
fullVdisRequired = [],
disableBaseTags = false,
snapshotNameLabel = undefined,
} = {}
) {
let vm = this.getObject(vmId)
// do not use the snapshot name in the delta export
const exportedNameLabel = vm.name_label
if (!vm.is_a_snapshot) {
if (!bypassVdiChainsCheck) {
await this.VM_assertHealthyVdiChains(vm.$ref)
}
vm = await this.getRecord(
'VM',
await this.VM_snapshot(vm.$ref, { cancelToken: $cancelToken, name_label: snapshotNameLabel })
)
$defer.onFailure(() => this.VM_destroy(vm.$ref))
}
const baseVm = baseVmId && this.getObject(baseVmId)
// refs of VM's VDIs → base's VDIs.
const baseVdis = {}
baseVm &&
forEach(baseVm.$VBDs, vbd => {
let vdi, snapshotOf
if (
(vdi = vbd.$VDI) &&
(snapshotOf = vdi.$snapshot_of) &&
!find(fullVdisRequired, id => snapshotOf.$id === id)
) {
baseVdis[vdi.snapshot_of] = vdi
}
})
const streams = {}
const vdis = {}
const vbds = {}
forEach(vm.$VBDs, vbd => {
let vdi
if (vbd.type !== 'Disk' || !(vdi = vbd.$VDI)) {
// Ignore this VBD.
return
}
// If the VDI name start with `[NOBAK]`, do not export it.
if (vdi.name_label.startsWith('[NOBAK]')) {
// FIXME: find a way to not create the VDI snapshot in the
// first time.
//
// The snapshot must not exist otherwise it could break the
// next export.
vdi.$destroy()::ignoreErrors()
return
}
vbds[vbd.$ref] = vbd
const vdiRef = vdi.$ref
if (vdiRef in vdis) {
// This VDI has already been managed.
return
}
// Look for a snapshot of this vdi in the base VM.
const baseVdi = baseVdis[vdi.snapshot_of]
vdis[vdiRef] = {
...vdi,
other_config: {
...vdi.other_config,
[TAG_BASE_DELTA]: baseVdi && !disableBaseTags ? baseVdi.uuid : undefined,
},
$SR$uuid: vdi.$SR.uuid,
}
streams[`${vdiRef}.vhd`] = () => this._exportVdi($cancelToken, vdi, baseVdi, VDI_FORMAT_VHD)
})
const suspendVdi = vm.$suspend_VDI
if (suspendVdi !== undefined) {
const vdiRef = suspendVdi.$ref
vdis[vdiRef] = {
...suspendVdi,
$SR$uuid: suspendVdi.$SR.uuid,
}
streams[`${vdiRef}.vhd`] = () => this._exportVdi($cancelToken, suspendVdi, undefined, VDI_FORMAT_VHD)
}
const vifs = {}
forEach(vm.$VIFs, vif => {
const network = vif.$network
vifs[vif.$ref] = {
...vif,
$network$uuid: network.uuid,
$network$name_label: network.name_label,
// https://github.com/babel/babel-eslint/issues/595
// eslint-disable-next-line no-undef
$network$VLAN: network.$PIFs[0]?.VLAN,
}
})
return Object.defineProperty(
{
version: '1.1.0',
vbds,
vdis,
vifs,
vm: {
...vm,
name_label: exportedNameLabel,
other_config:
baseVm && !disableBaseTags
? {
...vm.other_config,
[TAG_BASE_DELTA]: baseVm.uuid,
}
: omit(vm.other_config, TAG_BASE_DELTA),
},
},
'streams',
{
configurable: true,
value: streams,
writable: true,
}
)
}
@decorateWith(deferrable)
async importDeltaVm(
$defer,
delta,
{
deleteBase = false,
detectBase = true,
disableStartAfterImport = true,
mapVdisSrs = {},
name_label = delta.vm.name_label,
srId = this.pool.default_SR,
} = {}
) {
const { version } = delta
if (!semver.satisfies(version, '^1')) {
throw new Error(`Unsupported delta backup version: ${version}`)
}
let baseVm
if (detectBase) {
const remoteBaseVmUuid = delta.vm.other_config[TAG_BASE_DELTA]
if (remoteBaseVmUuid) {
baseVm = find(this.objects.all, obj => (obj = obj.other_config) && obj[TAG_COPY_SRC] === remoteBaseVmUuid)
if (!baseVm) {
throw new Error(`could not find the base VM (copy of ${remoteBaseVmUuid})`)
}
}
}
const baseVdis = {}
baseVm &&
forEach(baseVm.$VBDs, vbd => {
const vdi = vbd.$VDI
if (vdi !== undefined) {
baseVdis[vbd.VDI] = vbd.$VDI
}
})
// 0. Create suspend_VDI
let suspendVdi
if (delta.vm.power_state === 'Suspended') {
const vdi = delta.vdis[delta.vm.suspend_VDI]
suspendVdi = await this.createVdi({
...vdi,
other_config: {
...vdi.other_config,
[TAG_BASE_DELTA]: undefined,
[TAG_COPY_SRC]: vdi.uuid,
},
sr: mapVdisSrs[vdi.uuid] || srId,
})
$defer.onFailure.call(this, 'VDI_destroy', suspendVdi.$ref)
}
// 1. Create the VMs.
const vm = await this._getOrWaitObject(
await this._createVmRecord(
{
...delta.vm,
affinity: null,
blocked_operations: {
...delta.vm.blocked_operations,
start: 'Importing…',
start_on: 'Importing…',
},
ha_always_run: false,
is_a_template: false,
name_label: `[Importing…] ${name_label}`,
other_config: {
...delta.vm.other_config,
[TAG_COPY_SRC]: delta.vm.uuid,
},
},
{ suspend_VDI: suspendVdi?.$ref }
)
)
$defer.onFailure(() => this.VM_destroy(vm.$ref))
// 2. Delete all VBDs which may have been created by the import.
await asyncMapSettled(vm.$VBDs, vbd => this._deleteVbd(vbd))::ignoreErrors()
// 3. Create VDIs & VBDs.
//
// TODO: move all VDIs creation before the VM and simplify the code
const vbds = groupBy(delta.vbds, 'VDI')
const newVdis = await asyncMapValues(delta.vdis, async (vdi, vdiRef) => {
let newVdi
const remoteBaseVdiUuid = detectBase && vdi.other_config[TAG_BASE_DELTA]
if (remoteBaseVdiUuid) {
const baseVdi = find(baseVdis, vdi => vdi.other_config[TAG_COPY_SRC] === remoteBaseVdiUuid)
if (!baseVdi) {
throw new Error(`missing base VDI (copy of ${remoteBaseVdiUuid})`)
}
newVdi = await this._getOrWaitObject(await this._cloneVdi(baseVdi))
$defer.onFailure(() => newVdi.$destroy())
await newVdi.update_other_config(TAG_COPY_SRC, vdi.uuid)
} else if (vdiRef === delta.vm.suspend_VDI) {
// suspend VDI has been already created
newVdi = suspendVdi
} else {
newVdi = await this.createVdi({
...vdi,
other_config: {
...vdi.other_config,
[TAG_BASE_DELTA]: undefined,
[TAG_COPY_SRC]: vdi.uuid,
},
sr: mapVdisSrs[vdi.uuid] || srId,
})
$defer.onFailure(() => newVdi.$destroy())
}
await asyncMapSettled(vbds[vdiRef], vbd =>
this.createVbd({
...vbd,
vdi: newVdi,
vm,
})
)
return newVdi
})
const networksByNameLabelByVlan = {}
let defaultNetwork
forEach(this.objects.all, object => {
if (object.$type === 'network') {
const pif = object.$PIFs[0]
if (pif === undefined) {
// ignore network
return
}
const vlan = pif.VLAN
const networksByNameLabel = networksByNameLabelByVlan[vlan] || (networksByNameLabelByVlan[vlan] = {})
defaultNetwork = networksByNameLabel[object.name_label] = object
}
})
const { streams } = delta
await Promise.all([
// Import VDI contents.
asyncMapSettled(newVdis, async (vdi, id) => {
for (let stream of ensureArray(streams[`${id}.vhd`])) {
if (typeof stream === 'function') {
stream = await stream()
}
await this._importVdiContent(vdi, stream, VDI_FORMAT_VHD)
}
}),
// Wait for VDI export tasks (if any) termination.
asyncMapSettled(streams, stream => stream.task),
// Create VIFs.
asyncMapSettled(delta.vifs, vif => {
let network = vif.$network$uuid && this.getObject(vif.$network$uuid, undefined)
if (network === undefined) {
const { $network$VLAN: vlan = -1 } = vif
const networksByNameLabel = networksByNameLabelByVlan[vlan]
if (networksByNameLabel !== undefined) {
network = networksByNameLabel[vif.$network$name_label]
if (network === undefined) {
network = networksByNameLabel[Object.keys(networksByNameLabel)[0]]
}
} else {
network = defaultNetwork
}
}
if (network) {
return this._createVif(vm, network, vif)
}
}),
])
if (deleteBase && baseVm) {
this.VM_destroy(baseVm.$ref)::ignoreErrors()
}
await Promise.all([
delta.vm.ha_always_run && vm.set_ha_always_run(true),
vm.set_name_label(name_label),
// FIXME: move
asyncMap(['start', 'start_on'], op =>
vm.update_blocked_operations(
op,
disableStartAfterImport ? 'Do not start this VM, clone it if you want to use it.' : null
)
),
])
return { vm }
}
async _migrateVmWithStorageMotion(
vm,
hostXapi,