adsb-1090/check_adsb_mistral_v5_ByClaude.sh

282 lines
15 KiB
Bash
Executable File

#!/bin/bash
# =============================================
# Script de vérification complète de la stack ADS-B
# Version : 9.0 (Corrigé par Claude)
# Date : 26/06/2026
# Auteur : JC Abiven
# =============================================
if ! command -v jq &> /dev/null; then
echo -e "\033[0;31m✗ jq n'est pas installé : sudo apt install jq\033[0m"
exit 1
fi
GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; MAGENTA='\033[0;35m'; CYAN='\033[0;36m'; NC='\033[0m'
ok() { echo -e "${GREEN}${NC} $1"; }
fail() { echo -e "${RED}${NC} $1"; ERRORS=$((ERRORS+1)); }
warn() { echo -e "${YELLOW}${NC} $1"; WARNS=$((WARNS+1)); }
info() { echo -e "${CYAN}${NC} $1"; }
sec() { echo -e "\n${CYAN}═══ $1 ═══${NC}"; }
ERRORS=0; WARNS=0
HOST_IP=$(ip -4 addr show wlp58s0 2>/dev/null | grep -oP '(?<=inet )\d+\.\d+\.\d+\.\d+' | head -1)
[ -z "$HOST_IP" ] && HOST_IP=$(hostname -I | awk '{print $1}')
echo -e "${MAGENTA}╔══════════════════════════════════════════════════════╗"
echo -e "║ Stack ADS-B Linux-25 — Vérification complète ║"
echo -e "$(date '+%a %d/%m/%Y %H:%M:%S')"
echo -e "╚══════════════════════════════════════════════════════╝${NC}"
info "IP détectée : $HOST_IP"
# ── 1. Conteneurs ─────────────────────────────────────────────────────────────
sec "1. Conteneurs Docker"
for ctn in adsb-readsb adsb-tar1090 adsb-adsb2pg adsb-webapp wordpress-postgres; do
STATUS=$(docker inspect --format '{{.State.Status}}' "$ctn" 2>/dev/null)
HEALTH=$(docker inspect --format '{{.State.Health.Status}}' "$ctn" 2>/dev/null)
UPTIME=$(docker inspect --format '{{.State.StartedAt}}' "$ctn" 2>/dev/null | \
xargs -I{} date -d {} '+%d/%m %H:%M' 2>/dev/null)
if [ "$STATUS" = "running" ]; then
LABEL="$ctn"
[ "$HEALTH" = "healthy" ] && LABEL="$ctn [healthy]"
[ "$HEALTH" = "unhealthy" ] && LABEL="$ctn [unhealthy]" && WARNS=$((WARNS+1))
[ "$HEALTH" = "unhealthy" ] \
&& warn "$LABEL — démarré $UPTIME" \
|| ok "$LABEL — démarré $UPTIME"
else
fail "$ctn — STATUS=${STATUS:-absent}"
fi
done
# ── 2. Dongle RTL-SDR ─────────────────────────────────────────────────────────
sec "2. Dongle RTL-SDR"
if docker logs adsb-readsb 2>&1 | grep -q "SN 00000010"; then
# BUG CORRIGÉ : grep -oP avec lookbehind correct
GAIN=$(docker logs adsb-readsb 2>&1 | grep "tuner gain set to" | tail -1 \
| grep -oP '[\d.]+(?= dB)')
ok "AirNav FlightStick SN:00000010 détecté — gain ${GAIN:-?} dB"
else
fail "Dongle SN:00000010 non détecté"
fi
[ -L "/dev/adsb_dongle" ] && ok "Symlink /dev/adsb_dongle présent" \
|| warn "Symlink /dev/adsb_dongle introuvable"
# ── 3. Données ADS-B ──────────────────────────────────────────────────────────
sec "3. Données ADS-B"
AC_JSON=$(curl -s --max-time 5 "http://127.0.0.1:8090/data/aircraft.json" 2>/dev/null)
if [ -n "$AC_JSON" ]; then
# BUG CORRIGÉ : utiliser .aircraft[] et pas .[] (qui itère aussi sur messages/now)
MSGS=$(echo "$AC_JSON" | jq -r '.messages // 0')
AVIONS=$(echo "$AC_JSON" | jq '[.aircraft // []] | length')
WITH_POS=$(echo "$AC_JSON" | jq '[.aircraft[]? | select(.lat != null and .lon != null)] | length')
[ "${MSGS:-0}" -gt 0 ] \
&& ok "tar1090 actif — $(printf '%d' "$MSGS") messages décodés" \
|| warn "tar1090 répond — 0 message (démarrage récent ?)"
ok "$AVIONS avion(s) en vue dont $WITH_POS avec position GPS"
else
fail "tar1090 ne répond pas sur :8090/data/aircraft.json"
AVIONS=0; WITH_POS=0; MSGS=0
fi
# BUG CORRIGÉ : vérifier via docker exec (le volume tmpfs n'est pas accessible hôte)
if docker exec adsb-readsb test -f /run/readsb/aircraft.pb 2>/dev/null; then
ok "Volume readsb-run : aircraft.pb présent dans le conteneur readsb"
elif docker exec adsb-tar1090 test -f /run/readsb/aircraft.pb 2>/dev/null; then
ok "Volume readsb-run : aircraft.pb présent dans le conteneur tar1090"
else
warn "aircraft.pb introuvable dans les conteneurs"
fi
# ── 4. Ports réseau ───────────────────────────────────────────────────────────
sec "4. Ports réseau"
declare -A PORT_LABELS=(
["8080"]="webapp PHP" ["8090"]="tar1090 nginx"
["30005"]="Beast TCP" ["5432"]="PostgreSQL"
["30002"]="RAW TCP" ["30003"]="SBS TCP"
)
for port in 8080 8090 30005 5432 30002 30003; do
LISTEN=$(ss -tlnp 2>/dev/null | grep ":${port}[[:space:]]" | awk '{print $4}' | head -1)
if [ -n "$LISTEN" ]; then
ok "Port $port en écoute sur $LISTEN${PORT_LABELS[$port]}"
else
fail "Port $port absent — ${PORT_LABELS[$port]}"
fi
done
# Connexion Beast via gateway adsb-net
READSB_IP=$(docker inspect adsb-readsb 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)[0]
for n,v in d['NetworkSettings']['Networks'].items():
if 'adsb' in n: print(v['IPAddress'])" 2>/dev/null)
if [ -n "$READSB_IP" ] && [ "$READSB_IP" != "None" ]; then
ok "readsb attaché à adsb-net : $READSB_IP (gateway 172.20.0.1)"
else
fail "readsb non attaché à adsb-net — Beast TCP impossible"
fi
# ── 5. PostgreSQL ─────────────────────────────────────────────────────────────
sec "5. PostgreSQL — schéma adsb"
PG="docker exec wordpress-postgres psql -U pgz_admin -d wpz_postgres -t -c"
PG_VER=$($PG "SELECT version();" 2>/dev/null | head -1 | sed 's/ */ /g' | xargs)
if [ -n "$PG_VER" ]; then
ok "PostgreSQL accessible"
info "${PG_VER:0:70}"
else
fail "PostgreSQL inaccessible"
fi
# BUG CORRIGÉ : pg_tables plutôt que pg_class pour les partitions feuilles
PART_POS=$($PG "SELECT COUNT(*) FROM pg_tables
WHERE schemaname='adsb' AND tablename LIKE 'positions_%';" 2>/dev/null | xargs)
ok "${PART_POS:-0} sous-partitions adsb.positions"
PART_HIS=$($PG "SELECT COUNT(*) FROM pg_tables
WHERE schemaname='adsb' AND tablename LIKE 'aircraft_history_%';" 2>/dev/null | xargs)
ok "${PART_HIS:-0} sous-partitions adsb.aircraft_history"
POS_5MIN=$($PG "SELECT COUNT(*) FROM adsb.positions
WHERE ts >= NOW() - INTERVAL '5 minutes';" 2>/dev/null | xargs)
[ "${POS_5MIN:-0}" -gt 0 ] 2>/dev/null \
&& ok "$POS_5MIN positions insérées dans les 5 dernières minutes" \
|| warn "Aucune position dans les 5 dernières minutes"
PCT_DESC=$($PG "SELECT ROUND(COUNT(aircraft_desc)*100.0/NULLIF(COUNT(*),0),1)
FROM adsb.positions WHERE ts >= NOW() - INTERVAL '30 minutes'
AND lat IS NOT NULL;" 2>/dev/null | xargs)
python3 -c "exit(0 if float('${PCT_DESC:-0}') >= 80 else 1)" 2>/dev/null \
&& ok "aircraft_desc rempli à ${PCT_DESC}% (30 dernières min)" \
|| warn "aircraft_desc rempli à ${PCT_DESC:-0}% (< 80%)"
AV_TODAY=$($PG "SELECT COUNT(DISTINCT icao) FROM adsb.aircraft_history
WHERE session_start >= CURRENT_DATE;" 2>/dev/null | xargs)
SESS_TODAY=$($PG "SELECT COUNT(*) FROM adsb.aircraft_history
WHERE session_start >= CURRENT_DATE;" 2>/dev/null | xargs)
info "Aujourd'hui : ${AV_TODAY:-0} avions distincts, ${SESS_TODAY:-0} sessions"
# BUG CORRIGÉ : pg_size_pretty sur le schéma via pg_class
DB_SIZE=$($PG "SELECT pg_size_pretty(SUM(pg_total_relation_size(c.oid)))
FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE n.nspname='adsb';" 2>/dev/null | xargs)
info "Taille totale schéma adsb : ${DB_SIZE:-?}"
# ── 6. adsb2pg ────────────────────────────────────────────────────────────────
sec "6. adsb2pg — collecteur"
LAST_INS=$(docker logs adsb-adsb2pg 2>&1 | grep "positions insérées" | tail -1)
if [ -n "$LAST_INS" ]; then
ok "adsb2pg actif"
info "$LAST_INS"
# BUG CORRIGÉ : calculer l'âge depuis PostgreSQL (plus fiable que les logs)
LAST_SEC=$($PG "SELECT EXTRACT(EPOCH FROM (NOW() - MAX(inserted_at)))::INT
FROM adsb.positions WHERE inserted_at >= NOW() - INTERVAL '10 minutes';" \
2>/dev/null | xargs)
LAST_SEC_INT=${LAST_SEC%.*}
if [ -n "$LAST_SEC_INT" ] && [ "$LAST_SEC_INT" -le 15 ] 2>/dev/null; then
ok "Dernière insertion il y a ${LAST_SEC_INT}s (cycle 5s actif)"
elif [ -n "$LAST_SEC_INT" ]; then
warn "Dernière insertion il y a ${LAST_SEC_INT}s (> 15s)"
fi
else
warn "Aucun log d'insertion trouvé dans adsb2pg"
fi
# ── 7. Webapp ─────────────────────────────────────────────────────────────────
sec "7. Webapp — interface utilisateur"
for action in live kpi trajectories; do
RESP=$(curl -s --max-time 5 \
"http://127.0.0.1:8080/api.php?action=${action}&period=24&granularity=60" 2>/dev/null)
ERR=$(echo "$RESP" | jq -r '.error // empty' 2>/dev/null)
if echo "$RESP" | jq . >/dev/null 2>&1; then
[ -n "$ERR" ] && warn "api.php?action=${action} : $ERR" \
|| ok "api.php?action=${action} : JSON valide"
else
fail "api.php?action=${action} : réponse non-JSON"
fi
done
# BUG CORRIGÉ : compter les onglets directement dans le conteneur
TAB_CNT=$(docker exec adsb-webapp grep -c 'href="#tab' /var/www/html/index.php 2>/dev/null)
ok "${TAB_CNT:-?} onglets dans index.php"
[ "${TAB_CNT:-0}" -lt 5 ] 2>/dev/null && warn "Moins de 5 onglets — index.php peut être obsolète"
# BUG CORRIGÉ : taille app.js directement dans le conteneur
JS_SZ=$(docker exec adsb-webapp wc -c /var/www/html/js/app.js 2>/dev/null | awk '{print $1}')
info "app.js : ${JS_SZ:-?} octets"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "http://${HOST_IP}:8080/" 2>/dev/null)
[ "$HTTP_CODE" = "200" ] \
&& ok "Accès LAN http://${HOST_IP}:8080 : HTTP $HTTP_CODE" \
|| warn "Accès LAN http://${HOST_IP}:8080 : HTTP ${HTTP_CODE:-?}"
# ── 8. Autogain ───────────────────────────────────────────────────────────────
sec "8. Autogain"
# BUG CORRIGÉ : pattern grep correct pour le gain
CUR_GAIN=$(docker logs adsb-readsb 2>&1 | grep "tuner gain set to" | tail -1 \
| grep -oP '[\d.]+(?= dB)')
AG_STATE=$(docker logs adsb-readsb 2>&1 | grep -oP "(?<=state ')[\w]+" | tail -1)
[ -n "$CUR_GAIN" ] \
&& ok "Gain courant : ${CUR_GAIN} dB — état : ${AG_STATE:-inconnu}" \
|| warn "Gain courant inconnu"
# BUG CORRIGÉ : recherche en anglais (les logs readsb sont en anglais)
INSUF=$(docker logs adsb-readsb 2>&1 | grep -c "Insufficient messages")
[ "$INSUF" -gt 3 ] \
&& warn "$INSUF cycles avec messages insuffisants (antenne/portée ?)" \
|| info "$INSUF cycle(s) avec messages insuffisants"
# ── 9. Statistiques readsb ────────────────────────────────────────────────────
sec "9. Statistiques readsb"
# BUG CORRIGÉ : les stats sont sur lighttpd port 8080 interne, pas 30003
# Le bon endpoint est /data/stats.json via tar1090
STATS_JSON=$(curl -s --max-time 5 "http://127.0.0.1:8090/data/stats.json" 2>/dev/null)
if [ -n "$STATS_JSON" ] && echo "$STATS_JSON" | jq . >/dev/null 2>&1; then
# Stats last 1 min
MSGS_1MIN=$(echo "$STATS_JSON" | jq -r '.last1min.local.messages_strong_signal // .last1min.local.decoded // 0' 2>/dev/null)
MSGS_TOTAL=$(echo "$STATS_JSON" | jq -r '.total.local.messages // 0' 2>/dev/null)
RANGE=$(echo "$STATS_JSON" | jq -r '.last1min.local.max_distance_meters // 0' 2>/dev/null)
RANGE_KM=$(python3 -c "print(round(${RANGE:-0}/1000,1))" 2>/dev/null)
TRACKS=$(echo "$STATS_JSON" | jq -r '.last1min.local.tracks_with_pos // 0' 2>/dev/null)
ok "Statistiques readsb disponibles (via tar1090 :8090)"
info "Messages totaux : ${MSGS_TOTAL:-0}"
info "Messages dernière minute : ${MSGS_1MIN:-0}"
info "Pistes avec position (1min) : ${TRACKS:-0}"
info "Portée max (1min) : ${RANGE_KM:-0} km"
else
# Fallback : stats depuis lighttpd interne readsb
STATS2=$(docker exec adsb-readsb wget -qO- "http://localhost:8080/data/stats.json" 2>/dev/null)
if [ -n "$STATS2" ] && echo "$STATS2" | jq . >/dev/null 2>&1; then
MSGS_TOTAL=$(echo "$STATS2" | jq -r '.total.local.messages // 0')
ok "Statistiques readsb (via lighttpd interne) — Messages totaux : $MSGS_TOTAL"
else
warn "Statistiques readsb non disponibles"
info "Utiliser : docker exec adsb-readsb cat /run/readsb/stats.pb"
fi
fi
# Fichiers stats protobuf (toujours disponibles)
STATS_AGE=$(docker exec adsb-readsb stat -c %Y /run/readsb/stats.pb 2>/dev/null)
if [ -n "$STATS_AGE" ]; then
AGE_S=$(( $(date +%s) - STATS_AGE ))
ok "stats.pb dans readsb-run, mis à jour il y a ${AGE_S}s"
fi
# ── RÉSUMÉ ────────────────────────────────────────────────────────────────────
echo ""
echo -e "${MAGENTA}╔══════════════════════════════════════════════════════╗"
echo -e "║ RÉSUMÉ ║"
echo -e "╠══════════════════════════════════════════════════════╣${NC}"
if [ "$ERRORS" -eq 0 ] && [ "$WARNS" -eq 0 ]; then
echo -e "${MAGENTA}${NC} ${GREEN}✓ Stack opérationnel — aucune anomalie détectée${NC} ${MAGENTA}${NC}"
elif [ "$ERRORS" -eq 0 ]; then
echo -e "${MAGENTA}${NC} ${YELLOW}⚠ Stack opérationnel — $WARNS avertissement(s)${NC} ${MAGENTA}${NC}"
else
echo -e "${MAGENTA}${NC} ${RED}$ERRORS erreur(s), $WARNS avertissement(s)${NC} ${MAGENTA}${NC}"
fi
echo -e "${MAGENTA}${NC} ${BLUE}Dashboard : http://${HOST_IP}:8080${NC} ${MAGENTA}${NC}"
echo -e "${MAGENTA}${NC} ${BLUE}tar1090 : http://${HOST_IP}:8090${NC} ${MAGENTA}${NC}"
echo -e "${MAGENTA}╚══════════════════════════════════════════════════════╝${NC}"
exit $ERRORS