diff --git a/docs/pxe_test_setup.sh b/docs/pxe_test_setup.sh new file mode 100755 index 0000000..67c66c6 --- /dev/null +++ b/docs/pxe_test_setup.sh @@ -0,0 +1,195 @@ +#!/usr/bin/env bash +set -euo pipefail + +# --- Configuration --- +LAB_DIR="/var/lib/harmony_pxe_test" +IMG_DIR="${LAB_DIR}/images" +STATE_DIR="${LAB_DIR}/state" +VM_OPN="opnsense-pxe" +VM_PXE="pxe-node-1" +NET_HARMONYLAN="harmonylan" + +# Network settings for the isolated LAN +VLAN_CIDR="192.168.150.0/24" +VLAN_GW="192.168.150.1" +VLAN_MASK="255.255.255.0" + +# VM Specifications +RAM_OPN="2048" +VCPUS_OPN="2" +DISK_OPN_GB="10" +OS_VARIANT_OPN="freebsd13.1" # Using a slightly more recent variant + +RAM_PXE="4096" +VCPUS_PXE="2" +DISK_PXE_GB="40" +OS_VARIANT_LINUX="centos-stream9" + +# ISO URLs and Paths +OPN_ISO="${IMG_DIR}/OPNsense-latest.iso" +CENTOS_ISO="${IMG_DIR}/CentOS-Stream-9-latest-boot.iso" +OPN_URL="https://mirror.wdc1.us.leaseweb.net/opnsense/releases/25.7/OPNsense-25.7-dvd-amd64.iso.bz2" +CENTOS_URL="https://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/images/boot.iso" + +# Libvirt connection URI for system-wide daemon +CONNECT_URI="qemu:///system" + +# --- Helper Functions --- +download_if_missing() { + local url="$1" + local dest="$2" + if [[ ! -f "$dest" ]]; then + echo "Downloading $url to $dest" + mkdir -p "$(dirname "$dest")" + local tmp + tmp="$(mktemp)" + curl -L --progress-bar "$url" -o "$tmp" + case "$url" in + *.bz2) bunzip2 -c "$tmp" > "$dest" && rm -f "$tmp" ;; + *) mv "$tmp" "$dest" ;; + esac + else + echo "Already present: $dest" + fi +} + +# Ensures a libvirt network is defined and active +ensure_network() { + local net_name="$1" + local net_xml_path="$2" + if virsh --connect "${CONNECT_URI}" net-info "${net_name}" >/dev/null 2>&1; then + echo "Network ${net_name} already exists." + else + echo "Defining network ${net_name} from ${net_xml_path}" + virsh --connect "${CONNECT_URI}" net-define "${net_xml_path}" + fi + + if ! virsh --connect "${CONNECT_URI}" net-info "${net_name}" | grep "Active: *yes"; then + echo "Starting network ${net_name}..." + virsh --connect "${CONNECT_URI}" net-start "${net_name}" + virsh --connect "${CONNECT_URI}" net-autostart "${net_name}" + fi +} + +# Destroys a VM completely +destroy_vm() { + local vm_name="$1" + if virsh --connect "${CONNECT_URI}" dominfo "$vm_name" >/dev/null 2>&1; then + echo "Destroying and undefining VM: ${vm_name}" + virsh --connect "${CONNECT_URI}" destroy "$vm_name" || true + virsh --connect "${CONNECT_URI}" undefine "$vm_name" --nvram + fi +} + +# Destroys a libvirt network +destroy_network() { + local net_name="$1" + if virsh --connect "${CONNECT_URI}" net-info "$net_name" >/dev/null 2>&1; then + echo "Destroying and undefining network: ${net_name}" + virsh --connect "${CONNECT_URI}" net-destroy "$net_name" || true + virsh --connect "${CONNECT_URI}" net-undefine "$net_name" + fi +} + +# --- Main Logic --- +create_lab_environment() { + # Create network definition files + cat > "${STATE_DIR}/default.xml" < + default + + + + + + + + +EOF + + cat > "${STATE_DIR}/${NET_HARMONYLAN}.xml" < + ${NET_HARMONYLAN} + + + + + +EOF + + # Ensure both networks exist and are active + ensure_network "default" "${STATE_DIR}/default.xml" + ensure_network "${NET_HARMONYLAN}" "${STATE_DIR}/${NET_HARMONYLAN}.xml" + + # --- Create OPNsense VM --- + local disk_opn="${IMG_DIR}/${VM_OPN}.qcow2" + if [[ ! -f "$disk_opn" ]]; then + qemu-img create -f qcow2 "$disk_opn" "${DISK_OPN_GB}G" + fi + + echo "Creating OPNsense VM..." + virt-install \ + --connect "${CONNECT_URI}" \ + --name "${VM_OPN}" \ + --ram "${RAM_OPN}" \ + --vcpus "${VCPUS_OPN}" \ + --cpu host-model-only \ + --os-variant "${OS_VARIANT_OPN}" \ + --graphics none \ + --noautoconsole \ + --disk path="${disk_opn}",format=qcow2,bus=virtio \ + --cdrom "${OPN_ISO}" \ + --network network=default,model=virtio \ + --network network="${NET_HARMONYLAN}",model=virtio \ + --boot uefi + + echo "OPNsense VM created. Connect with: sudo virsh console ${VM_OPN}" + echo "In OPNsense, assign WAN to the NIC with DHCP (default), and LAN to the ${NET_HARMONYLAN} NIC." + echo "Set LAN IP to ${VLAN_GW}/24 and enable DHCP on LAN (e.g., ${VLAN_GW%.*}.100 - ${VLAN_GW%.*}.200)." + + # --- Create PXE Client VM --- + local disk_pxe="${IMG_DIR}/${VM_PXE}.qcow2" + if [[ ! -f "$disk_pxe" ]]; then + qemu-img create -f qcow2 "$disk_pxe" "${DISK_PXE_GB}G" + fi + + echo "Creating PXE client VM..." + virt-install \ + --connect "${CONNECT_URI}" \ + --name "${VM_PXE}" \ + --ram "${RAM_PXE}" \ + --vcpus "${VCPUS_PXE}" \ + --cpu host-model-only \ + --os-variant "${OS_VARIANT_LINUX}" \ + --graphics none \ + --noautoconsole \ + --disk path="${disk_pxe}",format=qcow2,bus=virtio \ + --network network="${NET_HARMONYLAN}",model=virtio \ + --pxe \ + --boot uefi,menu=on + + echo "PXE VM created. It will attempt to netboot on ${NET_HARMONYLAN}." +} + +# --- Script Entrypoint --- +case "${1:-}" in + up) + mkdir -p "${IMG_DIR}" "${STATE_DIR}" + download_if_missing "$OPN_URL" "$OPN_ISO" + download_if_missing "$CENTOS_URL" "$CENTOS_ISO" + create_lab_environment + echo "Lab setup complete. Use 'sudo virsh list --all' to see VMs." + ;; + clean) + destroy_vm "${VM_PXE}" + destroy_vm "${VM_OPN}" + destroy_network "${NET_HARMONYLAN}" + # Optionally destroy the default network if you want a full reset + # destroy_network "default" + echo "Cleanup complete." + ;; + *) + echo "Usage: sudo $0 {up|clean}" + exit 1 + ;; +esac