Files
xen-orchestra/@xen-orchestra/xva/_writeOvaXml.mjs
2024-01-30 18:54:46 +01:00

155 lines
3.5 KiB
JavaScript

import assert from 'node:assert'
import { fromCallback } from 'promise-toolbox'
import { v4 as uuid } from 'uuid'
import defaultsDeep from 'lodash.defaultsdeep'
import { DEFAULT_VBD } from './templates/vbd.mjs'
import { DEFAULT_VDI } from './templates/vdi.mjs'
import { DEFAULT_VIF } from './templates/vif.mjs'
import { DEFAULT_VM } from './templates/vm.mjs'
import toOvaXml from './_toOvaXml.mjs'
export default async function writeOvaXml(
pack,
{ memory, networks, nCpus, firmware, vdis, vhds, ...vmSnapshot },
{ sr, network }
) {
let refId = 0
function nextRef() {
return 'Ref:' + String(refId++).padStart(3, '0')
}
const data = {
version: {
hostname: 'localhost',
date: '2022-01-01',
product_version: '8.2.1',
product_brand: 'XCP-ng',
build_number: 'release/yangtze/master/58',
xapi_major: 1,
xapi_minor: 20,
export_vsn: 2,
},
objects: [],
}
const vm = defaultsDeep(
{
id: nextRef(),
// you can pass a full snapshot and nothing more to do
snapshot: vmSnapshot,
},
{
// some data need a little more work to be usable
// if they are not already in vm
snapshot: {
HVM_boot_params: {
firmware,
},
memory_static_max: memory,
memory_static_min: memory,
memory_dynamic_max: memory,
memory_dynamic_min: memory,
other_config: {
mac_seed: uuid(),
},
uuid: uuid(),
VCPUs_at_startup: nCpus,
VCPUs_max: nCpus,
},
},
DEFAULT_VM
)
data.objects.push(vm)
const srObj = defaultsDeep(
{
class: 'SR',
id: nextRef(),
snapshot: sr,
},
{
snapshot: {
VDIs: [],
},
}
)
data.objects.push(srObj)
assert.strictEqual(vhds.length, vdis.length)
for (let index = 0; index < vhds.length; index++) {
const userdevice = index + 1
const vhd = vhds[index]
const vdi = defaultsDeep(
{
id: nextRef(),
// overwrite SR from an opaqref to a ref:
snapshot: { ...vdis[index], SR: srObj.id },
},
{
snapshot: {
uuid: uuid(),
},
},
DEFAULT_VDI
)
data.objects.push(vdi)
srObj.snapshot.VDIs.push(vdi.id)
vhd.ref = vdi.id
const vbd = defaultsDeep(
{
id: nextRef(),
snapshot: {
device: `xvd${String.fromCharCode('a'.charCodeAt(0) + index)}`,
uuid: uuid(),
userdevice,
VM: vm.id,
VDI: vdi.id,
},
},
DEFAULT_VBD
)
data.objects.push(vbd)
vdi.snapshot.vbds.push(vbd.id)
vm.snapshot.VBDs.push(vbd.id)
}
if (network && networks?.length) {
const networkObj = defaultsDeep(
{
class: 'network',
id: nextRef(),
snapshot: network,
},
{
snapshot: {
vifs: [],
},
}
)
data.objects.push(networkObj)
let vifIndex = 0
for (const sourceNetwork of networks) {
const vif = defaultsDeep(
{
id: nextRef(),
snapshot: {
device: ++vifIndex,
MAC: sourceNetwork.macAddress,
MAC_autogenerated: sourceNetwork.isGenerated,
uuid: uuid(),
VM: vm.id,
network: networkObj.id,
},
},
DEFAULT_VIF
)
data.objects.push(vif)
networkObj.snapshot.vifs.push(vif.id)
}
}
const xml = toOvaXml(data)
await fromCallback.call(pack, pack.entry, { name: `ova.xml` }, xml)
}