Ein Befehl statt einer Befehlsfolge, wenn der Tunnel weg ist
deploy/rescue-tunnel.sh stellt der Reihe nach fest, wo es klemmt, sagt es in klaren Worten und behebt, was sich vom Server aus beheben laesst: Container starten, wg0 hochziehen, gemerkte UDP-Stroeme wegraeumen. Und es sagt, wenn der Server noch vor v1.4.4 steht, wo der Tunnel noch am Warteschlangen-Arbeiter hing. Bewusst nichts Zerstoererisches — kein Neubau, kein Neustart des Tunnel-Containers. Genau der waere die Ursache und nicht die Loesung. Der Grund fuer das Skript: im Ernstfall soll niemand eine Befehlsfolge aus einem Runbook abtippen. Ein Befehl, und was danach noch zu tun bleibt, steht am Ende der Ausgabe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>claude/nice-moser-521659
parent
7b336d49f9
commit
33fb5be4df
|
|
@ -0,0 +1,138 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# CluPilot — den Tunnel wieder hinbekommen.
|
||||
#
|
||||
# Ein Befehl statt einer Befehlsfolge, die man sich im Ernstfall merken müsste.
|
||||
# Das Skript stellt der Reihe nach fest, WO es klemmt, sagt es in klaren Worten,
|
||||
# und behebt, was sich von hier aus beheben lässt.
|
||||
#
|
||||
# Es macht nichts Zerstörerisches: kein Neubau, kein Löschen, kein Neustart des
|
||||
# Tunnel-Containers. Genau der wäre nämlich die Ursache und nicht die Lösung —
|
||||
# ein Neubau schreibt die Weiterleitungsregeln neu und reisst alle Sitzungen ab.
|
||||
#
|
||||
# sudo -u clupilot bash deploy/rescue-tunnel.sh
|
||||
#
|
||||
# Ausführlich: docs/runbooks/tunnel-recovery.md
|
||||
set -uo pipefail
|
||||
|
||||
cd "$(cd "$(dirname "$0")/.." && pwd)"
|
||||
|
||||
log() { printf '\n\033[1;34m==>\033[0m %s\n' "$*"; }
|
||||
ok() { printf '\033[1;32m ✓\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m !\033[0m %s\n' "$*"; }
|
||||
bad() { printf '\033[1;31m ✗\033[0m %s\n' "$*"; }
|
||||
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
echo "Bitte als Dienstbenutzer starten, nicht als root:" >&2
|
||||
echo " sudo -u clupilot bash $0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
hub() { docker compose exec -T queue-provisioning "$@" 2>/dev/null; }
|
||||
|
||||
WG_PORT="$(grep -m1 '^WG_HUB_PORT=' .env 2>/dev/null | cut -d= -f2- | tr -d '"'"'"' ')"
|
||||
WG_PORT="${WG_PORT:-51820}"
|
||||
|
||||
# ── 1. Läuft der Container, in dessen Namensraum wg0 lebt? ───────────────────
|
||||
log "Der Container mit dem Tunnel"
|
||||
|
||||
if ! docker compose ps --status running queue-provisioning 2>/dev/null | grep -q queue-provisioning; then
|
||||
bad "queue-provisioning läuft nicht. Ich starte ihn."
|
||||
docker compose up -d queue-provisioning || true
|
||||
sleep 8
|
||||
fi
|
||||
|
||||
if docker compose ps --status running queue-provisioning 2>/dev/null | grep -q queue-provisioning; then
|
||||
ok "läuft"
|
||||
else
|
||||
bad "startet nicht. Das Protokoll sagt warum:"
|
||||
docker compose logs --tail=30 queue-provisioning
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prozess 1 verrät, ob der Server den Stand ab v1.4.4 hat. Vorher war es der
|
||||
# Warteschlangen-Arbeiter, und dann nimmt jeder seiner Abstürze den Tunnel mit.
|
||||
if hub sh -c 'tr "\0" " " < /proc/1/cmdline' | grep -q 'provisioning-worker.sh'; then
|
||||
ok "Der Tunnel hängt nicht mehr am Warteschlangen-Arbeiter (v1.4.4 oder neuer)"
|
||||
else
|
||||
warn "Prozess 1 ist noch der Arbeiter selbst — dieser Server steht vor v1.4.4."
|
||||
warn "Bis dahin nimmt jeder Absturz des Arbeiters den Tunnel mit. Update einspielen."
|
||||
fi
|
||||
|
||||
# ── 2. Steht wg0? ────────────────────────────────────────────────────────────
|
||||
log "Das Interface wg0"
|
||||
|
||||
if ! hub wg show wg0 >/dev/null 2>&1; then
|
||||
bad "wg0 fehlt. Ich ziehe es hoch."
|
||||
hub wg-quick up wg0 || true
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
if hub wg show wg0 >/dev/null 2>&1; then
|
||||
ok "steht"
|
||||
else
|
||||
bad "lässt sich nicht hochziehen. Liegt die Konfiguration überhaupt da?"
|
||||
hub ls -l /etc/wireguard/ || true
|
||||
echo
|
||||
bad "Weiter in docs/runbooks/tunnel-recovery.md, Abschnitt 'Der Tunnel kommt nicht hoch'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
peers="$(hub wg show wg0 peers | grep -c . || true)"
|
||||
if [[ "${peers:-0}" -gt 0 ]]; then
|
||||
ok "$peers Zugänge geladen"
|
||||
else
|
||||
warn "Kein einziger Zugang geladen — /etc/wireguard/wg0.conf ansehen."
|
||||
fi
|
||||
|
||||
# ── 3. Kommt auch etwas an? ──────────────────────────────────────────────────
|
||||
#
|
||||
# Das eigentliche Krankheitsbild: der Hub sendet, aber empfängt nichts. Dann
|
||||
# zeigen die im Kernel gemerkten UDP-Ströme noch auf einen Container, den es
|
||||
# nicht mehr gibt — und sie verfallen NICHT, weil WireGuards Keepalive sie alle
|
||||
# 25 Sekunden auffrischt. Das heilt nie von allein.
|
||||
log "Kommen Antworten an?"
|
||||
|
||||
stumm=0
|
||||
while read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
empfangen="$(awk '{print $1}' <<<"$line")"
|
||||
[[ "$empfangen" == "0" ]] && stumm=$((stumm + 1))
|
||||
done < <(hub wg show wg0 transfer | awk '{print $2, $3}')
|
||||
|
||||
gesamt="$(hub wg show wg0 transfer | grep -c . || echo 0)"
|
||||
|
||||
if [[ "${stumm:-0}" -gt 0 ]]; then
|
||||
warn "$stumm von $gesamt Zugängen haben noch NIE etwas geschickt."
|
||||
log "Gemerkte UDP-Ströme wegräumen"
|
||||
if sudo -n conntrack -D -p udp --dport "$WG_PORT" >/dev/null 2>&1; then
|
||||
ok "erledigt — die Zugänge bauen sich in den nächsten 30 Sekunden neu auf"
|
||||
else
|
||||
bad "Dafür fehlt mir Root. Bitte einmal von Hand ausführen:"
|
||||
echo
|
||||
echo " sudo conntrack -D -p udp --dport $WG_PORT"
|
||||
echo
|
||||
warn "Damit ich das künftig selbst darf, siehe docs/runbooks/tunnel-recovery.md,"
|
||||
warn "Abschnitt 'Einmal einrichten'."
|
||||
fi
|
||||
else
|
||||
ok "Alle Zugänge haben schon Daten geschickt"
|
||||
fi
|
||||
|
||||
# ── 4. Der Stand, zum Mitlesen ───────────────────────────────────────────────
|
||||
log "Stand jetzt"
|
||||
hub wg show wg0 || true
|
||||
|
||||
echo
|
||||
log "Wenn ein HOST weiter fehlt, während andere Zugänge stehen"
|
||||
echo " Dann liegt es auf der Maschine, nicht hier. Über die Konsole des"
|
||||
echo " Anbieters (SSH ist von aussen zu, das ist Absicht):"
|
||||
echo
|
||||
echo " systemctl status wg-quick@wg0"
|
||||
echo " systemctl restart wg-quick@wg0"
|
||||
echo
|
||||
echo " Kommt man dort nicht weit genug, macht dieses Skript auf dem Host SSH"
|
||||
echo " wieder auf — und muss danach zurückgenommen werden:"
|
||||
echo
|
||||
echo " /usr/local/sbin/clupilot-emergency-open-firewall.sh"
|
||||
echo
|
||||
Loading…
Reference in New Issue