Backup automatico script del 2026-07-19 07:00
This commit is contained in:
@@ -4,49 +4,35 @@
|
||||
# 🔍 SUPER WATCHDOG DI RETE (Gira su Pi-2)
|
||||
# ================================================
|
||||
|
||||
# --- CONFIGURAZIONE TELEGRAM ---
|
||||
# Legge il token dal file sicuro invece che averlo in chiaro
|
||||
TOKEN_FILE="/etc/telegram_dpc_bot_token"
|
||||
LOOGLE_NOTIFY="/home/daniely/docker/loogle-casa/scripts/loogle-notify.sh"
|
||||
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
# Legge il file e rimuove spazi o 'a capo' accidentali
|
||||
BOT_TOKEN=$(cat "$TOKEN_FILE" | tr -d '\n' | tr -d '\r')
|
||||
else
|
||||
echo "ERRORE CRITICO: Token file non trovato in $TOKEN_FILE"
|
||||
if [[ ! -x "$LOOGLE_NOTIFY" ]]; then
|
||||
echo "ERRORE: loogle-notify non disponibile ($LOOGLE_NOTIFY)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CHAT_ID="64463169"
|
||||
# 👆👆 FINE MODIFICHE 👆👆
|
||||
|
||||
# Cartella dove salvare lo stato di ogni dispositivo
|
||||
STATE_DIR="/tmp/watchdog_states"
|
||||
mkdir -p "$STATE_DIR"
|
||||
|
||||
# --- LISTA DEI BERSAGLI ---
|
||||
# Formato: "Nome Amichevole|Indirizzo IP"
|
||||
# Usa icone diverse per capire subito la gravità.
|
||||
# Riavvio giornaliero AP WiFi: silenzio allarmi per REBOOT_GRACE_MIN minuti
|
||||
# dall'orario programmato. Se ancora DOWN dopo la finestra → allarme.
|
||||
REBOOT_GRACE_MIN=5
|
||||
|
||||
TARGETS=(
|
||||
# CRITICI 🚨
|
||||
"🍓 Pi-1 (Master)|192.168.128.80"
|
||||
"🗄️ NAS DS920+|192.168.128.100"
|
||||
"🌍 Internet (Google)|8.8.8.8"
|
||||
"📡 Router Main|192.168.128.1"
|
||||
|
||||
# INFRASTRUTTURA 🔌
|
||||
"🗄️ NAS DS214|192.168.128.90"
|
||||
"🔌 Switch Sala (.105)|192.168.128.105"
|
||||
"🔌 Switch Taverna (.106)|192.168.128.106"
|
||||
"🔌 Switch Lavanderia (.107)|192.168.128.107"
|
||||
|
||||
# WIFI 📶
|
||||
"📶 WiFi Sala (.101)|192.168.128.101"
|
||||
"📶 WiFi Luca (.102)|192.168.128.102"
|
||||
"📶 WiFi Taverna (.103)|192.168.128.103"
|
||||
"📶 WiFi Dado (.104)|192.168.128.104"
|
||||
"📶 WiFi Esterno (.108)|192.168.128.108"
|
||||
|
||||
# CAMERE 📷 (Sottorete .135)
|
||||
"📶 WiFi Pozzo (.109)|192.168.128.109"
|
||||
"📷 Cam Matrimoniale|192.168.135.2"
|
||||
"📷 Cam Luca|192.168.135.3"
|
||||
"📷 Cam Ingresso|192.168.135.4"
|
||||
@@ -55,62 +41,98 @@ TARGETS=(
|
||||
"📷 Cam Retro|192.168.135.7"
|
||||
)
|
||||
|
||||
# Funzione per inviare messaggi Telegram
|
||||
send_telegram() {
|
||||
MSG="$1"
|
||||
# Usa un timeout breve per curl per non bloccare lo script se Telegram non va
|
||||
curl -s --max-time 5 -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" -d chat_id="$CHAT_ID" -d text="$MSG" -d parse_mode="Markdown" > /dev/null 2>&1
|
||||
send_alert() {
|
||||
local title="$1"
|
||||
local body="$2"
|
||||
local severity="$3"
|
||||
"$LOOGLE_NOTIFY" --title "$title" --body "$body" --category super_watchdog \
|
||||
--severity "$severity" &
|
||||
}
|
||||
|
||||
# ================================================
|
||||
# CICLO DI CONTROLLO PRINCIPALE
|
||||
# ================================================
|
||||
# Restituisce i minuti da mezzanotte dell'inizio riavvio (o vuoto se non programmato).
|
||||
# 04:00 → Dado (.104), Sala (.101)
|
||||
# 04:30 → Luca (.102), Taverna (.103)
|
||||
# 14:00 → Esterno (.108), Pozzo (.109)
|
||||
wifi_reboot_start_min() {
|
||||
case "$1" in
|
||||
192.168.128.101|192.168.128.104) echo 240 ;; # 04:00
|
||||
192.168.128.102|192.168.128.103) echo 270 ;; # 04:30
|
||||
192.168.128.108|192.168.128.109) echo 840 ;; # 14:00
|
||||
*) echo "" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 0 se siamo nella finestra [start, start+grace) del riavvio programmato.
|
||||
in_wifi_reboot_window() {
|
||||
local start
|
||||
start=$(wifi_reboot_start_min "$1")
|
||||
[[ -n "$start" ]] || return 1
|
||||
local now_min=$((10#$(date +%H) * 60 + 10#$(date +%M)))
|
||||
local end=$((start + REBOOT_GRACE_MIN))
|
||||
[[ $now_min -ge $start && $now_min -lt $end ]]
|
||||
}
|
||||
|
||||
echo "--- Inizio controllo $(date) ---"
|
||||
|
||||
# Loop attraverso ogni dispositivo nella lista
|
||||
for target_line in "${TARGETS[@]}"; do
|
||||
# Estrai Nome e IP separati dal simbolo "|"
|
||||
NAME=$(echo "$target_line" | cut -d'|' -f1)
|
||||
IP=$(echo "$target_line" | cut -d'|' -f2)
|
||||
|
||||
# Crea un nome file sicuro per lo stato usando l'IP (es. 192_168_1_1.state)
|
||||
SAFE_IP="${IP//./_}"
|
||||
STATE_FILE="$STATE_DIR/${SAFE_IP}.state"
|
||||
|
||||
# Leggi lo stato precedente (default UP se non esiste)
|
||||
if [ -f "$STATE_FILE" ]; then
|
||||
LAST_STATE=$(cat "$STATE_FILE")
|
||||
else
|
||||
LAST_STATE="UP"
|
||||
echo "UP" > "$STATE_FILE" # Inizializza
|
||||
echo "UP" > "$STATE_FILE"
|
||||
fi
|
||||
|
||||
# --- IL PING ---
|
||||
# Tenta 2 ping, con timeout di 1 secondo l'uno.
|
||||
# È un controllo rapido. Se fallisce 2 volte di fila, è giù.
|
||||
ping -c 2 -W 1 "$IP" > /dev/null 2>&1
|
||||
PING_RESULT=$? # 0 = Successo, altro = Fallimento
|
||||
PING_RESULT=$?
|
||||
|
||||
if [ $PING_RESULT -eq 0 ]; then
|
||||
# === ORA È ONLINE ===
|
||||
if [ "$LAST_STATE" == "DOWN" ]; then
|
||||
# Era giù, ora è su: NOTIFICA DI RISOLUZIONE
|
||||
send_telegram "✅ **RISOLTO: $NAME è tornato ONLINE!**%0AIP: \`$IP\`"
|
||||
send_alert \
|
||||
"Dispositivo online" \
|
||||
"RISOLTO: $NAME è tornato ONLINE! IP: $IP" \
|
||||
"info"
|
||||
echo "UP" > "$STATE_FILE"
|
||||
echo "--> $NAME tornato UP. Notifica inviata."
|
||||
elif [ "$LAST_STATE" == "REBOOT_DOWN" ]; then
|
||||
# Ripristino dopo riavvio programmato: nessun allarme off/on
|
||||
echo "UP" > "$STATE_FILE"
|
||||
echo "--> $NAME tornato UP dopo riavvio programmato. Nessuna notifica."
|
||||
fi
|
||||
else
|
||||
# === ORA È OFFLINE ===
|
||||
if [ "$LAST_STATE" == "UP" ]; then
|
||||
# Era su, ora è giù: NOTIFICA DI ALLARME
|
||||
# Scegli l'icona in base al tipo di dispositivo per l'allarme
|
||||
ICON="⚠️"
|
||||
if [[ "$NAME" == *"🚨"* || "$NAME" == *"🌍"* ]]; then ICON="🚨 CRITICO:"; fi
|
||||
if in_wifi_reboot_window "$IP"; then
|
||||
echo "REBOOT_DOWN" > "$STATE_FILE"
|
||||
echo "--> $NAME DOWN in finestra riavvio programmato. Silenzio."
|
||||
else
|
||||
ICON="⚠️"
|
||||
if [[ "$NAME" == *"🚨"* || "$NAME" == *"🌍"* ]]; then ICON="🚨 CRITICO:"; fi
|
||||
|
||||
send_telegram "$ICON **ALLARME: $NAME è OFFLINE!**%0AIP: \`$IP\` non risponde."
|
||||
echo "DOWN" > "$STATE_FILE"
|
||||
echo "--> $NAME andato DOWN. Notifica inviata."
|
||||
send_alert \
|
||||
"Dispositivo offline" \
|
||||
"$ICON ALLARME: $NAME è OFFLINE! IP: $IP non risponde." \
|
||||
"warning"
|
||||
echo "DOWN" > "$STATE_FILE"
|
||||
echo "--> $NAME andato DOWN. Notifica inviata."
|
||||
fi
|
||||
elif [ "$LAST_STATE" == "REBOOT_DOWN" ]; then
|
||||
if in_wifi_reboot_window "$IP"; then
|
||||
echo "$NAME ancora DOWN in finestra riavvio. Silenzio."
|
||||
else
|
||||
# Oltre i 5 minuti dal riavvio programmato: allarme reale
|
||||
ICON="⚠️"
|
||||
send_alert \
|
||||
"Dispositivo offline" \
|
||||
"$ICON ALLARME: $NAME è OFFLINE oltre il riavvio programmato! IP: $IP non risponde." \
|
||||
"warning"
|
||||
echo "DOWN" > "$STATE_FILE"
|
||||
echo "--> $NAME ancora DOWN dopo finestra riavvio. Notifica inviata."
|
||||
fi
|
||||
else
|
||||
echo "$NAME ancora DOWN. Nessuna notifica."
|
||||
fi
|
||||
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ================================================
|
||||
# SENTINELLA DI BACKUP (Gira su Pi-1 Master)
|
||||
# Controlla Pi-2 e attiva failover bundle IoT su Pi-1 se down.
|
||||
# ================================================
|
||||
|
||||
LOOGLE_NOTIFY="/home/daniely/docker/loogle-casa/scripts/loogle-notify.sh"
|
||||
HA_FAILOVER="/home/daniely/rete/scripts/ha-failover.sh"
|
||||
|
||||
if [[ ! -x "$LOOGLE_NOTIFY" ]]; then
|
||||
echo "Errore: loogle-notify non disponibile ($LOOGLE_NOTIFY)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET_IP="192.168.128.81"
|
||||
TARGET_NAME="🍓 Pi-2 (Backup & Monitor)"
|
||||
STATE_FILE="/mnt/ha-apps/.metadata/pi2-watchdog.state"
|
||||
SIM_STATE="/mnt/ha-apps/.metadata/failover-sim.state"
|
||||
LEGACY_STATE_FILE="/tmp/pi2_watchdog.state"
|
||||
SSH_OPTS=(-o ConnectTimeout=5 -o BatchMode=yes -o StrictHostKeyChecking=accept-new)
|
||||
|
||||
if [[ -f "$SIM_STATE" ]] && [[ "$(cat "$SIM_STATE" 2>/dev/null)" != "none" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
send_alert() {
|
||||
local title="$1"
|
||||
local body="$2"
|
||||
local severity="$3"
|
||||
"$LOOGLE_NOTIFY" --title "$title" --body "$body" --category watchdog_pi2 \
|
||||
--severity "$severity" &
|
||||
}
|
||||
|
||||
pi2_reachable() {
|
||||
ping -c 3 -W 2 "$TARGET_IP" > /dev/null 2>&1 && return 0
|
||||
ssh "${SSH_OPTS[@]}" pi2 "exit 0" 2>/dev/null
|
||||
}
|
||||
|
||||
if [ ! -f "$STATE_FILE" ]; then
|
||||
if [ -f "$LEGACY_STATE_FILE" ]; then
|
||||
cp "$LEGACY_STATE_FILE" "$STATE_FILE"
|
||||
else
|
||||
echo "UP" > "$STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
LAST_STATE=$(cat "$STATE_FILE")
|
||||
|
||||
if pi2_reachable; then
|
||||
if [ "$LAST_STATE" == "DOWN" ]; then
|
||||
send_alert \
|
||||
"Pi-2 online" \
|
||||
"RISOLTO: $TARGET_NAME è tornato ONLINE! Failback bundle IoT in corso." \
|
||||
"info"
|
||||
echo "UP" > "$STATE_FILE"
|
||||
if [[ -x "$HA_FAILOVER" ]]; then
|
||||
sudo bash -c "\"$HA_FAILOVER\" stop-iot-bundle >> /var/log/ha-failover.log 2>&1 &"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ "$LAST_STATE" == "UP" ]; then
|
||||
send_alert \
|
||||
"Pi-2 offline" \
|
||||
"ALLARME: $TARGET_NAME è OFFLINE! Avvio failover bundle IoT su Pi-1." \
|
||||
"warning"
|
||||
echo "DOWN" > "$STATE_FILE"
|
||||
if [[ -x "$HA_FAILOVER" ]]; then
|
||||
sudo bash -c "\"$HA_FAILOVER\" start-iot-bundle >> /var/log/ha-failover.log 2>&1 &"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# PATH completo: il crontab root non eredita /usr/sbin (serve per shutdown, ecc.)
|
||||
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
CONF_FILE="/etc/weekly-maintenance.conf"
|
||||
LOG_FILE="/var/log/weekly-maintenance.log"
|
||||
REPORT_FILE="/var/log/weekly-maintenance-report.txt"
|
||||
@@ -165,7 +168,7 @@ run_watchtower() {
|
||||
output=$(docker run --rm \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-e WATCHTOWER_CLEANUP=true \
|
||||
-e WATCHTOWER_ROLLING_RESTART=true \
|
||||
-e WATCHTOWER_ROLLING_RESTART=false \
|
||||
-e WATCHTOWER_TIMEOUT="${WATCHTOWER_TIMEOUT}" \
|
||||
-e TZ=Europe/Rome \
|
||||
"$WATCHTOWER_IMAGE" \
|
||||
@@ -439,7 +442,7 @@ if [[ "$REBOOT_ON_SUCCESS" == true ]]; then
|
||||
append_report ""
|
||||
append_report "=== Reboot ==="
|
||||
append_report "Programmato tra ${REBOOT_DELAY_MIN} minuti"
|
||||
shutdown -r "+${REBOOT_DELAY_MIN}" "Manutenzione settimanale ${HOST_LABEL}" || {
|
||||
/usr/sbin/shutdown -r "+${REBOOT_DELAY_MIN}" "Manutenzione settimanale ${HOST_LABEL}" || {
|
||||
ERRORS+=("shutdown -r (reboot programmato)")
|
||||
log "✗ Impossibile programmare il reboot"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user