- 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.
173 lines
6.0 KiB
Bash
Executable File
173 lines
6.0 KiB
Bash
Executable File
#!/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)"
|