Files
vh e376d0aec9 Initial commit: PFI fleet inventory, stacks, tooling, and backup pipeline
Captures the full workspace state built up to this point:

  - CLAUDE.md + README.md describing conventions and the four-host fleet
    (ana-ml2, ana-docker, nh3-docker, esh-docker-vm).
  - Per-host notes under servers/<host>/ with ssh-target fallback files
    and latest system-details snapshots (two in-compose credential leaks
    scrubbed; the upstream compose files still need to move those to .env).
  - scripts/: server_inspect.sh (read-only remote diagnostic),
    refresh-server-info.sh (dir-driven discovery + snapshot capture with
    validation warnings), add-host.sh, sync-stacks.sh (pull
    compose/conf trees), deploy-stack.sh (push with per-file diff + prompt).
  - stacks/: canonical compose for backrest, beszel, dozzle, llama-swap,
    rest-server-ana, rest-server-nh3, vllm-qwen3, plus the retired
    infinity reference. All use the .env-driven + traefik-net + homepage
    label pattern.
  - configs/restic/ana-docker/: first resticprofile config + pre-backup
    hook (Synapse pg_dump, Seafile mysqldump, Vaultwarden SQLite); templates
    for the other three hosts to come.
  - docs/pfi/: general infrastructure reference carried over.
  - .gitignore excludes .env, stacks-mirror/, and assorted secret/state
    filenames to prevent re-leaks on later commits.
2026-04-20 14:29:48 -07:00

70 lines
2.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# add-host.sh — register a new server so refresh-server-info.sh picks it up.
#
# Creates servers/<name>/ and writes servers/<name>/ssh-target with the
# given IP (or user@ip). The next `scripts/refresh-server-info.sh <name>`
# run will discover the host and pull its first system-details.txt.
#
# Usage:
# scripts/add-host.sh <name> <ip-or-user@ip>
# scripts/add-host.sh <name> <ip-or-user@ip> --force # overwrite existing
#
# Example:
# scripts/add-host.sh la-docker 10.60.50.12
# scripts/add-host.sh edge-01 admin@203.0.113.9
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
SERVERS_DIR="$REPO_ROOT/servers"
FORCE=0
POSITIONAL=()
for arg in "$@"; do
case "$arg" in
-f|--force) FORCE=1 ;;
-h|--help) sed -n '2,14p' "$0"; exit 0 ;;
-*) echo "error: unknown flag $arg" >&2; exit 2 ;;
*) POSITIONAL+=("$arg") ;;
esac
done
if [ "${#POSITIONAL[@]}" -ne 2 ]; then
echo "usage: $(basename "$0") <name> <ip-or-user@ip> [--force]" >&2
exit 2
fi
name="${POSITIONAL[0]}"
target="${POSITIONAL[1]}"
if [[ ! "$name" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then
echo "error: invalid host name '$name' (expected [a-zA-Z0-9._-])" >&2
exit 2
fi
# Trivial sanity check on the target — not exhaustive, just catches typos.
if [[ -z "$target" ]] || [[ "$target" =~ [[:space:]] ]]; then
echo "error: invalid ssh target '$target'" >&2
exit 2
fi
host_dir="$SERVERS_DIR/$name"
ssh_target_file="$host_dir/ssh-target"
if [ -f "$ssh_target_file" ] && [ "$FORCE" -ne 1 ]; then
existing=$(awk 'NF{print $1; exit}' "$ssh_target_file")
if [ "$existing" = "$target" ]; then
echo "host '$name' already registered with target '$target' — nothing to do"
exit 0
fi
echo "error: $ssh_target_file already exists (currently '$existing'); pass --force to overwrite" >&2
exit 1
fi
mkdir -p "$host_dir"
printf '%s\n' "$target" > "$ssh_target_file"
printf 'registered: %s → %s\n' "$name" "$target"
printf 'next: scripts/refresh-server-info.sh %s\n' "$name"