Files
sysadmin-chronicles/tools/setup/first-run-setup.sh
T
44r0n7 0265afa054 chore: bootstrap lean sysadmin-chronicles repo
Import the runnable game code, content, docs, scripts, and repo guidance while leaving local agent state, dependency installs, build output, and backup copies out of the published tree.
2026-05-02 11:49:07 -04:00

207 lines
7.2 KiB
Bash

#!/usr/bin/env bash
# first-run-setup.sh — Sysadmin Chronicles one-time host setup
#
# This script creates the libvirt resources (networks, storage pool) and SSH
# keys required for the game. It is safe to re-run — all actions are idempotent.
#
# What this does:
# 1. Creates sc-internal libvirt network (private NAT, game-only)
# 2. Creates sc-images storage pool for qcow2 VM images
# 3. Generates the host→guest SSH key pair (sc_host_key)
# 4. Checks libvirtd is running and user has access
#
# What this does NOT do:
# - Build VM images (that's seed-vms.sh)
# - Modify /etc/libvirt or system-wide config beyond the named libvirt resources
# - Require broad sudo during normal gameplay
#
# AGENT RULES: Never run provisioning scripts against VMs from here.
# This script only creates host infrastructure.
set -euo pipefail
OWNER_USER="${SUDO_USER:-$USER}"
OWNER_HOME="$(getent passwd "$OWNER_USER" | cut -d: -f6)"
OWNER_HOME="${OWNER_HOME:-$HOME}"
export LIBVIRT_DEFAULT_URI="${LIBVIRT_DEFAULT_URI:-qemu:///system}"
DRY_RUN=false
if [[ "${1:-}" == "--dry-run" ]]; then
DRY_RUN=true
echo "[DRY-RUN] No changes will be made."
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
run() {
if [ "$DRY_RUN" = "true" ]; then
echo " [would run] $*"
else
"$@"
fi
}
step() { echo ""; echo "── $* ───────────────────────"; }
ok() { echo "$*"; }
info() { echo "$*"; }
libvirt_reachable() {
virsh -q list --all >/dev/null 2>&1
}
libvirt_socket_available() {
systemctl is-active --quiet libvirtd.socket 2>/dev/null || \
systemctl is-active --quiet virtqemud.socket 2>/dev/null
}
echo ""
echo "══════════════════════════════════════════════════"
echo " Sysadmin Chronicles — First-Run Setup"
echo "══════════════════════════════════════════════════"
# Sanity: check libvirt access
step "Checking libvirt access"
if libvirt_reachable; then
ok "libvirt responds to virsh"
elif libvirt_socket_available; then
ok "libvirt socket activation is available"
else
echo " ERROR: libvirt is not reachable."
echo " Run: sudo systemctl enable --now libvirtd.socket"
exit 1
fi
# ---------------------------------------------------------------------------
step "Creating sc-internal libvirt network"
# ---------------------------------------------------------------------------
NETWORK_XML="$SCRIPT_DIR/../vm/network-sc-internal.xml"
write_network_xml() {
local target="$1"
cat > "$target" << 'EOF'
<network>
<name>sc-internal</name>
<forward mode='nat'/>
<bridge name='sc-br0' stp='on' delay='0'/>
<ip address='10.42.0.1' netmask='255.255.255.0'>
<dhcp>
<range start='10.42.0.10' end='10.42.0.50'/>
</dhcp>
</ip>
</network>
EOF
}
network_has_nat() {
virsh net-dumpxml sc-internal 2>/dev/null | grep -q "<forward mode=['\"]nat['\"]"
}
define_network() {
local label="$1"
local tmpxml
tmpxml=$(mktemp /tmp/sc-internal-XXXXXX.xml)
if [ -f "$NETWORK_XML" ]; then
cp "$NETWORK_XML" "$tmpxml"
else
write_network_xml "$tmpxml"
fi
run virsh net-define "$tmpxml"
run virsh net-autostart sc-internal
run virsh net-start sc-internal
rm -f "$tmpxml"
ok "$label"
}
if virsh net-list --all | grep -q "sc-internal"; then
if network_has_nat; then
ok "sc-internal network already exists with NAT"
else
info "Recreating sc-internal with NAT egress for guest provisioning..."
run virsh net-destroy sc-internal >/dev/null 2>&1 || true
run virsh net-undefine sc-internal
define_network "sc-internal network recreated and started"
fi
else
info "Creating sc-internal (private NAT, game-scoped network)..."
define_network "sc-internal network created and started"
fi
# ---------------------------------------------------------------------------
step "Creating sc-images storage pool"
# ---------------------------------------------------------------------------
if [ "${LIBVIRT_DEFAULT_URI}" = "qemu:///system" ]; then
IMAGES_DIR="/var/lib/libvirt/images/sysadmin-chronicles"
else
IMAGES_DIR="$OWNER_HOME/.local/share/sysadmin-chronicles/images"
fi
if virsh pool-list --all | grep -q "sc-images"; then
CURRENT_POOL_PATH="$(virsh pool-dumpxml sc-images 2>/dev/null | sed -n 's:.*<path>\(.*\)</path>.*:\1:p' | head -n1)"
if [ "$CURRENT_POOL_PATH" = "$IMAGES_DIR" ]; then
ok "sc-images pool already exists"
else
info "Recreating sc-images pool at $IMAGES_DIR (was $CURRENT_POOL_PATH)..."
run mkdir -p "$IMAGES_DIR"
run virsh pool-destroy sc-images >/dev/null 2>&1 || true
run virsh pool-undefine sc-images
run virsh pool-define-as sc-images dir --target "$IMAGES_DIR"
run virsh pool-autostart sc-images
run virsh pool-start sc-images
ok "sc-images pool recreated"
fi
else
info "Creating sc-images pool at $IMAGES_DIR..."
run mkdir -p "$IMAGES_DIR"
run virsh pool-define-as sc-images dir --target "$IMAGES_DIR"
run virsh pool-autostart sc-images
run virsh pool-start sc-images
ok "sc-images pool created"
fi
# ---------------------------------------------------------------------------
step "Generating SSH key pair"
# ---------------------------------------------------------------------------
KEY_PATH="$OWNER_HOME/.ssh/sc_host_key"
if [ -f "$KEY_PATH" ]; then
run chown "$OWNER_USER:$OWNER_USER" "$KEY_PATH" "${KEY_PATH}.pub" >/dev/null 2>&1 || true
run chmod 600 "$KEY_PATH" >/dev/null 2>&1 || true
run chmod 644 "${KEY_PATH}.pub" >/dev/null 2>&1 || true
ok "SSH key already exists: $KEY_PATH"
else
info "Generating ed25519 key: $KEY_PATH"
run mkdir -p "$(dirname "$KEY_PATH")"
run ssh-keygen -t ed25519 -N "" -C "sysadmin-chronicles-host" -f "$KEY_PATH"
run chmod 600 "$KEY_PATH"
run chmod 644 "${KEY_PATH}.pub"
run chown "$OWNER_USER:$OWNER_USER" "$KEY_PATH" "${KEY_PATH}.pub"
ok "SSH key generated"
info "Public key (add to VM authorized_keys during build):"
if [ "$DRY_RUN" = "false" ]; then
cat "${KEY_PATH}.pub"
fi
fi
# ---------------------------------------------------------------------------
step "Verifying group membership"
# ---------------------------------------------------------------------------
if id -nG | grep -qw "libvirt"; then
ok "User is in libvirt group"
else
info "Consider adding yourself to the libvirt group for passwordless VM control:"
info " sudo usermod -aG libvirt \$USER && newgrp libvirt"
fi
# ---------------------------------------------------------------------------
echo ""
echo "══════════════════════════════════════════════════"
echo " Setup complete."
echo " Next step: bash tools/setup/seed-vms.sh"
echo "══════════════════════════════════════════════════"
echo ""