#!/usr/bin/env bash # swap.sh — run frank-dragoon on the candidate env through a transient systemd # drop-in (the fleet's A/B law: restart the SERVICE with a different # FRANK_DRAGOON_ENV_FILE, never a scratch port — one iGPU holds one server). # # swap.sh candidate install the drop-in, restart, print the boot ledger # swap.sh restore retire the drop-in (moved, never deleted), restart back # onto the repo env, print the boot ledger set -euo pipefail UNIT=frank-dragoon DROP=/etc/systemd/system/$UNIT.service.d/v2abl.conf ENVF=/tmp/frank-dragoon-v2abl.env LOG=/home/dank/logs/frank_dragoon.log ledger() { echo "--- boot ledger (kv pool / weights / mtp / clamp)" grep -aiE "kv pool|KV budget|checkpoint:|n-gram|vision|pinned|memory:|clamp|warn|error|MTP|prompt cache|version" \ "$LOG" | head -30 } case "${1:-}" in candidate) [ -f "$ENVF" ] || { echo "missing $ENVF" >&2; exit 1; } sudo mkdir -p "$(dirname "$DROP")" printf '[Service]\nEnvironment=FRANK_DRAGOON_ENV_FILE=%s\n' "$ENVF" \ | sudo tee "$DROP" >/dev/null sudo systemctl daemon-reload # the census window masks the unit; a masked unit cannot be started sudo systemctl unmask "$UNIT" 2>/dev/null || true sudo systemctl restart "$UNIT" echo "--- waiting for the listener (load is minutes; the listener opens after the full load)" for _ in $(seq 1 120); do curl -sf -m 5 -o /dev/null "http://127.0.0.1:7770/health" && break sleep 5 done systemctl is-active "$UNIT" curl -s -m 5 http://127.0.0.1:7770/v1/models | head -c 300; echo ledger ;; restore) if [ -f "$DROP" ]; then sudo mv "$DROP" "/tmp/v2abl.conf.retired-$(date +%s)" sudo systemctl daemon-reload fi sudo systemctl unmask "$UNIT" 2>/dev/null || true sudo systemctl restart "$UNIT" for _ in $(seq 1 120); do curl -sf -m 5 -o /dev/null "http://127.0.0.1:7770/health" && break sleep 5 done systemctl is-active "$UNIT" curl -s -m 5 http://127.0.0.1:7770/v1/models | head -c 300; echo ledger ;; *) echo "usage: $0 candidate|restore" >&2; exit 2 ;; esac