From bbea25f22462af3caa1135c74d63ee17921c6e0d Mon Sep 17 00:00:00 2001 From: oval Date: Tue, 7 Jul 2026 16:57:39 +0000 Subject: [PATCH] Add scripts/run-qemu.sh --- scripts/run-qemu.sh | 176 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 scripts/run-qemu.sh diff --git a/scripts/run-qemu.sh b/scripts/run-qemu.sh new file mode 100644 index 0000000..42f312a --- /dev/null +++ b/scripts/run-qemu.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash +# ─────────────────────────────────────────────────────────── +# run-qemu.sh — Launch the Ansible Control Node VM +# +# Boots the minimal Alpine Linux VM with: +# • Machine: pc-q35-10.0 +# • TTY: ttyS0, xterm-256color (serial console) +# • Keyboard: PS/2 (atkbd via QEMU default) +# • Network: user-mode NAT with port forwards: +# localhost:2222 → VM:22 (SSH) +# localhost:8080 → VM:8080 (custom services) +# • Disk: virtio-blk, read from output/ +# • Init: OpenRC (no systemd) +# +# Usage: +# ./scripts/run-qemu.sh # serial console (default) +# ./scripts/run-qemu.sh --gui # graphical (GTK) window +# ./scripts/run-qemu.sh --vnc :0 # VNC on display :0 +# ./scripts/run-qemu.sh --debug # verbose kernel boot +# +# Environment: +# QEMU_MEMORY — RAM size (default: 1024M) +# QEMU_SMP — CPU count (default: 2) +# SSH_PORT — host port for SSH forward (default: 2222) +# +# Access the VM: +# ssh -p 2222 ansible@localhost # password: ansible +# ssh -p 2222 root@localhost # password: ansible +# +# Stop the VM: +# Press Ctrl-A then X (in -nographic mode) +# Or: sudo shutdown -h now (inside VM) +# ─────────────────────────────────────────────────────────── +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +OUTPUT_DIR="${OUTPUT_DIR:-$SCRIPT_DIR/../output}" + +# ── Configuration (env-overridable) ───────────────────────── +QEMU_BIN="${QEMU_BIN:-qemu-system-x86_64}" +QEMU_MACHINE="${QEMU_MACHINE:-pc-q35-10.0}" +QEMU_MEMORY="${QEMU_MEMORY:-1024M}" +QEMU_SMP="${QEMU_SMP:-2}" +SSH_PORT="${SSH_PORT:-2222}" +EXTRA_PORT="${EXTRA_PORT:-8090}" + +# ── Colour helpers ────────────────────────────────────────── +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' +BLUE='\033[0;34m'; BOLD='\033[1m'; NC='\033[0m' +info() { echo -e "${BLUE}[*]${NC} $*"; } +ok() { echo -e "${GREEN}[✓]${NC} $*"; } +warn() { echo -e "${YELLOW}[!]${NC} $*"; } + +# ── Find build artifacts ──────────────────────────────────── +# Prefer qcow2 over raw +if [ -f "$OUTPUT_DIR/ansible-node.qcow2" ]; then + DISK="$OUTPUT_DIR/ansible-node.qcow2" + DISK_FMT="qcow2" +elif [ -f "$OUTPUT_DIR/ansible-node.raw" ]; then + DISK="$OUTPUT_DIR/ansible-node.raw" + DISK_FMT="raw" +else + echo -e "${RED}[✗]${NC} No disk image found in ${OUTPUT_DIR}" + echo " Run ./scripts/build-qemu.sh first." + exit 1 +fi + +KERNEL="$OUTPUT_DIR/vmlinuz-virt" +INITRD="$OUTPUT_DIR/initramfs-virt" + +for f in "$DISK" "$KERNEL" "$INITRD"; do + if [ ! -f "$f" ]; then + echo -e "${RED}[✗]${NC} Missing: $f" + exit 1 + fi +done + +# ── Parse arguments ───────────────────────────────────────── +DISPLAY_MODE="nographic" +KERNEL_APPEND="root=/dev/vda console=ttyS0 TERM=xterm-256color quiet modules=virtio_blk,ext4 rootflags=rw" +EXTRA_QEMU_ARGS=() + +while [[ $# -gt 0 ]]; do + case "$1" in + --gui|-g) + DISPLAY_MODE="gtk" + ;; + --vnc) + DISPLAY_MODE="vnc" + VNC_DISPLAY="${2:-:0}" + shift + ;; + --debug) + # Remove 'quiet', add verbose/delay for debugging + KERNEL_APPEND="${KERNEL_APPEND// quiet/} debug_init rootdelay=3" + ;; + --help|-h) + echo "Usage: $0 [--gui|--vnc :N|--debug] [extra qemu args...]" + echo "" + echo "Modes:" + echo " (default) Serial console (-nographic), Ctrl-A X to exit" + echo " --gui Graphical GTK window with keyboard support" + echo " --vnc :N VNC server on display N" + echo " --debug Verbose kernel boot messages" + echo "" + echo "Environment:" + echo " QEMU_MEMORY=1024M RAM size" + echo " QEMU_SMP=2 CPU count" + echo " SSH_PORT=2222 Host SSH port" + exit 0 + ;; + *) + EXTRA_QEMU_ARGS+=("$1") + ;; + esac + shift +done + +# ── Display mode flags ────────────────────────────────────── +case "$DISPLAY_MODE" in + nographic) + DISPLAY_FLAG="-nographic" + ;; + gtk) + DISPLAY_FLAG="-display gtk" + # QEMU's GTK display includes keyboard support via PS/2 emulation + # which covers the CONFIG_KEYBOARD_ATKBD kernel requirement + ;; + vnc) + DISPLAY_FLAG="-vnc ${VNC_DISPLAY} -vga virtio" + KERNEL_APPEND="$KERNEL_APPEND video=1024x768" + ;; +esac + +# ── Launch ────────────────────────────────────────────────── +echo "" +echo -e "${BOLD}══════════════════════════════════════════════${NC}" +echo -e "${BOLD} Ansible Control Node${NC}" +echo -e "${BOLD}══════════════════════════════════════════════${NC}" +echo "" +echo -e " Machine: ${GREEN}${QEMU_MACHINE}${NC}" +echo -e " Memory: ${GREEN}${QEMU_MEMORY}${NC}" +echo -e " CPUs: ${GREEN}${QEMU_SMP}${NC}" +echo -e " Disk: ${GREEN}${DISK_FMT}:${DISK}${NC}" +echo -e " Display: ${GREEN}${DISPLAY_MODE}${NC}" +echo -e " Kernel: ${KERNEL_APPEND}" +echo "" +echo -e " SSH: ${YELLOW}ssh -p ${SSH_PORT} ansible@localhost${NC}" +echo -e " Password: ${YELLOW}ansible${NC}" +echo "" +echo -e " ${BOLD}Ctrl-A X${NC} to quit (serial mode)" +echo -e " ${BOLD}Ctrl-C${NC} to force-quit (any mode)" +echo "" + +# Build netdev string, skipping extra port if already in use +NETDEV_FORWARDS="hostfwd=tcp::${SSH_PORT}-:22" +if ! ss -tlnp 2>/dev/null | grep -q ":${EXTRA_PORT} "; then + NETDEV_FORWARDS="${NETDEV_FORWARDS},hostfwd=tcp::${EXTRA_PORT}-:8080" +else + warn "Port ${EXTRA_PORT} already in use — skipping extra forward" +fi + +# shellcheck disable=SC2086 +exec "$QEMU_BIN" \ + -machine "$QEMU_MACHINE" \ + -m "$QEMU_MEMORY" \ + -smp "$QEMU_SMP" \ + -enable-kvm \ + -kernel "$KERNEL" \ + -initrd "$INITRD" \ + -append "$KERNEL_APPEND" \ + -drive "file=$DISK,if=virtio,format=$DISK_FMT" \ + -netdev "user,id=net0,${NETDEV_FORWARDS}" \ + -device virtio-net,netdev=net0 \ + $DISPLAY_FLAG \ + "${EXTRA_QEMU_ARGS[@]}"