Files
pxe-server/tests/vm
cproudlock 576955785d Faster shopfloor-setup sync, prompt spacing, XP-era test client
- Deploy shopfloor-setup with rsync instead of the copy module: the
  ~4 GB tree took about 4 minutes on every re-run because copy checksums
  each file. rsync transfers only changes; changed only when it did.
- iPXE drops a trailing space, so 'Machine number:' ran into the typed
  digits. The space now comes from a hex 20 setting.
- tests/vm: pxetest-xp is a permanent client (SeaBIOS, qemu32 32-bit CPU,
  rtl8139, 1 GiB, IDE disk) for the i686 Clonezilla path; start.sh xp.
  Only one client may run at a time across all three.
2026-10-15 21:43:33 -04:00
..

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 <forward>, no <ip>: 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.
pxetest-xp XP/Win7-era PC: 1 vCPU, 1 GiB, i440FX + SeaBIOS (legacy PXE, gets ipxe.pxe), qemu32 CPU (no long mode, so the menu picks the i686 Clonezilla; fallback='forbid' so it never silently becomes 64-bit), rtl8139 NIC, 8G thin IDE disk.

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 -
xp - 52:54:00:9e:10:05 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 <forward>, an <ip>, 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, all 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/start.sh xp         # legacy BIOS, 32-bit: i686 Clonezilla
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@<address> 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 <vm> KEY_DOWN (separator lines are skipped: Down x1 = Blancco, x2 = Blancco debug, x3 = Clonezilla: back up, x4 = Clonezilla: restore, x5 = Clonezilla manual, x6 = Clonezilla manual 32-bit, x7 = Reboot), then KEY_ENTER; startnet answers are KEY_ + KEY_ENTER.

Clonezilla back up / restore by machine number (VM test plan)

Covers GetPxeScript.aspx (:cz_backup, :cz_restore, :cz_auto64/32), playbook/clonezilla-scripts/pxe-cz.sh, the clonezilla Samba account and the webapp's Clonezilla backups page. Re-run the playbook first (or rebuild) so the server has the new menu, /var/www/html/clonezilla-scripts/pxe-cz.sh and the clonezilla user; --with-boot-tools is needed for Clonezilla itself (clonezilla/ and clonezilla-i686/).

  1. Server checks (ssh pxe@):
    • grep -c 'smb3://clonezilla:' /var/www/html/Altiris/iPXE/GetPxeScript.aspx = 2, and no __CLONEZILLA_SMB_PASSWORD__ left in it.
    • curl -s http://172.16.9.1/clonezilla-scripts/pxe-cz.sh | head -1 = #!/bin/bash.
    • pdbedit -L | grep ^clonezilla:; smbclient //172.16.9.1/clonezilla -U clonezilla%<pw> -c ls works, smbclient //172.16.9.1/winpeapps -U clonezilla%<pw> -c ls is refused (NT_STATUS_ACCESS_DENIED): the account opens only its share.
    • Blancco Releases page: add and remove a test entry still works.
  2. Back up as 6501, 64-bit Secure Boot client (pxetest-client, raise RAM to 3-4 GiB as for Blancco: the live system plus the squashfs need about 1.5 GiB). Put something on its 1G disk first (e.g. boot client2's WinPE and diskpart a partition, or qemu-img a small NTFS/ext4 image). Menu Down x3, Enter. At Machine number: press Enter on empty (asks again), then type 6501. Expect: Clonezilla boots through the shim (no Secure Boot error), no language/keyboard questions, no password on screen, the share mounts, one disk so no disk question, image 6501-YYYY-MM-DD-HHMM (server time, Eastern) is saved, "Checking the saved image", SUCCESS banner with serial and model, power off after 60 s.
  3. Same as 6501 from the 32-bit BIOS client (start.sh xp, pxetest-xp): cpuid --ext 29 fails on its qemu32 CPU and :cz_auto32 boots clonezilla-i686. Give its IDE disk content first, as for step 1. Expect pxe-meta.txt bits=32, firmware=bios, clonezilla=clonezilla-live-3.2.0-5-i686. Also type 65 01 once: Clonezilla says the number is not valid and asks again.
  4. Webapp (Tools > Clonezilla backups): both images under 6501, newest first, serial and model from the VM's DMI (QEMU: serial empty unless <sysinfo> sets one; set <entry name='serial'>VMSER1</entry>), size, disks/partitions, Clonezilla version, 64/32-bit, Check = Checked. Download .tar of one image and tar tvf it.
  5. Restore to a second, LARGER blank disk: attach a blank 4G disk to the client (virsh attach-disk ... --config, then boot). Menu Down x4, machine 6501. Expect only 6501's images, newest first; pick one; the disk list shows both disks with model and size; pick the 4G one; type YES. Clonezilla runs restoredisk with -k1 -r: afterwards sfdisk -l (Clonezilla shell, s at the end prompt) shows the partitions scaled to 4G and the filesystem grown. Picking the 1G source disk for a 4G image (repeat with the disks swapped) must be refused as SMALLER.
  6. Mismatch flag: back up the second client (different <sysinfo> serial) also as 6501. The page shows "Serial mismatch" on 6501 and marks the odd serial; Move to another machine... (e.g. 6502) clears it, and restore of 6502 lists the moved image.
  7. Retention: Settings > Keep last 1, Apply retention... lists the older 6501 image only; Delete removes it, the newest stays.