0265afa054
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.
386 lines
13 KiB
Bash
Executable File
386 lines
13 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Sysadmin Chronicles — Installer
|
|
# Usage: bash install.sh
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$SCRIPT_DIR"
|
|
|
|
source "$PROJECT_ROOT/tools/lib/ui.sh"
|
|
source "$PROJECT_ROOT/tools/lib/config.sh"
|
|
source "$PROJECT_ROOT/tools/lib/deps.sh"
|
|
source "$PROJECT_ROOT/tools/lib/libvirt.sh"
|
|
source "$PROJECT_ROOT/tools/lib/vm.sh"
|
|
|
|
OWNER_USER="${SUDO_USER:-$USER}"
|
|
OWNER_HOME="$(getent passwd "$OWNER_USER" | cut -d: -f6)"
|
|
OWNER_HOME="${OWNER_HOME:-$HOME}"
|
|
|
|
SC_LOG_DIR="$OWNER_HOME/.local/share/sysadmin-chronicles"
|
|
export SC_INSTALL_LOG="$SC_LOG_DIR/install.log"
|
|
export LIBVIRT_DEFAULT_URI="${LIBVIRT_DEFAULT_URI:-qemu:///system}"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 1 — Welcome
|
|
# ---------------------------------------------------------------------------
|
|
|
|
sc_header "SYSADMIN CHRONICLES — SETUP"
|
|
cat << 'WELCOME'
|
|
Welcome! This installer will:
|
|
• Install a few system tools (KVM, QEMU, libvirt)
|
|
• Set up a private virtual network for the game
|
|
• Build three virtual machines (~30 minutes, once only)
|
|
|
|
WELCOME
|
|
|
|
DEFAULT_GAME_DIR="$OWNER_HOME/Games/sysadmin-chronicles"
|
|
[ "$PROJECT_ROOT" = "$DEFAULT_GAME_DIR" ] || DEFAULT_GAME_DIR="$PROJECT_ROOT"
|
|
|
|
SC_GAME_DIR="$(sc_prompt "Where would you like to install the game?" "$DEFAULT_GAME_DIR")"
|
|
while [[ "$SC_GAME_DIR" == *//* ]]; do
|
|
SC_GAME_DIR="${SC_GAME_DIR//\/\//\/}"
|
|
done
|
|
while [ "$SC_GAME_DIR" != "/" ] && [ "${SC_GAME_DIR%/}" != "$SC_GAME_DIR" ]; do
|
|
SC_GAME_DIR="${SC_GAME_DIR%/}"
|
|
done
|
|
echo ""
|
|
SC_IMAGES_DIR="$SC_GAME_DIR/images"
|
|
|
|
# Build scripts normally default to /var/lib/libvirt when using qemu:///system.
|
|
# The installer asks for a custom game directory, so force the VM tooling to use
|
|
# the libvirt storage pool path selected above instead of silently falling back
|
|
# to /var/lib/libvirt/images/sysadmin-chronicles.
|
|
export SC_HOME="$SC_LOG_DIR"
|
|
export SC_IMAGE_ROOT="$SC_IMAGES_DIR"
|
|
export SC_POOL_NAME="sc-images"
|
|
export SC_NETWORK_NAME="sc-internal"
|
|
export SC_OWNER_USER="$OWNER_USER"
|
|
export SC_OWNER_HOME="$OWNER_HOME"
|
|
|
|
sc_log_append() {
|
|
mkdir -p "$SC_LOG_DIR"
|
|
{
|
|
printf '\n[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
|
} >> "$SC_INSTALL_LOG" 2>/dev/null || true
|
|
}
|
|
|
|
sc_log_cmd() {
|
|
mkdir -p "$SC_LOG_DIR"
|
|
{
|
|
printf '\n[%s] $' "$(date '+%Y-%m-%d %H:%M:%S')"
|
|
printf ' %q' "$@"
|
|
printf '\n'
|
|
"$@"
|
|
} >> "$SC_INSTALL_LOG" 2>&1
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 2 — Silent system check
|
|
# ---------------------------------------------------------------------------
|
|
|
|
detect_distro
|
|
|
|
if [ "$SC_DISTRO" = "unknown" ]; then
|
|
sc_warn "Could not detect your Linux distribution."
|
|
sc_warn "Dependency auto-install may not work — you may need to install packages manually."
|
|
echo ""
|
|
fi
|
|
|
|
mapfile -t _missing_deps < <(check_deps 2>/dev/null || true)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 3 — Dependency install (only if needed)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
if [ "${#_missing_deps[@]}" -gt 0 ]; then
|
|
sc_section "System check"
|
|
echo ""
|
|
echo " Your system is missing the following tools:"
|
|
echo ""
|
|
_shown_labels=""
|
|
for _dep in "${_missing_deps[@]}"; do
|
|
[ -z "$_dep" ] && continue
|
|
_label="$(dep_label "$_dep")"
|
|
[ -z "$_label" ] && continue
|
|
case "|${_shown_labels}|" in
|
|
*"|${_label}|"*) ;;
|
|
*) echo " • $_label"; _shown_labels="${_shown_labels}|${_label}" ;;
|
|
esac
|
|
done
|
|
echo ""
|
|
if sc_confirm "Install them now? You'll be asked for your password." "Y"; then
|
|
echo ""
|
|
mkdir -p "$SC_LOG_DIR"
|
|
# Write log header
|
|
cat > "$SC_INSTALL_LOG" << EOF
|
|
# Sysadmin Chronicles — Install Log
|
|
# Created: $(date '+%Y-%m-%d %H:%M:%S')
|
|
# Distro: ${SC_DISTRO} ($(uname -r))
|
|
# Game dir: $SC_GAME_DIR
|
|
# Images: $SC_IMAGES_DIR
|
|
|
|
EOF
|
|
install_deps "${_missing_deps[@]}"
|
|
log_present_deps
|
|
echo ""
|
|
# Append manual removal hint
|
|
{
|
|
echo ""
|
|
echo "# To remove manually:"
|
|
printf '# sudo %s\n' "$(case "$SC_DISTRO" in
|
|
arch) echo 'pacman -Rns libvirt qemu-system-x86 virt-install virt-viewer' ;;
|
|
debian|ubuntu) echo 'apt-get remove libvirt-daemon-system qemu-kvm virt-manager' ;;
|
|
fedora) echo 'dnf remove libvirt qemu-kvm virt-install' ;;
|
|
*) echo 'remove the packages listed above' ;;
|
|
esac)"
|
|
} >> "$SC_INSTALL_LOG"
|
|
sc_ok "Dependencies installed."
|
|
echo ""
|
|
echo " Install log: $SC_INSTALL_LOG"
|
|
echo ""
|
|
else
|
|
echo ""
|
|
sc_warn "Skipping dependency install. Some features may not work."
|
|
echo ""
|
|
fi
|
|
else
|
|
mkdir -p "$SC_LOG_DIR"
|
|
if [ ! -f "$SC_INSTALL_LOG" ]; then
|
|
cat > "$SC_INSTALL_LOG" << EOF
|
|
# Sysadmin Chronicles — Install Log
|
|
# Created: $(date '+%Y-%m-%d %H:%M:%S')
|
|
# Distro: ${SC_DISTRO} ($(uname -r))
|
|
# Game dir: $SC_GAME_DIR
|
|
# Images: $SC_IMAGES_DIR
|
|
|
|
EOF
|
|
log_present_deps
|
|
fi
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 4 — Network, storage, and SSH key setup
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Ensure libvirtd is running before touching networks or pools.
|
|
# Pacman installs the socket unit but does not start/enable it.
|
|
_libvirtd_ready=false
|
|
_need_relogin=false
|
|
|
|
# Ensure user is in the libvirt group (needed for virsh access without sudo)
|
|
if ! groups "$OWNER_USER" 2>/dev/null | grep -qw libvirt; then
|
|
sc_info "Adding $OWNER_USER to the libvirt group..."
|
|
sudo usermod -aG libvirt "$OWNER_USER" 2>/dev/null || true
|
|
_need_relogin=true
|
|
fi
|
|
|
|
# Clear any failed unit state from a previous attempt
|
|
sudo systemctl reset-failed libvirtd.service libvirtd.socket 2>/dev/null || true
|
|
|
|
if ! systemctl is-active --quiet libvirtd.service 2>/dev/null; then
|
|
sc_info "Starting virtual machine daemon..."
|
|
# Enable the socket for future boots, start the service directly now
|
|
sudo systemctl enable libvirtd.socket >/dev/null 2>&1 || true
|
|
if ! sudo systemctl start libvirtd.service >/dev/null 2>&1; then
|
|
echo ""
|
|
echo " libvirtd failed to start. Details:"
|
|
sudo systemctl status libvirtd.service --no-pager -l 2>&1 | tail -25 | sed 's/^/ /'
|
|
echo ""
|
|
sc_fail "Fix the error above, then run install.sh again."
|
|
fi
|
|
fi
|
|
|
|
# Wait up to 30s for libvirtd.service to reach active state (pure systemd
|
|
# check — no virsh connection needed, works regardless of group membership
|
|
# in the current session).
|
|
for _i in $(seq 1 60); do
|
|
if systemctl is-active --quiet libvirtd.service 2>/dev/null; then
|
|
_libvirtd_ready=true
|
|
break
|
|
fi
|
|
sleep 0.5
|
|
done
|
|
|
|
if [ "$_libvirtd_ready" != true ]; then
|
|
echo ""
|
|
echo " libvirtd did not reach active state. Current status:"
|
|
sudo systemctl status libvirtd.service --no-pager -l 2>&1 | tail -25 | sed 's/^/ /'
|
|
echo ""
|
|
sc_fail "Fix the error above, then run install.sh again."
|
|
fi
|
|
|
|
# If the group was just added, the current shell does not have it yet. The
|
|
# install can still proceed by using sudo for virsh operations.
|
|
if virsh -c "$LIBVIRT_DEFAULT_URI" list >/dev/null 2>&1; then
|
|
export SC_VIRSH_SUDO=false
|
|
else
|
|
export SC_VIRSH_SUDO=true
|
|
sc_log_append "virsh is not usable by $OWNER_USER in this session; using sudo for installer libvirt operations."
|
|
fi
|
|
|
|
sc_log_append "Installer paths: SC_GAME_DIR=$SC_GAME_DIR SC_IMAGES_DIR=$SC_IMAGES_DIR SC_IMAGE_ROOT=$SC_IMAGE_ROOT LIBVIRT_DEFAULT_URI=$LIBVIRT_DEFAULT_URI SC_VIRSH_SUDO=${SC_VIRSH_SUDO:-false}"
|
|
sc_log_cmd id || true
|
|
sc_log_cmd groups "$OWNER_USER" || true
|
|
sc_log_cmd systemctl is-active libvirtd.service || true
|
|
|
|
sc_section "Setting up game network"
|
|
echo ""
|
|
|
|
NETWORK_XML="$PROJECT_ROOT/tools/vm/network-sc-internal.xml"
|
|
|
|
sc_spinner "Creating private game network"
|
|
if ! ensure_network "sc-internal" "$NETWORK_XML"; then
|
|
sc_spinner_stop
|
|
echo ""
|
|
sc_fail "Could not create the game network.
|
|
|
|
Make sure the virtual machine tools are installed and running:
|
|
sudo systemctl enable --now libvirtd.socket
|
|
|
|
Then run install.sh again."
|
|
fi
|
|
sc_spinner_stop
|
|
sc_ok "Private game network created"
|
|
|
|
sc_spinner "Configuring VM image storage"
|
|
if ! ensure_pool "sc-images" "$SC_IMAGES_DIR"; then
|
|
sc_spinner_stop
|
|
sc_fail "Could not configure image storage at $SC_IMAGES_DIR"
|
|
fi
|
|
sc_spinner_stop
|
|
sc_ok "VM image storage configured at $SC_IMAGES_DIR"
|
|
|
|
# Pre-create subdirectories used by tools/vm/lib/common.sh. Since these live
|
|
# under the user-selected install path, they should be user-writable. This also
|
|
# fails early with a useful message instead of producing a one-line build log.
|
|
if ! mkdir -p "$SC_IMAGES_DIR/base" "$SC_IMAGES_DIR/seed"; then
|
|
sc_fail "Could not create VM image directories under $SC_IMAGES_DIR"
|
|
fi
|
|
chown -R "$OWNER_USER:$OWNER_USER" "$SC_IMAGES_DIR" 2>/dev/null || true
|
|
sc_log_cmd ls -lah "$SC_IMAGES_DIR" || true
|
|
|
|
SC_SSH_KEY="$OWNER_HOME/.ssh/sc_host_key"
|
|
if [ ! -f "$SC_SSH_KEY" ]; then
|
|
sc_spinner "Generating game access keys"
|
|
mkdir -p "$(dirname "$SC_SSH_KEY")"
|
|
ssh-keygen -t ed25519 -N "" -C "sysadmin-chronicles-host" -f "$SC_SSH_KEY" >/dev/null 2>&1
|
|
chmod 600 "$SC_SSH_KEY"
|
|
chmod 644 "${SC_SSH_KEY}.pub"
|
|
chown "$OWNER_USER:$OWNER_USER" "$SC_SSH_KEY" "${SC_SSH_KEY}.pub" 2>/dev/null || true
|
|
sc_spinner_stop
|
|
sc_ok "Game access keys generated"
|
|
else
|
|
sc_ok "Game access keys already present"
|
|
fi
|
|
|
|
# Write config (survives game dir moves)
|
|
config_write SC_GAME_DIR "$SC_GAME_DIR"
|
|
config_write SC_IMAGES_DIR "$SC_IMAGES_DIR"
|
|
config_write SC_LIBVIRT_URI "$LIBVIRT_DEFAULT_URI"
|
|
config_write SC_INSTALL_DATE "$(date '+%Y-%m-%d')"
|
|
echo ""
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 5 — VM build
|
|
# ---------------------------------------------------------------------------
|
|
|
|
sc_section "Building your game world"
|
|
echo ""
|
|
echo " This happens once and takes about 30 minutes."
|
|
echo " You can leave this running in the background."
|
|
echo ""
|
|
|
|
_build_vm() {
|
|
local label="$1"
|
|
local n="$2"
|
|
local total="$3"
|
|
local profile="$4"
|
|
local logfile="$SC_LOG_DIR/build-${profile}.log"
|
|
local start_ts elapsed mins secs
|
|
start_ts="$(date +%s)"
|
|
printf " Building %-20s (%d/%d) " "$label" "$n" "$total"
|
|
{
|
|
echo "# Sysadmin Chronicles VM build log"
|
|
echo "# Created: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo "# Profile: $profile"
|
|
echo "# Game dir: $SC_GAME_DIR"
|
|
echo "# Images: $SC_IMAGES_DIR"
|
|
echo "# SC_IMAGE_ROOT: $SC_IMAGE_ROOT"
|
|
echo "# LIBVIRT_DEFAULT_URI: $LIBVIRT_DEFAULT_URI"
|
|
echo "# SC_VIRSH_SUDO: ${SC_VIRSH_SUDO:-false}"
|
|
echo ""
|
|
} > "$logfile"
|
|
if vm_build "$profile" >> "$logfile" 2>&1; then
|
|
elapsed=$(( $(date +%s) - start_ts ))
|
|
mins=$(( elapsed / 60 ))
|
|
secs=$(( elapsed % 60 ))
|
|
printf "✓ %dm %02ds\n" "$mins" "$secs"
|
|
else
|
|
printf "✗\n"
|
|
sc_warn "Build failed — see $logfile"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
echo "Generating TLS certificates..."
|
|
bash "$PROJECT_ROOT/tools/setup/generate-certs.sh"
|
|
echo ""
|
|
|
|
_build_vm "workstation" 1 3 "workstation"
|
|
_build_vm "web server" 2 3 "web-server"
|
|
_build_vm "build server" 3 3 "build-machine"
|
|
|
|
printf " Setting up quest scenarios "
|
|
bash "$PROJECT_ROOT/tools/setup/seed-vms.sh" --skip-build \
|
|
> "$SC_LOG_DIR/seed-vms.log" 2>&1 && printf "✓\n" || { printf "✗\n"; sc_warn "Quest setup had errors — see $SC_LOG_DIR/seed-vms.log"; }
|
|
echo ""
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 6 — Application menu entry
|
|
# ---------------------------------------------------------------------------
|
|
|
|
sc_section "Application menu launcher"
|
|
echo ""
|
|
if sc_confirm "Create an application-menu launcher? This does not add a desktop icon." "Y"; then
|
|
DESKTOP_FILE="$OWNER_HOME/.local/share/applications/sysadmin-chronicles.desktop"
|
|
mkdir -p "$(dirname "$DESKTOP_FILE")"
|
|
cat > "$DESKTOP_FILE" << EOF
|
|
[Desktop Entry]
|
|
Name=Sysadmin Chronicles
|
|
Comment=A sysadmin simulation game
|
|
Exec=bash $SC_GAME_DIR/start-game.sh
|
|
Terminal=true
|
|
Type=Application
|
|
Categories=Game;
|
|
EOF
|
|
sc_ok "Application-menu launcher created"
|
|
fi
|
|
echo ""
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 7 — Done
|
|
# ---------------------------------------------------------------------------
|
|
|
|
sc_done_banner
|
|
cat << EOF
|
|
Start the game:
|
|
bash $SC_GAME_DIR/start-game.sh
|
|
(or from your system application menu if you created the launcher; no desktop icon is installed)
|
|
|
|
Rebuild the virtual machines at any time:
|
|
bash $SC_GAME_DIR/tools/vm/rebuild-vms.sh
|
|
|
|
Install log:
|
|
$SC_INSTALL_LOG
|
|
|
|
EOF
|
|
|
|
if [ "$_need_relogin" = true ]; then
|
|
sc_warn "You were added to the 'libvirt' group during install."
|
|
sc_warn "Log out and back in before running the game, or run:"
|
|
echo " newgrp libvirt"
|
|
echo ""
|
|
fi
|