155 lines
3.5 KiB
JavaScript
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)
|
|
}
|