build-usb: whole webapp, hard sfdisk failure, ISO-derived boot params, image-file mode; tests/vm harness
- Copy the whole webapp/ tree (minus __pycache__) in build-usb.sh and build-proxmox-iso.sh, so config, services/, views/ and blancco_evidence_monthly.py reach the server. - sfdisk --append failure now aborts; the CIDATA partition is the one starting exactly at the computed sector, and nothing that starts before it is ever formatted (the old fallback hit the ISO's EFI partition). - Volume id and El Torito load sizes come from the ISO (xorriso -report_el_torito as_mkisofs); grub.cfg must contain autoinstall after patching. - --image FILE SIZE|auto builds the same layout in a file without root (mkfs.vfat -C + mtools, sfdisk on the file). Plus --payload-root, --skip-enrollment/-bios/-drivers/-boot-tools, --yes. - tests/vm: libvirt harness (pxetest-server, pxetest-client, isolated pxetest-imaging network) with fetch-iso/build-image/create/start/ status/stop/destroy.
This commit is contained in:
172
tests/vm/create.sh
Executable file
172
tests/vm/create.sh
Executable file
@@ -0,0 +1,172 @@
|
||||
#!/bin/bash
|
||||
# Define the pxetest network, volumes and VMs. Idempotent: existing
|
||||
# pxetest-* objects are kept (run destroy.sh first to rebuild them).
|
||||
#
|
||||
# pxetest-imaging isolated libvirt network: no <forward>, no <ip>, so the
|
||||
# host has no address on it and libvirt runs no DHCP.
|
||||
# Bridge virbr-pxetest holds only the VMs' tap devices.
|
||||
# pxetest-server 2 vCPU, 4 GiB, OVMF (Secure Boot, MS keys), 60G thin
|
||||
# qcow2 + the USB image as a USB disk.
|
||||
# NIC1 52:54:00:9e:10:01 on 'default' NAT ("GE/corp")
|
||||
# NIC2 52:54:00:9e:10:02 on pxetest-imaging ("imaging")
|
||||
# pxetest-client 2 vCPU, 2 GiB, OVMF Secure Boot with MS keys, 1G blank
|
||||
# disk, one NIC 52:54:00:9e:10:03 on pxetest-imaging,
|
||||
# network boot first (UEFI IPv4 PXE).
|
||||
#
|
||||
# Usage: tests/vm/create.sh
|
||||
source "$(dirname "$0")/common.sh"
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
# --- isolated imaging network ---
|
||||
if ! net_exists "$IMAGING_NET"; then
|
||||
cat >"$TMP/net.xml" <<XML
|
||||
<network>
|
||||
<name>$IMAGING_NET</name>
|
||||
<bridge name='$IMAGING_BRIDGE' stp='on' delay='0'/>
|
||||
</network>
|
||||
XML
|
||||
virsh net-define "$TMP/net.xml" >/dev/null
|
||||
log "defined network $IMAGING_NET (isolated, no forward, no ip)"
|
||||
fi
|
||||
virsh net-autostart --disable "$IMAGING_NET" >/dev/null 2>&1 || true
|
||||
if ! net_active "$IMAGING_NET"; then
|
||||
virsh net-start "$IMAGING_NET" >/dev/null
|
||||
fi
|
||||
assert_imaging_isolated
|
||||
net_exists "$GE_NET" || die "libvirt network '$GE_NET' (NAT) does not exist"
|
||||
net_active "$GE_NET" || virsh net-start "$GE_NET" >/dev/null
|
||||
|
||||
# --- volumes ---
|
||||
if ! vol_exists "$SERVER_DISK_VOL"; then
|
||||
virsh vol-create-as "$POOL" "$SERVER_DISK_VOL" "$SERVER_DISK_SIZE" --format qcow2 >/dev/null
|
||||
log "created $SERVER_DISK_VOL ($SERVER_DISK_SIZE thin qcow2)"
|
||||
fi
|
||||
if ! vol_exists "$CLIENT_DISK_VOL"; then
|
||||
virsh vol-create-as "$POOL" "$CLIENT_DISK_VOL" 1G --format qcow2 >/dev/null
|
||||
log "created $CLIENT_DISK_VOL (1G blank)"
|
||||
fi
|
||||
vol_exists "$USB_VOL" || log "WARNING: no $USB_VOL volume yet; run build-image.sh before start.sh"
|
||||
|
||||
# Disks are type='file' with the pool's path: with type='volume' sources
|
||||
# qemu got "Permission denied" opening them (AppArmor profile).
|
||||
POOL_DIR=$(virsh pool-dumpxml "$POOL" | sed -n 's|.*<path>\(.*\)</path>.*|\1|p' | head -1)
|
||||
[ -n "$POOL_DIR" ] || die "cannot read the path of pool $POOL"
|
||||
|
||||
# Secure Boot with Microsoft keys enrolled: libvirt picks the edk2
|
||||
# descriptor (40-edk2-x86_64-secure-enrolled.json) and copies its
|
||||
# OVMF_VARS_4M.ms.fd template into a per-VM nvram.
|
||||
efi_os() {
|
||||
cat <<XML
|
||||
<os firmware='efi'>
|
||||
<type arch='x86_64' machine='q35'>hvm</type>
|
||||
<firmware>
|
||||
<feature enabled='yes' name='secure-boot'/>
|
||||
<feature enabled='yes' name='enrolled-keys'/>
|
||||
</firmware>
|
||||
</os>
|
||||
<features><acpi/><apic/><smm state='on'/></features>
|
||||
XML
|
||||
}
|
||||
|
||||
# --- server VM ---
|
||||
# Boot order: the installed disk first, the USB second. A blank disk falls
|
||||
# through to the USB; after the install the disk boots, so autoinstall does
|
||||
# not loop. CIDATA stays attached for the first-boot playbook.
|
||||
if ! dom_exists "$SERVER_VM"; then
|
||||
cat >"$TMP/server.xml" <<XML
|
||||
<domain type='kvm'>
|
||||
<name>$SERVER_VM</name>
|
||||
<memory unit='MiB'>$SERVER_MEM_MIB</memory>
|
||||
<vcpu>2</vcpu>
|
||||
$(efi_os)
|
||||
<cpu mode='host-passthrough'/>
|
||||
<clock offset='utc'/>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2' discard='unmap'/>
|
||||
<source file='$POOL_DIR/$SERVER_DISK_VOL'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
<boot order='1'/>
|
||||
</disk>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
<source file='$POOL_DIR/$USB_VOL'/>
|
||||
<target dev='sda' bus='usb' removable='on'/>
|
||||
<boot order='2'/>
|
||||
</disk>
|
||||
<controller type='usb' model='qemu-xhci'/>
|
||||
<interface type='network'>
|
||||
<source network='$GE_NET'/>
|
||||
<mac address='$SERVER_GE_MAC'/>
|
||||
<model type='virtio'/>
|
||||
</interface>
|
||||
<interface type='network'>
|
||||
<source network='$IMAGING_NET'/>
|
||||
<mac address='$SERVER_IMAGING_MAC'/>
|
||||
<model type='virtio'/>
|
||||
</interface>
|
||||
<serial type='pty'/>
|
||||
<console type='pty'/>
|
||||
<graphics type='vnc' listen='127.0.0.1' autoport='yes'/>
|
||||
<video><model type='virtio'/></video>
|
||||
<memballoon model='virtio'/>
|
||||
<rng model='virtio'><backend model='random'>/dev/urandom</backend></rng>
|
||||
</devices>
|
||||
</domain>
|
||||
XML
|
||||
virsh define "$TMP/server.xml" >/dev/null
|
||||
log "defined $SERVER_VM"
|
||||
fi
|
||||
|
||||
# --- client VM ---
|
||||
if ! dom_exists "$CLIENT_VM"; then
|
||||
cat >"$TMP/client.xml" <<XML
|
||||
<domain type='kvm'>
|
||||
<name>$CLIENT_VM</name>
|
||||
<memory unit='MiB'>$CLIENT_MEM_MIB</memory>
|
||||
<vcpu>2</vcpu>
|
||||
$(efi_os)
|
||||
<cpu mode='host-passthrough'/>
|
||||
<clock offset='utc'/>
|
||||
<devices>
|
||||
<interface type='network'>
|
||||
<source network='$IMAGING_NET'/>
|
||||
<mac address='$CLIENT_MAC'/>
|
||||
<model type='virtio'/>
|
||||
<rom enabled='no'/>
|
||||
<boot order='1'/>
|
||||
</interface>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='$POOL_DIR/$CLIENT_DISK_VOL'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
<boot order='2'/>
|
||||
</disk>
|
||||
<serial type='pty'/>
|
||||
<console type='pty'/>
|
||||
<graphics type='vnc' listen='127.0.0.1' autoport='yes'/>
|
||||
<video><model type='virtio'/></video>
|
||||
<memballoon model='virtio'/>
|
||||
</devices>
|
||||
</domain>
|
||||
XML
|
||||
virsh define "$TMP/client.xml" >/dev/null
|
||||
log "defined $CLIENT_VM"
|
||||
fi
|
||||
|
||||
# Never attach a pxetest VM anywhere but default NAT / pxetest-imaging.
|
||||
for vm in "$SERVER_VM" "$CLIENT_VM"; do
|
||||
while read -r _ type src _ _; do
|
||||
case "$type:$src" in
|
||||
network:"$GE_NET") [ "$vm" = "$SERVER_VM" ] || die "$vm is on $GE_NET" ;;
|
||||
network:"$IMAGING_NET") ;;
|
||||
*) die "$vm has an interface on $type:$src (only $GE_NET / $IMAGING_NET allowed)" ;;
|
||||
esac
|
||||
done < <(virsh domiflist "$vm" | tail -n +3 | grep -v '^$')
|
||||
done
|
||||
log "ready. Playbook NIC pins for this site:"
|
||||
log " pxe_imaging_mac: \"$SERVER_IMAGING_MAC\" (pxe_nic_mac)"
|
||||
log " pxe_ge_mac: \"$SERVER_GE_MAC\" (corp_nic_mac)"
|
||||
Reference in New Issue
Block a user