feat: support network boot (PXE) for VM interfaces (#1176)

Add an "Enable network boot (PXE)" option to bridge network interfaces and
a VM-level choice to place network boot devices before or after volumes.
The form now owns interface boot order: enabled NICs get sequential boot
orders ahead of or behind the volumes, and a stale bootOrder is no longer
inherited from the old spec.

This also fixes editing a VM whose interface bootOrder was set in YAML
(the documented workaround): the form used to renumber disks from 1 while
keeping the NIC's bootOrder, producing a duplicate that KubeVirt rejects.

The boot order shown on the VM, snapshot and backup detail pages now
includes network interfaces.

Related: harvester/harvester#3325

Signed-off-by: Alejandro Bonilla <abonilla@suse.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Alejandro Bonilla
2026-10-07 11:21:27 +08:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 528255dea4
commit 5af181f5b6
11 changed files with 141 additions and 51 deletions
@@ -6,6 +6,7 @@ import HarvesterIpAddress from '../../../formatters/HarvesterIpAddress';
import VMConsoleBar from '../../../components/VMConsoleBar';
import { HCI } from '../../../types';
import { getVmCPUMemoryValues } from '../../../utils/cpuMemory';
import { getBootDevices } from '../../../utils/vm';
const UNDEFINED = 'n/a';
@@ -69,18 +70,8 @@ export default {
return image?.spec?.displayName || 'N/A';
},
disks() {
const disks = this.value?.spec?.template?.spec?.domain?.devices?.disks || [];
return disks.filter((disk) => {
return !!disk.bootOrder;
}).sort((a, b) => {
if (a.bootOrder < b.bootOrder) {
return -1;
}
return 1;
});
bootDevices() {
return getBootDevices(this.value?.spec?.template?.spec?.domain?.devices);
},
cdroms() {
@@ -122,8 +113,10 @@ export default {
getDeviceType(o) {
if (o.disk) {
return 'Disk';
} else {
} else if (o.cdrom) {
return 'CD-ROM';
} else {
return 'Network';
}
},
isEmpty(o) {
@@ -219,16 +212,16 @@ export default {
<div class="col span-6">
<InputOrDisplay
:name="t('harvester.virtualMachine.detail.details.bootOrder')"
:value="disks"
:value="bootDevices"
:mode="mode"
>
<template #value>
<ul>
<li
v-for="(disk, i) in disks"
v-for="(device, i) in bootDevices"
:key="i"
>
{{ disk.bootOrder }}. {{ disk.name }} ({{ getDeviceType(disk) }})
{{ device.bootOrder }}. {{ device.name }} ({{ getDeviceType(device) }})
</li>
</ul>
</template>