fix: Voll-Deploy der Rettungsstation gegen doppelte Images und stillen Loeschverlust absichern
Zwei Build-Verzeichnisse mit demselben Image-Dateinamen (z.B. build/evk und build/evk-onb, letzteres ohne WLAN-Zugangsdaten) landeten flach im selben Staging-Namen - die Sortierreihenfolge entschied zufaellig, welches gewinnt, und die Trailer-Pruefung merkt nichts, weil in beiden derselbe Geraetetyp steht. deploy.sh bricht jetzt ab und nennt beide Fundorte, statt zu raten. Der Voll-Deploy (deploy.sh <host> ohne target - der in README.md gezeigte Normalfall) loeschte per rsync --delete zudem die Images aller gerade nicht gebauten Geraetetypen, ohne je zu sagen, welche. Vor dem Loeschen wird jetzt per Namensvergleich ermittelt und ausgegeben, welche Dateien verschwinden - sichtbar statt still, ohne den Ablauf fuer Skripte zu blockieren. Neue Testszenarien 7-9 in tools/station/tests/test_deploy.sh decken beide Faelle ab. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
6daf36540c
commit
d464bb167e
+33
-2
@@ -27,7 +27,23 @@ if [ $# -gt 0 ]; then
|
||||
done
|
||||
else
|
||||
FULL_SYNC=1
|
||||
while IFS= read -r f; do FILES+=("$f"); done < <(find "$ROOT/build" -maxdepth 2 -name 'ninlight_*_ota.img' | sort)
|
||||
# Zwei Build-Verzeichnisse koennen denselben Image-Dateinamen liefern (z.B.
|
||||
# build/evk/ und ein Nebenschauplatz wie build/evk-onb/, das ohne WLAN-
|
||||
# Zugangsdaten gebaut wurde). Landen beide flach im selben STAGE/$base,
|
||||
# entscheidet allein die Sortierreihenfolge, welches gewinnt - und die
|
||||
# Trailer-Pruefung merkt nichts, weil in beiden derselbe Geraetetyp steht.
|
||||
# Ein zweiter Fundort fuer denselben Dateinamen ist deshalb ein Abbruch,
|
||||
# kein Zufall.
|
||||
declare -A SEEN_AT=()
|
||||
while IFS= read -r f; do
|
||||
base=$(basename "$f")
|
||||
if [ -n "${SEEN_AT[$base]:-}" ]; then
|
||||
echo "Fehler: $base mehrfach gefunden - ${SEEN_AT[$base]} und $f. Voller Deploy abgebrochen, welches Bild echt ist, ist nicht entscheidbar. Nicht benoetigtes Build-Verzeichnis loeschen oder gezielt deployen." >&2
|
||||
exit 1
|
||||
fi
|
||||
SEEN_AT[$base]=$f
|
||||
FILES+=("$f")
|
||||
done < <(find "$ROOT/build" -maxdepth 2 -name 'ninlight_*_ota.img' | sort)
|
||||
[ ${#FILES[@]} -gt 0 ] || { echo "Fehler: keine Images unter $ROOT/build gefunden" >&2; exit 1; }
|
||||
fi
|
||||
|
||||
@@ -73,7 +89,22 @@ UNIT_PATH=${NINLIGHT_STATION_UNIT:-/etc/systemd/system/ninlight-station.service}
|
||||
sudo install -d -m 0755 "$ROOT_DIR/images"
|
||||
if [ "$FULL_SYNC" -eq 1 ]; then
|
||||
# Vollabgleich: alle Images ausserhalb der aktuellen Auslieferung entfernen.
|
||||
echo " voller Abgleich - Images ausserhalb der Auswahl werden entfernt"
|
||||
# Vorher zeigen, WELCHE das sind - sonst faellt ein geloeschtes Image erst
|
||||
# auf, wenn jemand mit einer toten Lampe vor der Station steht. Ermittelt
|
||||
# per einfachem Namensvergleich (portabel, kein Verlass auf rsyncs
|
||||
# "deleting"-Ausgabe, die ohne -v gar nicht erscheint).
|
||||
OLD_LIST=$(find "$ROOT_DIR/images" -maxdepth 1 -name 'ninlight_*_ota.img' -exec basename {} \; 2>/dev/null | sort)
|
||||
NEW_LIST=$(find /tmp/ninlight-images -maxdepth 1 -name 'ninlight_*_ota.img' -exec basename {} \; | sort)
|
||||
REMOVED=""
|
||||
if [ -n "$OLD_LIST" ]; then
|
||||
REMOVED=$(comm -23 <(printf '%s\n' "$OLD_LIST") <(printf '%s\n' "$NEW_LIST"))
|
||||
fi
|
||||
if [ -n "$REMOVED" ]; then
|
||||
echo " voller Abgleich - folgende Images werden entfernt:"
|
||||
echo "$REMOVED" | sed 's/^/ /'
|
||||
else
|
||||
echo " voller Abgleich - keine Images werden entfernt"
|
||||
fi
|
||||
sudo rsync -a -c --delete /tmp/ninlight-images/ "$ROOT_DIR/images/"
|
||||
else
|
||||
# Gezielter Deploy: nur die uebertragenen Dateien ersetzen/ergaenzen, alle
|
||||
|
||||
@@ -275,6 +275,87 @@ else
|
||||
fail "setup_pi.sh: Default fuer SCP_BIN ist nicht mehr /usr/bin/scp"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== Szenario 7: Voll-Deploy mit zwei Build-Verzeichnissen fuer denselben Dateinamen -> Abbruch (B1) ==="
|
||||
SANDBOX="$TMPROOT/s7"; STUBBIN="$TMPROOT/bin7"; LOG="$TMPROOT/s7.log"; SANDBOX_STATE="$TMPROOT/s7-state"
|
||||
setup_sandbox "$SANDBOX"
|
||||
setup_stubbin "$STUBBIN" "$LOG"
|
||||
mkdir -p "$SANDBOX/build/evk" "$SANDBOX/build/evk-onb"
|
||||
echo "evk-mit-wlan" >"$SANDBOX/build/evk/ninlight_evk_ota.img"
|
||||
echo "evk-ohne-wlan" >"$SANDBOX/build/evk-onb/ninlight_evk_ota.img"
|
||||
: >"$LOG"
|
||||
set +e
|
||||
OUT=$(run_deploy "$SANDBOX" pi-test 2>&1)
|
||||
RC=$?
|
||||
set -e
|
||||
if [ "$RC" -ne 0 ]; then pass "Exit-Code != 0 ($RC)"; else fail "Exit-Code war 0, obwohl zwei Fundorte denselben Dateinamen liefern"; fi
|
||||
if echo "$OUT" | grep -q "ninlight_evk_ota.img mehrfach gefunden"; then
|
||||
pass "Fehlermeldung nennt den doppelten Dateinamen"
|
||||
else
|
||||
fail "Fehlermeldung zum doppelten Dateinamen fehlt: $OUT"
|
||||
fi
|
||||
if echo "$OUT" | grep -q "build/evk/ninlight_evk_ota.img" && echo "$OUT" | grep -q "build/evk-onb/ninlight_evk_ota.img"; then
|
||||
pass "Fehlermeldung nennt beide Fundorte"
|
||||
else
|
||||
fail "Fehlermeldung nennt nicht beide Fundorte: $OUT"
|
||||
fi
|
||||
if ! grep -q "STUB" "$LOG" 2>/dev/null; then
|
||||
pass "kein Transfer-Kommando aufgerufen - nichts wurde stillschweigend uebertragen"
|
||||
else
|
||||
fail "ein Transfer-Kommando wurde trotz doppeltem Dateinamen aufgerufen: $(cat "$LOG")"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== Szenario 8: Voll-Deploy zeigt vor dem Loeschen, welche Images verschwinden (B2) ==="
|
||||
SANDBOX="$TMPROOT/s8"; STUBBIN="$TMPROOT/bin8"; LOG="$TMPROOT/s8.log"; SANDBOX_STATE="$TMPROOT/s8-state"
|
||||
setup_sandbox "$SANDBOX"
|
||||
setup_stubbin "$STUBBIN" "$LOG"
|
||||
mkdir -p "$SANDBOX/build/foo"
|
||||
echo "foo-image-neu" >"$SANDBOX/build/foo/ninlight_foo_ota.img"
|
||||
mkdir -p "$SANDBOX_STATE/opt/ninlight-station/images"
|
||||
echo "veraltet" >"$SANDBOX_STATE/opt/ninlight-station/images/ninlight_veraltet_ota.img"
|
||||
echo "auch-veraltet" >"$SANDBOX_STATE/opt/ninlight-station/images/ninlight_e14_cw_ota.img"
|
||||
: >"$LOG"
|
||||
set +e
|
||||
OUT=$(run_deploy "$SANDBOX" pi-test 2>&1)
|
||||
RC=$?
|
||||
set -e
|
||||
if [ "$RC" -eq 0 ]; then pass "Exit-Code 0"; else fail "Exit-Code $RC, Ausgabe: $OUT"; fi
|
||||
if echo "$OUT" | grep -q "folgende Images werden entfernt"; then
|
||||
pass "Ausgabe kuendigt die zu entfernenden Images an, bevor geloescht wird"
|
||||
else
|
||||
fail "Ausgabe nennt die zu entfernenden Images nicht: $OUT"
|
||||
fi
|
||||
if echo "$OUT" | grep -q "ninlight_veraltet_ota.img" && echo "$OUT" | grep -q "ninlight_e14_cw_ota.img"; then
|
||||
pass "beide zu entfernenden Dateien werden namentlich genannt"
|
||||
else
|
||||
fail "nicht alle zu entfernenden Dateien werden genannt: $OUT"
|
||||
fi
|
||||
if [ ! -f "$SANDBOX_STATE/opt/ninlight-station/images/ninlight_veraltet_ota.img" ]; then
|
||||
pass "veraltetes Image wurde nach der Ankuendigung tatsaechlich entfernt"
|
||||
else
|
||||
fail "veraltetes Image wurde trotz Ankuendigung nicht entfernt"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== Szenario 9: Voll-Deploy ohne verwaiste Images meldet das statt zu schweigen (B2) ==="
|
||||
SANDBOX="$TMPROOT/s9"; STUBBIN="$TMPROOT/bin9"; LOG="$TMPROOT/s9.log"; SANDBOX_STATE="$TMPROOT/s9-state"
|
||||
setup_sandbox "$SANDBOX"
|
||||
setup_stubbin "$STUBBIN" "$LOG"
|
||||
mkdir -p "$SANDBOX/build/foo"
|
||||
echo "foo-image" >"$SANDBOX/build/foo/ninlight_foo_ota.img"
|
||||
: >"$LOG"
|
||||
set +e
|
||||
OUT=$(run_deploy "$SANDBOX" pi-test 2>&1)
|
||||
RC=$?
|
||||
set -e
|
||||
if [ "$RC" -eq 0 ]; then pass "Exit-Code 0"; else fail "Exit-Code $RC, Ausgabe: $OUT"; fi
|
||||
if echo "$OUT" | grep -q "keine Images werden entfernt"; then
|
||||
pass "Ausgabe meldet explizit, dass nichts entfernt wird"
|
||||
else
|
||||
fail "Ausgabe meldet nicht, dass nichts entfernt wird: $OUT"
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ "$FAILED" -eq 0 ]; then
|
||||
echo "Alle Tests bestanden."
|
||||
|
||||
Reference in New Issue
Block a user