70 lines
4.7 KiB
Bash
70 lines
4.7 KiB
Bash
#!/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")"
|