Boot KVM guests via UEFI by default; per-image firmware setting

Run 5 on the real host bisected the guest hang: the Debian 13 image
hangs after GRUB under SeaBIOS with or without our seed and with either
CPU model, and boots under OVMF. The image's legacy boot chain is the
problem, not the provider.

images.<key>.firmware is "uefi" (default) or "bios". The domain XML
emits <os firmware="efi"> with secure boot off, so libvirt selects the
OVMF binary and manages the NVRAM file, which the existing nvram undefine
flag removes. Direct-URL images default to UEFI too. OVMF joins the
hypervisor prerequisites; sample, config table, known gaps, decision log
and the execution log record the finding.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 19:13:51 +00:00
co-authored by Claude Fable 5.1
parent 5a6c889531
commit 9a393b1df8
12 changed files with 151 additions and 26 deletions
+12 -1
View File
@@ -23,7 +23,11 @@ Per host, once:
4. **A storage pool** (default `default`, usually `/var/lib/libvirt/images`)
with room for one base image per distro (a few hundred MB) plus the
per-VM overlays (`diskSizeGb` each, thin-provisioned).
5. Optionally, **outbound internet from the VMs**: the default
5. **UEFI firmware for guests**: the `ovmf` package on Debian/Ubuntu,
`edk2-ovmf` on Fedora/RHEL. VMs boot UEFI by default (libvirt picks
the OVMF binary itself); a domain start fails with "no firmware
found" without it. Only `firmware: bios` images skip this.
6. Optionally, **outbound internet from the VMs**: the default
vendor-data installs `qemu-guest-agent` from the distro mirrors on
first boot. Without it the VM still works — the operator falls back to
the host's ARP table to find the IP, which fills in once the guest
@@ -107,6 +111,7 @@ ssh virt@nas1.home.lan ip link show br0
| `images.<key>.url` | yes per entry | | http(s) URL of a cloud image (qcow2 or raw) |
| `images.<key>.sha256` | | | expected digest; verified after download, a change triggers a re-download |
| `images.<key>.format` | | `qcow2` | `qcow2` or `raw` |
| `images.<key>.firmware` | | `uefi` | `uefi` (OVMF, secure boot off) or `bios` (SeaBIOS) for images without an EFI system partition; Debian 13's BIOS path does not boot, see *Known gaps* |
| `machineTypes.<key>` | ≥ 1 | | `{vcpus, memoryMiB}` size profile |
| `hosts[].name` | yes | | the `placement.zone` value that selects this host; unique |
| `hosts[].address` | yes | | SSH endpoint, `host:port` |
@@ -228,6 +233,12 @@ The provider logs through controller-runtime's logger, named `kvm`, with
- **IP discovery needs either guest traffic or the agent.** A VM on a
bridge with no DHCP never gets an address and stays `Provisioning`
forever; check `virsh console`.
- **Debian 13 cloud images do not boot via BIOS on the tested host**
(Ryzen 8845HS, libvirt 11.6, QEMU 10.1): GRUB prints "Booting" and
the kernel never reaches the console, with or without a seed, with
host-passthrough and host-model CPUs alike. The same image boots
under UEFI, which is why `firmware` defaults to `uefi`. Images that
need `firmware: bios` are the exception, not the rule.
## Testing