#!/bin/bash # monwatch — внешний сторож мониторинга fr1 («кто сторожит сторожа»). # Весь мониторинг (Prometheus, Alertmanager → Telegram) живёт на fr1: если упадёт fr1 или сломается # цепочка доставки, никаких алертов не будет вообще. Раз в час малина спрашивает fr1 `health` # (тот же ограниченный ключ метрик, режим только чтение) и при проблеме пишет в Telegram # НАПРЯМУЮ — через своего бота (@rasp_contol_bot, токен из /etc/astra-bot.env), минуя fr1. # # Тревога — при поломке, повтор раз в 6 ч, ✅ при восстановлении. Разовый сбой сети # не тревожит: перед тревогой одна повторная проверка через 2 минуты. set -uo pipefail STATE=/var/lib/monwatch; mkdir -p "$STATE" CHAT=${MONWATCH_CHAT:-607015} REPEAT=$((6 * 3600)) MAX_PUSH_AGE=${MONWATCH_MAX_PUSH_AGE:-3600} # smart-metrics пушит каждые 15 мин health() { timeout 60 ssh -i /etc/metrics-push/id_ed25519 -o UserKnownHostsFile=/etc/metrics-push/known_hosts \ -o StrictHostKeyChecking=yes -o BatchMode=yes -o ConnectTimeout=20 rus@161.97.93.252 health 2>&1 } check() { # печатает проблемы по строке; пусто = всё хорошо local out rc out=$(health); rc=$? if [ $rc -ne 0 ] || ! grep -q '^prometheus_healthy=' <<< "$out"; then echo "fr1 не отвечает на проверку (ssh rc=$rc): $(tail -1 <<< "$out")"; return fi declare -A v; while IFS='=' read -r k val; do v[$k]=$val; done <<< "$out" [ "${v[prometheus_healthy]}" = 200 ] || echo "Prometheus не отвечает (HTTP ${v[prometheus_healthy]})" [ "${v[alertmanager_healthy]}" = 200 ] || echo "Alertmanager не отвечает (HTTP ${v[alertmanager_healthy]}) — алерты не доставляются" [ "${v[pushgateway_healthy]}" = 200 ] || echo "Pushgateway не отвечает (HTTP ${v[pushgateway_healthy]})" local age=${v[push_age_seconds]:--1} if [ "$age" -lt 0 ] || [ "$age" -gt $MAX_PUSH_AGE ]; then echo "Prometheus не видит свежих метрик малины ($([ "$age" -lt 0 ] && echo 'нет данных' || echo "$((age / 60)) мин"))" fi local failed=${v[tg_notifications_failed_total]:-0} prev prev=$(cat "$STATE/tg_failed" 2>/dev/null || echo "$failed") [ "$failed" -gt "$prev" ] && echo "Alertmanager не смог отправить в Telegram $((failed - prev)) уведомл. за последний час" echo "$failed" > "$STATE/tg_failed" } tg() { local token token=$(sed -n 's/^TG_TOKEN=//p' /etc/astra-bot.env) curl -s -o /dev/null -w '%{http_code}' --max-time 30 "https://api.telegram.org/bot$token/sendMessage" \ --data-urlencode "chat_id=$CHAT" --data-urlencode "text=$1" | grep -q 200 || echo "не удалось отправить в Telegram" >&2 } problems=$(check) if [ -n "$problems" ]; then sleep 120; problems=$(check) # повторная проверка: не тревожим из-за разового сбоя сети fi now=$(date +%s); state=$(cat "$STATE/state" 2>/dev/null || echo up); last=$(cat "$STATE/last_alert" 2>/dev/null || echo 0) if [ -n "$problems" ]; then echo "DOWN: $problems" if [ "$state" != down ] || [ $((now - last)) -ge $REPEAT ]; then tg "🔴 Мониторинг fr1 сломан — алерты от него могут не приходить. $problems (сторож на rpi, проверка раз в час; повтор через 6 ч)" && echo "$now" > "$STATE/last_alert" fi echo down > "$STATE/state" exit 1 fi echo "OK: мониторинг fr1 в порядке" [ "$state" = down ] && tg "✅ Мониторинг fr1 снова в порядке (сторож на rpi)." echo up > "$STATE/state"