opentofu/modules/cloudinit-vm gained a cpu block and an expose_nested_virt variable.opentofu/main.tf instantiates modules/base-image (Ubuntu 24.04 LTS) and modules/cloudinit-vm for voffice1 -- the first real instantiation of either module.voffice1 is LIVE.cloudinit-vm's libvirt_domain had no cpu block at all. With none, libvirt renders a GENERIC EMULATED CPU MODEL that exposes no svm flag -- so nested KVM is impossible in the guest. Since LXD virtual machines are qemu/KVM guests, that meant no service VM could ever have been composed into voffice1, and D-114's model would have failed at its first step, with a confusing "KVM not available" rather than anything pointing at OpenTofu.
Measured proof of the masking: the host is an AMD EPYC 9965, but a default-CPU guest is handed an "Opteron_G3". Post-fix, voffice1 reports AMD EPYC 9965 and svm on all 16 cores.
expose_nested_virt is a per-caller decision with NO default, deliberately:
svm through. Required for the D-114 site containment VMs.svm, matching modules/opnsense-edge, which disables it as legitimate hardening for a router guest that has no business seeing nested virt. (Operator asked whether the edge's svm disable was a leftover of the failed OPNsense deploy: it is NOT. It was tried as a triple-fault fix on 2026-07-12 and did NOT resolve it -- the real cause was the memory unit -- and was retained on hardening grounds. It stays disabled on the edge.)host-passthrough, single NIC on office1-local.file(var.office1_ssh_pubkey_path) -- the key material never enters a command line, the repo, or an agent's context. The private half is never read (SEC-007 tracks its rotation).network_config matches the NIC by glob (en*), not a guessed kernel name: the name (ens3/enp1s0/...) depends on machine type and PCI topology and is not knowable before first boot. Naming it would have been an inferred value. (It came up enp1s0.)office1-local had no client. Measured via the D-113(a2) REST API: 10.10.0.100, hwaddr 52:54:00:6a:87:e5 (matches voffice1's NIC exactly), hostname voffice1, state active. DHCP is now proven end to end.voffice1: /dev/kvm PRESENT, svm on all 16 cores, real EPYC CPU model. CAVEAT, stated honestly: this proves nested KVM is AVAILABLE. The DEFINITIVE L3 proof is an actual guest booting inside voffice1 -- that lands when the first LXD VM is composed. Do not record L3 as fully proven until then.scripts/opentofu-validate.sh: PASS (all modules).tofu plan: 5 to add, 0 to change, 0 to destroy -- confirmed BEFORE applying that the running OPNsense edge was NOT touched (no in-place update -> no repeat of the 2026-07-13 guest bounce).tofu apply: 5 added, 0 changed, 0 destroyed. Edge stayed up throughout.tofu -chdir=opentofu destroy -target=module.voffice1 -target=module.ubuntu_noble_base git revert <this commit>
Destroys voffice1, its disk/seed, and the base image; reverts the module + main.tf changes. The OPNsense edge and every Stage-1 network/pool are untouched by both halves. NOTE the base image is a 600 MB download -- reverting and re-applying re-fetches it.
modules/node-vm has the SAME missing-cpu-block defect. The DC OpenStack nodes run nova-compute, which needs working KVM, so they will need host-passthrough with svm passed through for the same reason. NOT fixed here: DC1 is explicitly GATED behind Office1 completing (D-114), and fixing it now would be scope beyond the current step. It must be fixed before Stage 3 or the DC nodes will come up unable to run a single instance.
Operator ruling: "Apply the fixes to DC1 as we find them. Fixes are not blocked, just deployment at this stage." So the modules/node-vm defect logged above as "NOT actioned" is now FIXED.
modules/node-vm gained an UNCONDITIONAL cpu = { mode = "host-passthrough" } -- no expose_nested_virt knob, deliberately. A DC node runs nova-compute; it MUST be able to run KVM guests. There is no correct value other than this one, so no knob that could only ever be set wrong. (Contrast cloudinit-vm, where the flag IS a real per-VM decision, and opnsense-edge, which DISABLES svm as correct hardening for a router.)
modules/node-vm is not yet instantiated, so adding this breaks no live call. Without it the DC nodes would have come up looking healthy while being unable to launch a single instance -- the failure would have surfaced during Stage 5 as an inscrutable scheduler error.
scripts/opentofu-validate.sh: PASS (node-vm, cloudinit-vm, all modules).
voffice1 first came up on 10.10.0.100 -- the first address of Kea's DYNAMIC pool (.100-.199). Infrastructure, and a MAAS region controller above all, should not hold a pool address that can move.
A Kea host reservation was added through the D-113(a2) REST API (a second live exercise of that write path): 52:54:00:6a:87:e5 -> 10.10.0.20, deliberately OUTSIDE the dynamic pool. kea/dhcpv4/add_reservation -> {"result":"saved"}, then kea/service/reconfigure -> {"status":"ok"}. voffice1 was rebooted and came back on 10.10.0.20; .100 is released back to the pool; /dev/kvm still present. Done NOW because nothing yet depends on the address -- it is the cheapest moment it will ever be.