#!/usr/bin/env bash # build-vm.sh — Modular VM builder. Sources a profile file that declares VM # variables and a generate_user_data() function, then runs the common build # pipeline against it. # # Usage: # ./build-vm.sh [--dry-run] [--force] # # Example: # ./build-vm.sh profiles/web-server.sh --force set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" if [[ $# -lt 1 ]]; then echo "Usage: $0 [--dry-run] [--force]" exit 1 fi PROFILE_ARG="$1"; shift DRY_RUN=false FORCE=false while [[ $# -gt 0 ]]; do case "$1" in --dry-run) DRY_RUN=true; shift ;; --force) FORCE=true; shift ;; *) echo "Unknown argument: $1"; exit 1 ;; esac done source "$PROJECT_ROOT/tools/lib/config.sh" config_read || true if [ -n "${SC_IMAGES_DIR:-}" ]; then SC_IMAGE_ROOT="${SC_IMAGE_ROOT:-$SC_IMAGES_DIR}" export SC_IMAGE_ROOT fi if [ -n "${SC_LIBVIRT_URI:-}" ]; then LIBVIRT_DEFAULT_URI="${LIBVIRT_DEFAULT_URI:-$SC_LIBVIRT_URI}" export LIBVIRT_DEFAULT_URI fi source "$SCRIPT_DIR/lib/common.sh" # Resolve profile path: bare name (e.g. "web-server") or explicit path. if [[ -f "$PROFILE_ARG" ]]; then PROFILE="$PROFILE_ARG" elif [[ -f "$SCRIPT_DIR/profiles/${PROFILE_ARG}.sh" ]]; then PROFILE="$SCRIPT_DIR/profiles/${PROFILE_ARG}.sh" elif [[ -f "$SCRIPT_DIR/profiles/${PROFILE_ARG}" ]]; then PROFILE="$SCRIPT_DIR/profiles/${PROFILE_ARG}" else echo "Profile not found: $PROFILE_ARG" echo "Available profiles:" ls "$SCRIPT_DIR/profiles/" exit 1 fi source "$PROFILE" # Validate required profile variables. for var in DOMAIN HOSTNAME RAM_MB VCPUS DISK_SIZE GRAPHICS BASE_URL BASE_IMAGE; do [[ -n "${!var:-}" ]] || { echo "Profile must set $var"; exit 1; } done declare -f generate_user_data >/dev/null || { echo "Profile must define generate_user_data()"; exit 1; } GAME_HOST_IP="${SC_GAME_HOST_IP:-10.42.0.1}" POOL_DIR="$(pool_path)" DISK_PATH="$POOL_DIR/${DOMAIN}.qcow2" SEED_ISO="$SC_SEED_DIR/${DOMAIN}-seed.iso" PUBKEY="$(<"${SC_SSH_KEY}.pub")" export DOMAIN HOSTNAME RAM_MB VCPUS DISK_SIZE GRAPHICS BASE_URL BASE_IMAGE export GAME_HOST_IP POOL_DIR DISK_PATH SEED_ISO PUBKEY ensure_vm_tooling echo "" echo "══════════════════════════════════════════════════" echo " Building VM: $DOMAIN ($HOSTNAME)" echo " Profile: $(basename "$PROFILE")" echo " RAM: ${RAM_MB} MB vCPUs: ${VCPUS} Disk: ${DISK_SIZE}" echo "══════════════════════════════════════════════════" if domain_exists "$DOMAIN" && [ "$FORCE" = "false" ]; then ok "$DOMAIN already exists. Use --force to rebuild it." exit 0 fi step "Preparing base image" download_if_missing "$BASE_URL" "$BASE_IMAGE" step "Preparing cloud-init seed" tmpdir="$(mktemp -d)" trap 'rm -rf "$tmpdir"' EXIT generate_user_data > "$tmpdir/user-data" cat > "$tmpdir/meta-data" <