Files
knowledge-base/snippets/niikn-podkop/niikn-podkop-watchdog.sh

70 lines
4.7 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# niikn-podkop-watchdog.sh — внешний сторож обхода НИИКН (OpenWrt 192.168.1.50). На LXC137, cron */5.
# Роутер лечится сам (podkop-selfcheck cron + boot-self-heal). Этот сторож делает ПРОБУ с позиции клиента
# (netns-probe на роутере) и АЛЕРТИТ Олегу + эскалирует (heal→reboot) с гистерезисом, если не лечится.
# Алертит отсюда, т.к. на коробке за обходом TG недостижим при сломанном обходе. Образец: benelux-podkop-watchdog.sh
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ROUTER=192.168.1.50
SSH="sshpass -p 1qaz!QAZ ssh -o StrictHostKeyChecking=no -o ConnectTimeout=8 root@$ROUTER"
CFG=/root/.openclaw/openclaw.json
CHAT=1292155421
STATE=/root/.niikn-pk-wd.state
ALERT=/root/.niikn-pk-wd.alert
REBOOTS=/root/.niikn-pk-wd.reboots
COOLDOWN=/run/niikn-pk-wd.cooldown
COOLDOWN_SEC=300
REBOOT_CAP=2
TOKEN=$(grep -oE '[0-9]{8,}:[A-Za-z0-9_-]{30,}' "$CFG" 2>/dev/null | head -1)
send(){
[ -n "$TOKEN" ] && curl -s --max-time 20 "https://api.telegram.org/bot${TOKEN}/sendMessage" \
--data-urlencode "chat_id=$CHAT" --data-urlencode "text=$1" >/dev/null 2>&1
[ -f /root/.wd-mail.env ] && . /root/.wd-mail.env
if [ -n "${MAILTO:-}" ]; then
printf 'From: dttb watchdog <%s>\nTo: %s\nSubject: %s\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit\nDate: %s\n\n%s\n' \
"$SMTPUSER" "$MAILTO" "[NIIKN podkop] watchdog" "$(date -R)" "$1" > /tmp/.niiknwd.eml
curl -s --max-time 25 --url "smtp://${MAILHOST}:587" --ssl-reqd --resolve "${MAILHOST}:587:${MAILIP}" \
--mail-from "$SMTPUSER" --mail-rcpt "$MAILTO" --user "${SMTPUSER}:${SMTPPASS}" --upload-file /tmp/.niiknwd.eml >/dev/null 2>&1
fi
}
NOW=$(date +%s); TODAY=$(date +%F)
# роутер/проба достижимы?
if ! $SSH 'test -x /usr/local/bin/podkop-probe.sh' 2>/dev/null; then
if ping -c2 -W2 "$ROUTER" >/dev/null 2>&1; then iss="• OpenWrt НИИКН пингуется, но SSH/probe недоступен (NetBird/dropbear?).\n"
else iss="• OpenWrt НИИКН ($ROUTER) недоступен (ни ping, ни SSH) — туннель/роутер/VM лёг.\n"; fi
h=$(printf '%s' "$iss" | md5sum | cut -d' ' -f1)
[ "$(cat "$ALERT" 2>/dev/null)" = "$h" ] && exit 0
echo "$h" > "$ALERT"; send "$(printf '⚠️ Обход НИИКН:\n%b' "$iss")"; echo "UNREACHABLE"; exit 0
fi
$SSH '/usr/local/bin/podkop-probe.sh' 2>/dev/null; rc=$?
if [ "$rc" = "0" ]; then
rm -f "$STATE"
if [ -f "$ALERT" ]; then send "✅ Обход НИИКН снова работает (проба с клиента OK)."; rm -f "$ALERT"; fi
echo "OK: обход НИИКН здоров (проба с клиента)."; exit 0
fi
[ "$rc" = "2" ] && { echo "infra (DNS/netns) — не лечим podkop"; exit 0; }
# rc=1 — сломан. Гистерезис: даём роутеру шанс полечиться самому (selfcheck) до 2 провалов.
FAILS=0; STEP=0; [ -f "$STATE" ] && read -r FAILS STEP < "$STATE"; FAILS=$((${FAILS:-0}+1))
if [ "$FAILS" -lt 2 ]; then echo "$FAILS $STEP" > "$STATE"; echo "DEGRADED $FAILS/2 (жду самолечения роутера)"; exit 0; fi
if [ -f "$COOLDOWN" ] && [ $((NOW-$(cat "$COOLDOWN" 2>/dev/null||echo 0))) -lt "$COOLDOWN_SEC" ]; then echo "$FAILS $STEP" > "$STATE"; echo cooldown; exit 0; fi
iss="• Обход НИИКН сломан с позиции клиента ($FAILS проб подряд, роутер сам не вылечил).\n"; heal=""
case "$STEP" in
0) $SSH '/usr/local/bin/podkop-heal.sh' >/dev/null 2>&1
heal="🔧 Шаг1: принудительный heal (restart podkop + cache + dnsmasq).\n"; STEP=1; echo "$NOW" > "$COOLDOWN" ;;
1) RDAY=""; RCNT=0; [ -f "$REBOOTS" ] && read -r RDAY RCNT < "$REBOOTS"; [ "$RDAY" != "$TODAY" ] && { RDAY=$TODAY; RCNT=0; }
if [ "${RCNT:-0}" -lt "$REBOOT_CAP" ]; then
$SSH 'reboot' >/dev/null 2>&1; echo "$TODAY $((RCNT+1))" > "$REBOOTS"
heal="🔧 Шаг2: heal не помог → перезагружаю роутер (ребут $((RCNT+1))/$REBOOT_CAP сегодня).\n"; STEP=2; echo "$NOW" > "$COOLDOWN"
else iss="${iss}• Лимит ребутов на сегодня исчерпан.\n"; STEP=2; fi ;;
*) iss="${iss}• Автолечение не помогло (все шаги пройдены) — нужно руками.\n" ;;
esac
echo "$FAILS $STEP" > "$STATE"
h=$(printf '%s%s' "$iss" "$heal" | md5sum | cut -d' ' -f1)
[ "$(cat "$ALERT" 2>/dev/null)" = "$h" ] && exit 0
echo "$h" > "$ALERT"
send "$(printf '⚠️ Обход НИИКН — сбой:\n%b\n%b' "$iss" "$heal")"