adsb-1090/export_adsb_bundle.sh

183 lines
9.9 KiB
Bash
Executable File

#!/bin/bash
# ═══════════════════════════════════════════════════════════════════════════════
# export_adsb_bundle.sh — Empaquette le stack ADS-B fonctionnel de Linux-25
# Version 2.0 — JCA 2026
#
# À LANCER SUR LINUX-25 (la machine source, celle qui fonctionne déjà).
# Produit une archive .tar.gz portable, prête à copier sur la machine neuve
# et à installer avec install_adsb_stack.sh.
#
# v2.0 (05/07/2026) : inclut les correctifs découverts lors des incidents
# du 03-05/07/2026 :
# - adsb2pg.py : clean_altitude() (bug "ground") + rollback() sur exception
# - watchdog_readsb.sh v2 : seuil adaptatif jour/nuit (évite le flapping
# nocturne sur les creux de trafic réels)
# - schema_adsb_base.sql : schéma générique SANS les partitions datées
# spécifiques à Linux-25 (w25-w28, 2026/2027) — la nouvelle machine
# amorce ses propres partitions à la date réelle d'installation
# - check_adsb.sh v3.4 : watchdog crontab, continuité partitions, RestartCount
# - cron d'automatisation des partitions (dimanche 20h, +14 jours)
#
# Usage : ./export_adsb_bundle.sh [chemin_sortie.tar.gz]
# ═══════════════════════════════════════════════════════════════════════════════
set -euo pipefail
ADSB_DIR="/data/adsb"
OUT_FILE="${1:-/tmp/adsb_bundle_$(date +%Y%m%d_%H%M%S).tar.gz}"
WORK_DIR=$(mktemp -d)
BUNDLE_DIR="$WORK_DIR/adsb_bundle"
GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
ok() { echo -e " ${GREEN}${NC} $1"; }
fail() { echo -e " ${RED}${NC} $1"; }
warn() { echo -e " ${YELLOW}${NC} $1"; }
info() { echo -e " ${CYAN}${NC} $1"; }
step() { echo -e "\n${BOLD}$1${NC}"; }
trap 'rm -rf "$WORK_DIR"' EXIT
echo -e "${BOLD}╔══════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║ Export bundle ADS-B — source : $(hostname)${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════════════════╝${NC}"
mkdir -p "$BUNDLE_DIR"/{adsb2pg,webapp,scripts,sql,docs}
# ── 1. docker-compose.yml (nettoyé des secrets) ───────────────────────────────
step "1. docker-compose.yml"
if [ -f "$ADSB_DIR/docker-compose.yml" ]; then
# Remplace le mot de passe en dur par un placeholder — install_adsb_stack.sh
# en génère un nouveau et l'injecte à l'installation.
sed -E 's/(PG_PASSWORD=)[^[:space:]]+/\1__PG_PASSWORD_PLACEHOLDER__/' \
"$ADSB_DIR/docker-compose.yml" > "$BUNDLE_DIR/docker-compose.yml"
ok "docker-compose.yml exporté (mot de passe neutralisé)"
else
fail "docker-compose.yml introuvable dans $ADSB_DIR"
fi
# ── 2. adsb2pg (code source complet) ──────────────────────────────────────────
step "2. adsb2pg"
if [ -d "$ADSB_DIR/adsb2pg" ]; then
# --exclude .git : tar1090-db est un dépôt Git cloné en sous-répertoire —
# son historique n'a aucune utilité dans l'image Docker et alourdit
# inutilement le bundle (souvent plusieurs dizaines de Mo).
if command -v rsync &>/dev/null; then
rsync -a --exclude='.git' "$ADSB_DIR/adsb2pg/" "$BUNDLE_DIR/adsb2pg/"
else
cp -r "$ADSB_DIR/adsb2pg/." "$BUNDLE_DIR/adsb2pg/"
find "$BUNDLE_DIR/adsb2pg" -type d -name ".git" -exec rm -rf {} + 2>/dev/null
fi
GIT_LEFT=$(find "$BUNDLE_DIR/adsb2pg" -type d -name ".git" | wc -l)
if [ "$GIT_LEFT" -eq 0 ]; then
ok "Code adsb2pg copié ($(find "$BUNDLE_DIR/adsb2pg" -name '*.py' | wc -l) fichier(s) .py), .git exclu"
else
warn ".git non exclu proprement — vérifier manuellement la taille du bundle"
fi
if grep -q "clean_altitude" "$BUNDLE_DIR/adsb2pg/adsb2pg.py" 2>/dev/null; then
ok "Correctif clean_altitude() présent"
else
warn "Correctif clean_altitude() ABSENT — bundle basé sur une version non corrigée !"
fi
if grep -q "conn.rollback()" "$BUNDLE_DIR/adsb2pg/adsb2pg.py" 2>/dev/null; then
ok "Correctif rollback() présent"
else
warn "Correctif rollback() ABSENT — bundle basé sur une version non corrigée !"
fi
else
fail "Répertoire adsb2pg introuvable dans $ADSB_DIR"
fi
# ── 3. webapp (code source complet) ───────────────────────────────────────────
step "3. webapp"
if [ -d "$ADSB_DIR/webapp" ]; then
cp -r "$ADSB_DIR/webapp/." "$BUNDLE_DIR/webapp/"
ok "Code webapp copié"
else
fail "Répertoire webapp introuvable dans $ADSB_DIR"
fi
# ── 4. Schéma SQL générique (SANS les partitions datées) ──────────────────────
step "4. Schéma PostgreSQL"
if [ -f "$ADSB_DIR/schema_adsb_base.sql" ]; then
cp "$ADSB_DIR/schema_adsb_base.sql" "$BUNDLE_DIR/sql/schema_adsb_base.sql"
ok "schema_adsb_base.sql copié depuis $ADSB_DIR"
else
warn "schema_adsb_base.sql absent de $ADSB_DIR — utilisation de la copie du bundle courant"
info "Pense à le régénérer si le schéma a changé depuis :"
info " docker exec wordpress-postgres pg_dump -U pgz_admin -d wpz_postgres --schema-only -n adsb > schema_full.sql"
info " puis en retirer les partitions datées (w25-w28, aircraft_history_2026/2027)"
fi
# ── 5. Scripts opérationnels (watchdog v2, check_adsb v3.4) ───────────────────
step "5. Scripts opérationnels"
for f in scripts/watchdog_readsb.sh check_adsb.sh; do
SRC="$ADSB_DIR/$f"
DEST="$BUNDLE_DIR/scripts/$(basename "$f")"
if [ -f "$SRC" ]; then
cp "$SRC" "$DEST"
chmod +x "$DEST"
ok "$(basename "$f") copié"
else
warn "$SRC introuvable — à ajouter manuellement au bundle avant install"
fi
done
# Vérifier que le watchdog copié est bien la v2 (seuil adaptatif)
if grep -q "THRESHOLD" "$BUNDLE_DIR/scripts/watchdog_readsb.sh" 2>/dev/null; then
ok "watchdog_readsb.sh : v2 (seuil adaptatif jour/nuit) confirmée"
else
warn "watchdog_readsb.sh : semble être la v1 (pas de seuil adaptatif) — flapping nocturne possible sur la nouvelle machine"
fi
# ── 6. udev rule (RTL-SDR) ────────────────────────────────────────────────────
step "6. Règle udev RTL-SDR"
if [ -f /etc/udev/rules.d/99-adsb-docker.rules ]; then
cp /etc/udev/rules.d/99-adsb-docker.rules "$BUNDLE_DIR/scripts/99-adsb-docker.rules"
ok "Règle udev copiée"
else
warn "Règle udev absente sur cette machine — la nouvelle machine n'aura pas de relance auto USB"
fi
# ── 7. Documentation / notes de version ───────────────────────────────────────
step "7. Documentation"
cat > "$BUNDLE_DIR/docs/CHANGELOG_BUNDLE.md" << 'EOF'
# Bundle ADS-B — historique des correctifs inclus
## v2.0 (05/07/2026)
- **adsb2pg.py** : fix `clean_altitude()` — readsb/tar1090 renvoient la chaîne
littérale `"ground"` pour l'altitude d'un avion au sol, ce qui plantait
l'INSERT PostgreSQL (colonne integer). Sans `conn.rollback()` derrière,
cette unique erreur bloquait tout le collecteur pendant 13h (incident du
03/07/2026 sur Linux-25).
- **watchdog_readsb.sh v2** : seuil adaptatif jour (1 cycle/5min) / nuit
(3 cycles/15min) — la v1 redémarrait le dongle sur de simples creux de
trafic nocturne, confondus avec un vrai gel matériel.
- **schema_adsb_base.sql** : schéma généré à partir d'un pg_dump --schema-only
de Linux-25, DÉLIBÉRÉMENT expurgé des partitions datées (semaines/années
spécifiques à Linux-25). L'installeur amorce les partitions à la date
réelle d'installation via `create_week_partition()`/`create_year_partition()`.
- **check_adsb.sh v3.4** : ajout des vérifications watchdog (crontab, fraîcheur,
flapping), continuité des partitions, RestartCount Docker, sync NTP.
- Automatisation cron de création des partitions (dimanche 20h, +14 jours).
## Notes de déploiement
- Le récepteur RTL-SDR de la nouvelle machine aura un numéro de série USB
différent — install_adsb_stack.sh le détecte automatiquement et met à jour
RECEIVER_SERIAL dans docker-compose.yml + une ligne dans adsb.receivers.
- Le mot de passe PostgreSQL est régénéré à l'installation, jamais réutilisé
tel quel entre machines.
EOF
ok "CHANGELOG_BUNDLE.md généré"
# ── 8. Archivage ───────────────────────────────────────────────────────────────
step "8. Création de l'archive"
tar czf "$OUT_FILE" -C "$WORK_DIR" adsb_bundle
SIZE=$(du -sh "$OUT_FILE" | cut -f1)
ok "Archive créée : $OUT_FILE ($SIZE)"
echo -e "\n${BOLD}╔══════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║ Bundle prêt : $OUT_FILE"
echo -e "${BOLD}║ Copie sur la nouvelle machine puis lance : ║${NC}"
echo -e "${BOLD}║ tar xzf $(basename "$OUT_FILE")${NC}"
echo -e "${BOLD}║ cd adsb_bundle && sudo ./install_adsb_stack.sh ║${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════════════════╝${NC}"