bastion: discover-first PXE provisioning with multi-arch support
Rewrote bastion from install-only to discover-first flow: - Default mode discovers hardware (PXE boot → inventory → poweroff) - Discovered machines promoted to install via subcommand - Per-MAC iPXE dispatch (/dispatch?mac=) routes discover vs install - Python HTTP server with discovery API, state management, kickstart gen - Added full DHCP mode (DHCP_MODE=full) for isolated/test networks - Added arm64 UEFI support (client-arch 11, iPXE arm64 binary) - Added QEMU test script (aarch64+KVM on Asahi Linux) - All API endpoints unit tested and working Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
38
bastion.sh
38
bastion.sh
@@ -27,6 +27,9 @@ HTTP_PORT="${HTTP_PORT:-8080}"
|
||||
TIMEZONE="${TIMEZONE:-Europe/London}"
|
||||
LOCALE="${LOCALE:-en_GB.UTF-8}"
|
||||
BASTION_DIR="${BASTION_DIR:-/tmp/lab-bastion}"
|
||||
DHCP_MODE="${DHCP_MODE:-proxy}" # proxy (alongside existing DHCP) or full (bastion IS the DHCP server)
|
||||
DHCP_RANGE_START="${DHCP_RANGE_START:-}" # only for full mode, auto-derived if empty
|
||||
DHCP_RANGE_END="${DHCP_RANGE_END:-}"
|
||||
|
||||
# ──── Colors ──────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
||||
@@ -199,10 +202,11 @@ download() {
|
||||
FEDORA_MIRROR="https://download.fedoraproject.org/pub/fedora/linux/releases/${FEDORA_VERSION}/Everything/${ARCH}/os"
|
||||
|
||||
log "Fetching boot artifacts (Fedora ${FEDORA_VERSION} ${ARCH})..."
|
||||
download "https://boot.ipxe.org/undionly.kpxe" "$TFTPDIR/undionly.kpxe" "iPXE BIOS"
|
||||
download "https://boot.ipxe.org/ipxe.efi" "$TFTPDIR/ipxe.efi" "iPXE UEFI"
|
||||
download "${FEDORA_MIRROR}/images/pxeboot/vmlinuz" "$HTTPDIR/vmlinuz" "Fedora kernel"
|
||||
download "${FEDORA_MIRROR}/images/pxeboot/initrd.img" "$HTTPDIR/initrd.img" "Fedora initrd"
|
||||
download "https://boot.ipxe.org/undionly.kpxe" "$TFTPDIR/undionly.kpxe" "iPXE BIOS"
|
||||
download "https://boot.ipxe.org/ipxe.efi" "$TFTPDIR/ipxe.efi" "iPXE UEFI x86_64"
|
||||
download "https://boot.ipxe.org/arm64-efi/snponly.efi" "$TFTPDIR/ipxe-arm64.efi" "iPXE UEFI arm64"
|
||||
download "${FEDORA_MIRROR}/images/pxeboot/vmlinuz" "$HTTPDIR/vmlinuz" "Fedora kernel"
|
||||
download "${FEDORA_MIRROR}/images/pxeboot/initrd.img" "$HTTPDIR/initrd.img" "Fedora initrd"
|
||||
|
||||
# ──── Generate discovery kickstart ────────────────────────────────
|
||||
# Boots Fedora installer env, collects hardware info, POSTs to bastion, powers off.
|
||||
@@ -652,9 +656,15 @@ if __name__ == "__main__":
|
||||
PYSERVER
|
||||
|
||||
# ──── Generate dnsmasq config ─────────────────────────────────────
|
||||
# ──── Generate dnsmasq config ─────────────────────────────────────
|
||||
# Derive DHCP range for full mode
|
||||
if [[ "$DHCP_MODE" == "full" ]]; then
|
||||
DHCP_RANGE_START="${DHCP_RANGE_START:-${NETWORK%.*}.100}"
|
||||
DHCP_RANGE_END="${DHCP_RANGE_END:-${NETWORK%.*}.200}"
|
||||
fi
|
||||
|
||||
cat > "$BASTION_DIR/dnsmasq.conf" << DNSMASQ
|
||||
# Lab PXE Bastion — dnsmasq config
|
||||
# ProxyDHCP mode: adds PXE options without replacing existing DHCP
|
||||
|
||||
# Disable DNS (we only want DHCP/TFTP)
|
||||
port=0
|
||||
@@ -663,8 +673,17 @@ port=0
|
||||
interface=${IFACE}
|
||||
bind-interfaces
|
||||
|
||||
$(if [[ "$DHCP_MODE" == "full" ]]; then
|
||||
cat << FULL_DHCP
|
||||
# Full DHCP mode — bastion is the only DHCP server on this network
|
||||
dhcp-range=${DHCP_RANGE_START},${DHCP_RANGE_END},255.255.255.0,12h
|
||||
FULL_DHCP
|
||||
else
|
||||
cat << PROXY_DHCP
|
||||
# ProxyDHCP — works alongside existing DHCP (UniFi etc)
|
||||
dhcp-range=${NETWORK},proxy
|
||||
PROXY_DHCP
|
||||
fi)
|
||||
|
||||
# TFTP for initial PXE boot
|
||||
enable-tftp
|
||||
@@ -672,15 +691,17 @@ tftp-root=${TFTPDIR}
|
||||
|
||||
# Detect client architecture
|
||||
dhcp-match=set:bios,option:client-arch,0
|
||||
dhcp-match=set:efi64,option:client-arch,7
|
||||
dhcp-match=set:efi64,option:client-arch,9
|
||||
dhcp-match=set:efi-x86_64,option:client-arch,7
|
||||
dhcp-match=set:efi-x86_64,option:client-arch,9
|
||||
dhcp-match=set:efi-arm64,option:client-arch,11
|
||||
|
||||
# Detect iPXE clients (already chainloaded)
|
||||
dhcp-userclass=set:ipxe,iPXE
|
||||
|
||||
# First PXE boot → serve iPXE binary via TFTP
|
||||
dhcp-boot=tag:bios,tag:!ipxe,undionly.kpxe
|
||||
dhcp-boot=tag:efi64,tag:!ipxe,ipxe.efi
|
||||
dhcp-boot=tag:efi-x86_64,tag:!ipxe,ipxe.efi
|
||||
dhcp-boot=tag:efi-arm64,tag:!ipxe,ipxe-arm64.efi
|
||||
|
||||
# iPXE clients → chain to boot script via HTTP
|
||||
dhcp-boot=tag:ipxe,http://${SERVER_IP}:${HTTP_PORT}/boot.ipxe
|
||||
@@ -732,6 +753,7 @@ echo -e "${CYAN}${BOLD} Lab PXE Bastion — Discovery Mode${NC}"
|
||||
echo -e "${CYAN}${BOLD}════════════════════════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
echo -e " Network: ${BOLD}${NETWORK}/24${NC} via ${BOLD}${IFACE}${NC}"
|
||||
echo -e " DHCP: ${BOLD}${DHCP_MODE}${NC}$(if [[ "$DHCP_MODE" == "full" ]]; then echo " (${DHCP_RANGE_START}–${DHCP_RANGE_END})"; else echo " (alongside existing DHCP)"; fi)"
|
||||
echo -e " HTTP: ${BOLD}http://${SERVER_IP}:${HTTP_PORT}/${NC}"
|
||||
echo -e " OS: ${BOLD}Fedora ${FEDORA_VERSION} (${ARCH})${NC}"
|
||||
echo -e " State: ${BOLD}${STATEFILE}${NC}"
|
||||
|
||||
Reference in New Issue
Block a user