Files
edgeguard-native/packaging/scripts/keepalived-master.sh
Debian 09e6e0c4f7 fix(keepalived): notify_master ermittelt PG-Rolle über Publication statt Datei — v1.3.10
keepalived-master.sh loggte beim VIP-Übernehmen "PG-Rolle ist noch 'standby'",
weil es /var/lib/edgeguard/pg_role las — die schreibt nur `promote`, ein via
cluster-init-replication eingerichteter Primary hat sie nie → falsches Label.
Jetzt zuverlässig über pg_publication (nur der Primary trägt edgeguard_shared,
Konvention wie cluster_repair.go): Primary → "bereits PG-Primary (kein promote
nötig)", sonst → "standby, edgeguard-ctl promote". Rein kosmetisch/Logging.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-31 19:06:05 +02:00

54 lines
3.1 KiB
Bash

#!/bin/bash
# Keepalived notify_master: dieser Node hat die VIP übernommen.
#
# KEIN Auto-Promote — Split-Brain-Schutz durch manuelle Promotion.
# Admin muss "edgeguard-ctl promote" ausführen wenn PG-Failover gewünscht.
# PG-Rolle ZUVERLÄSSIG über die Publication ermitteln — nicht über die evtl.
# veraltete/fehlende Datei /var/lib/edgeguard/pg_role (die schrieb nur `promote`;
# ein via cluster-init-replication eingerichteter Primary hat sie nie → Log sagte
# fälschlich "standby"). Nur der Primary trägt die Publication edgeguard_shared
# (Konvention, vgl. cluster_repair.go). Best-effort: bei psql-Fehler neutral.
if sudo -u postgres psql -d edgeguard -tAc \
"SELECT EXISTS(SELECT 1 FROM pg_publication WHERE pubname='edgeguard_shared')" \
2>/dev/null | grep -q '^t$'; then
logger -t keepalived -p daemon.warning \
"MASTER: VIP übernommen — dieser Node ist bereits PG-Primary (kein promote nötig)."
else
logger -t keepalived -p daemon.warning \
"MASTER: VIP übernommen — PG-Rolle ist 'standby'. Für PG-Failover: edgeguard-ctl promote"
fi
# ── Upstream-ARP/Routing für die Failover-VIP(s) aktualisieren ──
# Manche Hoster lernen die neue MAC einer Failover-IP NICHT zuverlässig über
# Gratuitous-ARP, sondern erst, wenn sie Traffic VON der IP sehen. Ohne das ist
# die VIP nach einem Schwenk von außen unerreichbar. Wir pingen daher den
# Default-Gateway aus jeder Public-IP (inkl. VIP) an (source via -I), damit der
# Upstream die MAC sofort umlernt. Hintergrund-Pings, damit notify nicht blockt.
WAN_DEV="$(ip -4 route show default 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev"){print $(i+1); exit}}')"
WAN_GW="$(ip -4 route show default 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="via"){print $(i+1); exit}}')"
if [ -n "$WAN_DEV" ] && [ -n "$WAN_GW" ]; then
for vip in $(ip -4 -o addr show dev "$WAN_DEV" scope global 2>/dev/null | awk '{print $4}' | cut -d/ -f1); do
ping -I "$vip" -c 3 -W 1 "$WAN_GW" >/dev/null 2>&1 &
done
logger -t keepalived -p daemon.info "MASTER: Upstream-ARP via Ping aus VIP(s) auf $WAN_GW ($WAN_DEV) angestoßen"
fi
# Dienste reloaden/starten damit sie die neu aktiven VIPs binden.
# Squid + Unbound + HAProxy binden beim Start an spezifische IPs — war der Dienst
# während des BACKUP-Zustands gecrasht oder gestoppt, muss er gestartet werden.
for svc in squid.service unbound.service haproxy.service; do
if systemctl is-active --quiet "$svc"; then
systemctl reload "$svc" 2>/dev/null || systemctl restart "$svc" 2>/dev/null || true
else
systemctl start "$svc" 2>/dev/null || true
fi
done
logger -t keepalived -p daemon.info "MASTER: squid/unbound/haproxy reload-or-start nach VIP-Übernahme"
# Alert an die API schicken (best-effort, ignoriert Fehler)
curl -sf --max-time 3 -X POST \
-H "Content-Type: application/json" \
-d '{"level":"warning","message":"Keepalived MASTER: VIP übernommen. Wenn PG-Failover gewünscht: edgeguard-ctl promote ausführen.","source":"keepalived"}' \
http://127.0.0.1:9443/api/v1/internal/alert > /dev/null 2>&1 || true