#!/bin/bash
# Pull small config backups (sysupgrade -b) from the home routers into $1 (staging dir for the crystalcave restic job).
# the GL.iNet/OpenWrt routers via ssh (creds file home-routers.env, never printed).
# A router that is down is skipped with a warning; its last good copy stays in older snapshots.
OUT=${1:?staging dir}; U=canutethegreat; ENVF=/home/$U/.hermes/state/home-routers.env
install -d -m 700 "$OUT"
# kingscross (OpenWrt VM 100) is NOT pulled here: its config is ~10 MB and streaming that through the QEMU guest agent wedged the agent for a minute.
# It is covered by the nightly vzdump (az-guests, 02:30) that azkaban's restic job uploads to B2.
. "$ENVF"
for h in $ROUTER_HOSTS; do   # GL.iNet units only; the Slate is handled below by MAC (10.66.69.179 is an HS300 power strip - never probe it)
  f="$OUT/router-$h.tar.gz"; t="$f.new"
  SSHPASS=$ROUTER_SSH_PASS sshpass -e ssh -o ConnectTimeout=8 -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/root/.ssh/known_hosts.ctg "$ROUTER_SSH_USER@$h" 'sysupgrade -b -' > "$t" 2>/dev/null
  # Only replace the staged copy on success: a failed pull keeps the LAST GOOD copy staged, so it stays in
  # every new snapshot (and never ages out of the 30-day retention while the router is away).
  if [ "$(stat -c %s "$t" 2>/dev/null || echo 0)" -gt 200 ]; then mv -f "$t" "$f"; else echo "WARN: router $h config pull failed (down?); keeping last good copy" >&2; rm -f "$t"; fi
done
# GL.iNet Slate (GL-AR750S, hostname 'slate', owner's test router; Wi-Fi client of 10.66.69.11, often offline).
# Its address changes and it is not in kingscross' dhcp.leases: resolve it by MAC from kingscross' neighbour table
# (never a guessed IP), fall back to the last address that verified, and accept the tarball only if it is really the slate
# (hostname 'slate' in /etc/config/system). A missed pull is INFO, not an alert (test device, offline sometimes).
SLATE_MAC=e6:95:6e:49:a6:4c; SLATE_CACHE=/var/lib/ctg-backup/slate.ip
ip=$(timeout 40 sudo -u "$U" ssh -o BatchMode=yes -o ConnectTimeout=8 azkaban 'sudo qm guest exec 100 -- ip neigh' 2>/dev/null \
  | python3 -c 'import sys,json; print(json.load(sys.stdin).get("out-data",""))' 2>/dev/null \
  | awk -v m="$SLATE_MAC" 'tolower($0) ~ m && $1 ~ /^10\.66\.69\./ {print $1; exit}')
# No fallback to a cached IP: the Slate usually lives in the owner's bag, and its old address may belong to
# another device by now (we must never send the router password to it). Not in the neighbour table = away.
if [ -n "$ip" ]; then
  f="$OUT/router-slate.tar.gz"; t="$f.new"
  SSHPASS=$ROUTER_SSH_PASS sshpass -e ssh -o ConnectTimeout=8 -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/root/.ssh/known_hosts.ctg "$ROUTER_SSH_USER@$ip" 'sysupgrade -b -' > "$t" 2>/dev/null
  if [ "$(stat -c %s "$t" 2>/dev/null || echo 0)" -gt 200 ] && tar -xzOf "$t" etc/config/system 2>/dev/null | grep -qE "option hostname '?slate'?"; then
    mv -f "$t" "$f"; install -d -m 700 "$(dirname "$SLATE_CACHE")"; echo "$ip" > "$SLATE_CACHE"; date -Is > "$OUT/router-slate.pulled-at"
  else echo "INFO: slate ($ip) config pull failed (offline?); keeping last good copy" >&2; rm -f "$t"; fi
else echo "INFO: slate away (not on the LAN); keeping last good copy from $(cat "$OUT/router-slate.pulled-at" 2>/dev/null || echo unknown)" >&2; fi
exit 0
