#!/bin/bash # ============================================= # Script de vérification complète de la stack ADS-B # Version : 7.0 (Avec port/IP PostgreSQL et corrections jq) # Date : 26/06/2026 # Auteur : JC Abiven (avec Mistral AI) # ============================================= # Vérifier que jq est installé if ! command -v jq &> /dev/null; then echo -e "\033[0;31m✗ jq n'est pas installé. Installez-le avec : sudo apt install jq\033[0m" exit 1 fi # Couleurs pour l'affichage 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' # Fonction pour afficher un message avec une couleur print_status() { echo -e "${1}${2}${NC}" } # Fonction pour afficher un titre print_title() { echo -e "\n${BLUE}═══ ${1} ═══${NC}" } # Fonction pour afficher une section print_section() { echo -e "\n${CYAN}═══ ${1} ═══${NC}" } # Récupérer l'IP de l'hôte HOST_IP=$(hostname -I | awk '{print $1}') # Afficher l'en-tête 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 "╚══════════════════════════════════════════════════════╝" print_status "$YELLOW" " → IP détectée : $HOST_IP" # ============================================= # 1. Vérification des conteneurs Docker # ============================================= print_section "1. Conteneurs Docker" DOCKER_CONTAINERS=("adsb-readsb" "adsb-tar1090" "adsb-adsb2pg" "adsb-webapp" "wordpress-postgres") for container in "${DOCKER_CONTAINERS[@]}"; do if docker ps | grep -q "$container"; then STATUS=$(docker inspect --format='{{.State.Health.Status}}' "$container" 2>/dev/null || echo "none") if [ "$STATUS" = "healthy" ]; then print_status "$GREEN" " ✓ $container [healthy]" else print_status "$GREEN" " ✓ $container" fi else print_status "$RED" " ✗ $container — non démarré" fi done # ============================================= # 2. Vérification du dongle RTL-SDR # ============================================= print_section "2. Dongle RTL-SDR" if docker logs adsb-readsb 2>&1 | grep -q "rtlsdr: using device #0: Generic RTL2832U OEM (AIRNAV, ADSB_1090, SN 00000010)"; then print_status "$GREEN" " ✓ AirNav FlightStick SN:00000010 détecté" GAIN=$(docker logs adsb-readsb 2>&1 | grep -oP "tuner gain set to \K[0-9.]+ dB" | tail -1) print_status "$GREEN" " → Gain actuel : $GAIN" else print_status "$RED" " ✗ Dongle RTL-SDR non détecté" fi # Vérifier le symlink /dev/adsb_dongle if [ -L "/dev/adsb_dongle" ]; then print_status "$GREEN" " ✓ Symlink /dev/adsb_dongle présent" else print_status "$YELLOW" " ⚠ Symlink /dev/adsb_dongle introuvable" fi # ============================================= # 3. Vérification des données ADS-B # ============================================= print_section "3. Données ADS-B" # Vérifier tar1090 if curl -s --max-time 5 http://127.0.0.1:8090 >/dev/null; then TAR1090_STATS=$(curl -s --max-time 5 http://127.0.0.1:8090/data/stats.json 2>/dev/null) if [ -n "$TAR1090_STATS" ]; then MESSAGES=$(echo "$TAR1090_STATS" | jq -r '.totalMessages // "N/A"') print_status "$GREEN" " ✓ tar1090 actif — $MESSAGES messages décodés" else print_status "$YELLOW" " ⚠ Impossible de récupérer les stats de tar1090" fi AIRCRAFT_DATA=$(curl -s --max-time 5 http://127.0.0.1:8090/data/aircraft.json 2>/dev/null) if [ -n "$AIRCRAFT_DATA" ]; then AIRCRAFT_COUNT=$(echo "$AIRCRAFT_DATA" | jq '. | length // 0') # Correction : utiliser `select` pour éviter l'erreur jq AIRCRAFT_WITH_POS=$(echo "$AIRCRAFT_DATA" | jq '[.[] | select(.lat != null and .lon != null)] | length // 0') print_status "$GREEN" " ✓ $AIRCRAFT_COUNT avion(s) en vue dont $AIRCRAFT_WITH_POS avec position GPS" else print_status "$YELLOW" " ⚠ Impossible de récupérer les données des avions" fi else print_status "$RED" " ✗ tar1090 non accessible" fi # Vérifier le volume readsb-run if docker exec adsb-readsb ls /run/readsb/aircraft.pb >/dev/null 2>&1; then print_status "$GREEN" " ✓ Volume readsb-run : aircraft.pb présent" else print_status "$YELLOW" " ⚠ Volume readsb-run : aircraft.pb introuvable" fi # ============================================= # 4. Vérification des ports réseau (avec adresses IP) # ============================================= print_section "4. Ports réseau" # Fonction pour obtenir l'adresse IP et le port d'écoute get_listening_info() { local port=$1 # Essayer avec ss d'abord if command -v ss &> /dev/null; then ss -tulnp | grep ":$port " | awk '{print $5}' | head -1 else # Fallback sur netstat netstat -tulnp 2>/dev/null | grep ":$port " | awk '{print $4}' | head -1 fi } # Liste des ports à vérifier : format "port:service:ip_attendue" PORTS=( "8080:webapp PHP:127.0.0.1" "8090:tar1090 nginx:0.0.0.0" "30005:Beast TCP readsb:0.0.0.0" "5432:PostgreSQL:127.0.0.1" "30002:RAW TCP:127.0.0.1" "30003:SBS TCP:127.0.0.1" ) for port_info in "${PORTS[@]}"; do PORT=${port_info%%:*} SERVICE=${port_info#*:} SERVICE=${SERVICE%:*} EXPECTED_IP=${port_info##*:} # Obtenir l'IP et le port réel LISTENING_INFO=$(get_listening_info "$PORT" || echo "inconnu") ACTUAL_IP=$(echo "$LISTENING_INFO" | cut -d: -f1) ACTUAL_PORT=$(echo "$LISTENING_INFO" | cut -d: -f2) if timeout 2 nc -z "$EXPECTED_IP" "$PORT" 2>/dev/null; then print_status "$GREEN" " ✓ Port $PORT ($SERVICE) — IP: ${ACTUAL_IP:-inconnu}:${ACTUAL_PORT:-$PORT} (attendu: $EXPECTED_IP:$PORT)" else print_status "$RED" " ✗ Port $PORT ($SERVICE) — IP: ${ACTUAL_IP:-inconnu}:${ACTUAL_PORT:-$PORT} (attendu: $EXPECTED_IP:$PORT)" fi done # Vérifier la connectivité Beast TCP via la gateway if timeout 2 nc -z 172.20.0.1 30005 2>/dev/null; then print_status "$GREEN" " ✓ readsb attaché à adsb-net : 172.20.0.2 (gateway: 172.20.0.1)" else print_status "$RED" " ✗ Problème de connectivité avec adsb-net (172.20.0.1:30005)" fi # ============================================= # 5. Vérification de PostgreSQL et du schéma adsb # ============================================= print_section "5. PostgreSQL — schéma adsb" # Vérifier l'accès à PostgreSQL if docker exec wordpress-postgres pg_isready -U pgz_admin -d wpz_postgres 2>/dev/null | grep -q "accepting connections"; then print_status "$GREEN" " ✓ PostgreSQL accessible" PG_VERSION=$(docker exec wordpress-postgres psql -U pgz_admin -d wpz_postgres -t -c "SELECT version();" 2>/dev/null | head -1 | tr -d ' ') print_status "$GREEN" " → $PG_VERSION" # Obtenir le port et l'IP d'écoute de PostgreSQL PG_LISTEN_INFO=$(docker exec wordpress-postgres ss -tulnp 2>/dev/null | grep "5432" | awk '{print $5}' | head -1 || echo "inconnu") PG_ACTUAL_IP=$(echo "$PG_LISTEN_INFO" | cut -d: -f1) PG_ACTUAL_PORT=$(echo "$PG_LISTEN_INFO" | cut -d: -f2) print_status "$GREEN" " → Écoute sur : ${PG_ACTUAL_IP:-127.0.0.1}:${PG_ACTUAL_PORT:-5432}" else print_status "$RED" " ✗ PostgreSQL non accessible" fi # Vérifier les partitions PARTITIONS_POSITIONS=$(docker exec wordpress-postgres psql -U pgz_admin -d wpz_postgres -t -c "SELECT COUNT(*) FROM pg_tables WHERE schemaname = 'adsb' AND tablename LIKE 'positions_%';" 2>/dev/null | tr -d ' ') PARTITIONS_HISTORY=$(docker exec wordpress-postgres psql -U pgz_admin -d wpz_postgres -t -c "SELECT COUNT(*) FROM pg_tables WHERE schemaname = 'adsb' AND tablename LIKE 'aircraft_history_%';" 2>/dev/null | tr -d ' ') print_status "$GREEN" " ✓ $PARTITIONS_POSITIONS sous-partitions adsb.positions" print_status "$GREEN" " ✓ $PARTITIONS_HISTORY sous-partitions adsb.aircraft_history" # Vérifier les insertions récentes POSITIONS_5MIN=$(docker exec wordpress-postgres psql -U pgz_admin -d wpz_postgres -t -c "SELECT COUNT(*) FROM adsb.positions WHERE ts >= NOW() - INTERVAL '5 minutes';" 2>/dev/null | tr -d ' ') print_status "$GREEN" " ✓ $POSITIONS_5MIN positions insérées dans les 5 dernières minutes" # Vérifier le remplissage de aircraft_desc DESC_FILL=$(docker exec wordpress-postgres psql -U pgz_admin -d wpz_postgres -t -c "SELECT ROUND(COUNT(aircraft_desc)*100.0/COUNT(*),1) FROM adsb.positions WHERE ts >= NOW() - INTERVAL '30 minutes' AND lat IS NOT NULL;" 2>/dev/null | tr -d ' ') print_status "$GREEN" " ✓ aircraft_desc rempli à ${DESC_FILL:-0}% (30 dernières min)" # Taille du schéma adsb SCHEMA_SIZE=$(docker exec wordpress-postgres psql -U pgz_admin -d wpz_postgres -t -c "SELECT pg_size_pretty(pg_total_relation_size('adsb'));" 2>/dev/null | tr -d ' ') print_status "$GREEN" " → Taille totale schéma adsb : ${SCHEMA_SIZE:-inconnu}" # ============================================= # 6. Vérification de adsb2pg (collecteur) # ============================================= print_section "6. adsb2pg — collecteur" if docker ps | grep -q "adsb-adsb2pg"; then ADSB2PG_LOGS=$(docker logs adsb-adsb2pg 2>&1 | tail -1) if echo "$ADSB2PG_LOGS" | grep -q "positions insérées"; then print_status "$GREEN" " ✓ adsb2pg actif : $ADSB2PG_LOGS" else print_status "$YELLOW" " ⚠ adsb2pg actif mais aucun log récent" fi # Vérifier la dernière insertion (en secondes) LAST_INSERT_SEC=$(docker exec wordpress-postgres psql -U pgz_admin -d wpz_postgres -t -c "SELECT EXTRACT(EPOCH FROM (NOW() - MAX(inserted_at))) FROM adsb.positions WHERE inserted_at >= NOW() - INTERVAL '10 minutes';" 2>/dev/null | tr -d ' ') if [ -n "$LAST_INSERT_SEC" ]; then LAST_INSERT_SEC_INT=${LAST_INSERT_SEC%.*} # Supprimer la partie décimale if [ "$LAST_INSERT_SEC_INT" -le 10 ] 2>/dev/null; then print_status "$GREEN" " ✓ Dernière insertion il y a ${LAST_INSERT_SEC_INT}s (cycle 5s actif)" else print_status "$RED" " ✗ Dernière insertion trop ancienne (${LAST_INSERT_SEC_INT}s)" fi else print_status "$RED" " ✗ Impossible de vérifier la dernière insertion" fi else print_status "$RED" " ✗ adsb2pg non démarré" fi # ============================================= # 7. Vérification de la webapp # ============================================= print_section "7. Webapp — interface utilisateur" # Vérifier les endpoints API API_ENDPOINTS=("action=live" "action=kpi" "action=trajectories") for endpoint in "${API_ENDPOINTS[@]}"; do if curl -s --max-time 5 "http://127.0.0.1:8080/api.php?$endpoint" >/dev/null; then print_status "$GREEN" " ✓ api.php?$endpoint : OK (IP: 127.0.0.1:8080)" else print_status "$RED" " ✗ api.php?$endpoint : KO (IP: 127.0.0.1:8080)" fi done # Vérifier le nombre d'onglets dans index.php ONGETS=$(curl -s --max-time 5 http://127.0.0.1:8080/index.php | grep -o "