# pxetest VM harness Proves a new PXE server can be built from this repo, in two libvirt VMs on a laptop, without root and without touching a real network. ## Topology | Object | What | |-------------------|----------------------------------------------------------------------| | `pxetest-imaging` | libvirt network, bridge `virbr-pxetest`. No ``, no ``: the host has no address on it and libvirt runs no DHCP there. Only VM taps are on the bridge. | | `default` | libvirt NAT, 192.168.122.0/24. Stands in for the GE/corp network. | | `pxetest-server` | 2 vCPU, 4 GiB, q35 + OVMF Secure Boot (MS keys), 60G thin qcow2 (`vda`, boot 1), the USB image as a USB disk (`sda`, boot 2). | | `pxetest-client` | 2 vCPU, 2 GiB, OVMF Secure Boot (MS keys), 1G blank disk, network boot first (UEFI IPv4 PXE, virtio-net, OVMF driver, no option ROM). Proves shim -> iPXE -> menu -> WinPE under Secure Boot; WinPE has no virtio driver, so it stops at "Waiting for network". | | `pxetest-client-nosb` | 2 vCPU, 2 GiB, OVMF without Secure Boot, e1000e NIC, 64G thin SATA disk. WinPE has in-box drivers for both, so startnet gets a network and maps the shares. | NIC MACs (fixed): | VM | NIC | MAC | Network | Playbook var | |--------|---------|---------------------|-------------------|-------------------| | server | GE | `52:54:00:9e:10:01` | `default` NAT | `corp_nic_mac` | | server | imaging | `52:54:00:9e:10:02` | `pxetest-imaging` | `pxe_nic_mac` | | client | - | `52:54:00:9e:10:03` | `pxetest-imaging` | - | | client-nosb | - | `52:54:00:9e:10:04` | `pxetest-imaging` | - | `build-image.sh` writes `$PXETEST_CACHE/site-vars.yml` with these two MACs (`pxe_nic_mac`, `corp_nic_mac`) and passes it to `build-usb.sh --site-vars`, so it lands on CIDATA as `playbook/site-vars.yml`. The installer brings both NICs up with DHCP; the playbook renames them to pxe0 / corp0 and pins pxe0 to 172.16.9.1. The disk boots before the USB on purpose: a blank disk falls through to the installer, and after the install the server boots its disk instead of re-running autoinstall. CIDATA stays attached for the first-boot playbook. Never attach a pxetest VM to a physical NIC, a host bridge with physical ports, or macvtap: the server's dnsmasq serves DHCP/PXE as 172.16.9.1. `create.sh`, `start.sh` and `status.sh` check the isolation and refuse to continue if `pxetest-imaging` ever gains a ``, an ``, a host IPv4 address or a non-tap bridge port. ## Run it export PXETEST_CACHE=~/.cache/pxetest # ISO + image (about 10 GB) export PXETEST_PAYLOAD_ROOT=/home/camp/projects/pxe # checkout holding offline-packages/, boot-files/, ... export UBUNTU_ISO_NAME=ubuntu-24.04.3-live-server-amd64.iso # optional; default 24.04.5 tests/vm/fetch-iso.sh # the live-server ISO, SHA256SUMS-verified scripts/download-packages.sh --iso "$PXETEST_CACHE/$UBUNTU_ISO_NAME" "$PXETEST_PAYLOAD_ROOT/offline-packages" scripts/check-updates.py --debs "$PXETEST_PAYLOAD_ROOT/offline-packages" tests/vm/build-image.sh # build-usb.sh --image, upload as volume pxetest-usb.img tests/vm/create.sh # network, volumes, both VMs (prints the MAC pins) tests/vm/start.sh server # autoinstall, reboot, first-boot playbook tests/vm/status.sh --shot /tmp/pxetest-shots # states, leases, screenshots tests/vm/start.sh client # once the server playbook is done (Secure Boot client) tests/vm/stop.sh client tests/vm/start.sh client2 # Secure Boot off, e1000e: WinPE maps the shares tests/vm/stop.sh # ACPI shutdown all, keep them defined tests/vm/destroy.sh # remove every pxetest-* object `build-image.sh` skips enrollment/, bios-staging/, drivers-staging/ and boot-tools/ by default; `--with-enrollment` and `--with-boot-tools` add them back, `--size 20G` fixes the image size (default `auto`). If the host has no `sfdisk` or `mtools`, the debs are extracted into `$PXETEST_CACHE/tools` (no install, no root). Watch the server with `virt-viewer -c qemu:///system pxetest-server` (VNC on 127.0.0.1) or screenshots. On the installed system, first-boot output goes to `/var/log/first-boot.log`. Once the GE NIC takes a DHCP lease on the NAT network, `status.sh` shows its address and `ssh pxe@
` works from the host. The offline package set must be built against the SAME ISO the image is built from (download-packages.sh resolves against that ISO's base). For a fresh server disk: `tests/vm/destroy.sh`, then build-image.sh, create.sh, start.sh server. Memory: server 4 GiB + one client 2 GiB (start.sh refuses a second client). Keep other VMs (win11) off while both run, and stop them when done. Blancco needs more client RAM than 2 GiB: blancco-init downloads its ~850 MB rootfs into a tmpfs, and at 2 GiB it stops at 48% with "No space left on device". To test it within the 6 GiB budget, shrink the server and grow the client while both are off, and put them back afterwards: virsh -c qemu:///system setmaxmem pxetest-server 2048M --config virsh -c qemu:///system setmem pxetest-server 2048M --config virsh -c qemu:///system setmaxmem pxetest-client 4096M --config virsh -c qemu:///system setmem pxetest-client 4096M --config Menu keys from the host: `virsh -c qemu:///system send-key KEY_DOWN` (separator lines are skipped: Down x1 = Blancco, x3 = Clonezilla, x4 = Reboot), then KEY_ENTER; startnet answers are KEY_ + KEY_ENTER.