fix(station): CLI prueft Rettungs- und Migrationsbildsatz getrennt, meldet Modus dauerhaft
Fixrunde 1, Befund 1: imageset_dir()/migrate_images()/imageset_status_lines() pruefen bislang IMMER die Migrationsverzeichnisse, unabhaengig vom Modus - im Rettungsbetrieb meldete "status" so faelschlich "MISSING", waehrend rescue-nocreds voll war, oder umgekehrt "vorhanden", waehrend die Rettung nichts hatte. Ein falsches "MISSING" dort verleitet dazu, auf mit-wlan umzuschalten - und dann liefert die Rettung tatsaechlich Abbilder mit dem WLAN-Passwort aus. imageset_dir() nimmt jetzt den Modus als Parameter (Vorgabe: current_mode()), dieselbe Unterscheidung wie im Panel. Befund 2: images() griff weiter flach auf $IMAGE_DIR zu, wo seit dem Deploy-Umbau nichts mehr liegt - "recovery on" warnte deshalb bei JEDEM Start "answers everything with 404". Ersetzt durch imageset_images(), das dem Bildsatz-Umschalter UND dem Modus folgt. Befund 3 (CLI-Seite): current_mode() liest die neue dauerhafte LAST_MODE_FILE statt der ephemeren RUN_DIR/mode - write_mode() schreibt jetzt beide (siehe display.py-Commit fuer die Panel-Seite derselben Ursache). tests/test_cli.sh legte weiterhin die alte flache Rettungsablage an (images/ninlight_foo_ota.img) - die Sandbox hat jetzt eigene rescue-wlan/rescue-nocreds-Verzeichnisse wie ein echter Pi nach diesem Umschalter, und run_cli() setzt NINLIGHT_LAST_MODE_FILE auf einen Sandbox-Pfad. Mehrere bestehende Bildsatz-Szenarien liefen unbemerkt gegen den Migrationssatz, obwohl kein Modus gesetzt war (Vorgabe: recovery) - angepasst, damit sie den tatsaechlich geltenden Satz pruefen.
This commit is contained in:
@@ -130,8 +130,33 @@ need_profile() {
|
||||
}
|
||||
}
|
||||
|
||||
images() {
|
||||
find "$IMAGE_DIR" -maxdepth 1 -name 'ninlight_*_ota.img' 2>/dev/null | sort
|
||||
# --- Modus lesen/schreiben (Fixrunde 1, Befund 3) -----------------------------------
|
||||
#
|
||||
# RUN_DIR/mode (write_mode() unten schreibt sie zusaetzlich) taugt NICHT als Quelle
|
||||
# fuer "welcher Modus gilt gerade/als naechstes", solange die Station AUS ist: die Unit
|
||||
# setzt RuntimeDirectoryPreserve=restart, das erhaelt /run/ninlight-station nur ueber
|
||||
# einen "systemctl restart" (das, was "recovery on"/"migrate on" bei einem schon
|
||||
# laufenden Dienst ausloesen), NICHT ueber einen echten "systemctl stop" - und genau
|
||||
# den fuehrt "ninlight-station off" aus. Fehlt die Datei, gilt ueberall stillschweigend
|
||||
# "recovery" (derselbe sichere Vorgabewert wie beim Bildsatz) - eine fruehere Fassung
|
||||
# dieses Skripts UND von display.py hat das mit "die Datei bleibt bei jedem Zustand
|
||||
# erhalten" verwechselt.
|
||||
#
|
||||
# LAST_MODE_FILE ist deshalb wie IMAGESET_FILE eine EIGENE, dauerhafte Ablage unter
|
||||
# /var/lib - dieselbe Datei, die display.py:LAST_MODE_FILE liest (Panel und CLI muessen
|
||||
# sich hier einig sein, sonst zeigt das eine "Rettung: MISSING" waehrend das andere
|
||||
# "Migration: 3 image(s)" meldet).
|
||||
LAST_MODE_FILE=${NINLIGHT_LAST_MODE_FILE:-/var/lib/ninlight-station/mode}
|
||||
|
||||
# Der zuletzt angeforderte Modus, oder "recovery" bei fehlender/unlesbarer/unbekannter
|
||||
# Datei - dieselbe Vorgabe und dieselbe Begruendung wie imageset_get() unten. Scheitert
|
||||
# nie: eine kaputte Datei darf weder "status" noch "bildsatz" aufhalten.
|
||||
current_mode() {
|
||||
_m=$(cat "$LAST_MODE_FILE" 2>/dev/null | tr -d ' \t\r\n') || true
|
||||
case "$_m" in
|
||||
recovery|migration) printf '%s' "$_m" ;;
|
||||
*) printf '%s' "recovery" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Bildsatz lesen, schreiben, benennen --------------------------------------------
|
||||
@@ -153,12 +178,27 @@ imageset_get() {
|
||||
esac
|
||||
}
|
||||
|
||||
# Das Verzeichnis zum Namen des Bildsatzes ($1).
|
||||
# Das Verzeichnis zum Namen des Bildsatzes ($1), fuer den Modus $2 (Vorgabe:
|
||||
# current_mode()). Rettung und Migration liegen in getrennten Verzeichnispaaren
|
||||
# (server.py:RESCUE_SET_DIRS/IMAGE_SET_DIRS begruendet das) - dieselbe Unterscheidung
|
||||
# wie display.py:_read_imageset(). Fixrunde 1, Befund 1: vor dieser Aenderung pruefte
|
||||
# dieses Skript hier IMMER die Migrationsverzeichnisse, auch im Rettungsbetrieb - ein
|
||||
# falsches "MISSING" dort verleitet dazu, auf mit-wlan umzuschalten, und DANN liefert
|
||||
# die Rettung tatsaechlich Abbilder mit dem WLAN-Passwort aus.
|
||||
imageset_dir() {
|
||||
case "$1" in
|
||||
mit-wlan) printf '%s' "$IMAGE_DIR/migrate-wlan" ;;
|
||||
*) printf '%s' "$IMAGE_DIR/migrate-nocreds" ;;
|
||||
esac
|
||||
_name=$1
|
||||
_mode=${2:-$(current_mode)}
|
||||
if [ "$_mode" = "recovery" ]; then
|
||||
case "$_name" in
|
||||
mit-wlan) printf '%s' "$IMAGE_DIR/rescue-wlan" ;;
|
||||
*) printf '%s' "$IMAGE_DIR/rescue-nocreds" ;;
|
||||
esac
|
||||
else
|
||||
case "$_name" in
|
||||
mit-wlan) printf '%s' "$IMAGE_DIR/migrate-wlan" ;;
|
||||
*) printf '%s' "$IMAGE_DIR/migrate-nocreds" ;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
imageset_label() {
|
||||
@@ -179,8 +219,14 @@ imageset_set() {
|
||||
sudo mv -f "$_tmp" "$IMAGESET_FILE"
|
||||
}
|
||||
|
||||
migrate_images() {
|
||||
find "$(imageset_dir "$(imageset_get)")" -maxdepth 1 -name '*.img' 2>/dev/null | sort
|
||||
# Die Abbilder des eingestellten Bildsatzes fuer den Modus $1 (Vorgabe: current_mode()).
|
||||
# Ersetzt das fruehere migrate_images() (nur Migration) UND das fruehere images() (immer
|
||||
# flach in $IMAGE_DIR, Fixrunde 1, Befund 2: nach dem Deploy-Umbau liegt dort nichts
|
||||
# mehr - recovery_on() meldete seither bei JEDEM Start faelschlich "answers everything
|
||||
# with 404", ununterscheidbar vom echten Fehlerfall).
|
||||
imageset_images() {
|
||||
_mode=${1:-$(current_mode)}
|
||||
find "$(imageset_dir "$(imageset_get)" "$_mode")" -maxdepth 1 -name '*.img' 2>/dev/null | sort
|
||||
}
|
||||
|
||||
# "bildsatz" ohne Argument: nur berichten. Mit Argument: umschalten.
|
||||
@@ -204,6 +250,9 @@ bildsatz_cmd() {
|
||||
}
|
||||
echo "Image set: $(imageset_label "$_want")"
|
||||
[ "$_now" = "$_want" ] && echo " (was already set)"
|
||||
# Der Umschalter gilt fuer BEIDE Betriebsarten - hier wird deshalb der Satz gemeldet,
|
||||
# der fuer den Modus zaehlt, in dem die Station gerade steht bzw. als naechstes
|
||||
# anlaufen wuerde (current_mode()), nicht pauschal die Migration.
|
||||
_dir=$(imageset_dir "$_want")
|
||||
if [ "$(find "$_dir" -maxdepth 1 -name '*.img' 2>/dev/null | wc -l | tr -d ' ')" -eq 0 ]; then
|
||||
# Kein stiller Rueckfall auf den anderen Satz - server.py liefert dann gar nichts
|
||||
@@ -212,18 +261,20 @@ bildsatz_cmd() {
|
||||
echo "Warning: $_dir missing or empty - this image set serves NOTHING. Run tools/station/deploy.sh again." >&2
|
||||
fi
|
||||
if [ "$_want" = "mit-wlan" ]; then
|
||||
echo "Caution: migrated lamps join the Wi-Fi from config.local.cmake right away - including lamps that are not yours and got picked up in automatic mode." >&2
|
||||
echo "Caution: any lamp migrated OR rescued while this is set joins the Wi-Fi from config.local.cmake right away - including lamps that are not yours and got picked up in automatic mode." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# Die zwei Zeilen, die "status" und "bildsatz" ohne Argument gemeinsam ausgeben.
|
||||
# Die zwei Zeilen, die "status" und "bildsatz" ohne Argument gemeinsam ausgeben - fuer
|
||||
# den Modus, in dem die Station gerade steht bzw. als naechstes anlaufen wuerde.
|
||||
imageset_status_lines() {
|
||||
_mode=$(current_mode)
|
||||
_set=$(imageset_get)
|
||||
_dir=$(imageset_dir "$_set")
|
||||
_dir=$(imageset_dir "$_set" "$_mode")
|
||||
# "Vorhanden" heisst: mindestens ein Image darin - dieselbe Regel wie
|
||||
# server.py:migrate_set_present() und display.py:_read_imageset(). Ein leeres
|
||||
# Verzeichnis liefert genauso nichts aus wie ein fehlendes.
|
||||
_n=$(migrate_images | wc -l | tr -d ' ')
|
||||
# server.py:migrate_set_present()/rescue_set_present() und display.py:_read_imageset().
|
||||
# Ein leeres Verzeichnis liefert genauso nichts aus wie ein fehlendes.
|
||||
_n=$(imageset_images "$_mode" | wc -l | tr -d ' ')
|
||||
if [ "$_n" -gt 0 ]; then
|
||||
_state="$_n image(s)"
|
||||
else
|
||||
@@ -293,12 +344,22 @@ ap_switch() {
|
||||
}
|
||||
|
||||
# Schreibt $RUN_DIR/mode atomar mit 0644 (Temp-Datei im selben Verzeichnis, dann
|
||||
# umbenennen) - server.py liest sie bei jedem Dienststart per --mode-file.
|
||||
# umbenennen) - server.py liest sie bei jedem Dienststart per --mode-file. ZUSAETZLICH
|
||||
# dieselbe Zeichenkette nach $LAST_MODE_FILE (dauerhaft, siehe dort) - RUN_DIR/mode
|
||||
# ueberlebt nur einen "systemctl restart", nicht das "systemctl stop" von
|
||||
# "ninlight-station off" (Fixrunde 1, Befund 3). Beide Schreibvorgaenge muessen
|
||||
# gelingen: schlaegt der dauerhafte fehl, wuerden Panel und CLI nach einem "off" auf
|
||||
# den falschen (naemlich den vorherigen) Modus zurueckfallen, ohne dass das hier
|
||||
# auffiele.
|
||||
write_mode() {
|
||||
sudo mkdir -p "$RUN_DIR"
|
||||
_tmp="$RUN_DIR/.mode-$$"
|
||||
printf '%s' "$1" | sudo tee "$_tmp" >/dev/null && sudo chmod 0644 "$_tmp" || return 1
|
||||
sudo mv -f "$_tmp" "$RUN_DIR/mode"
|
||||
sudo mv -f "$_tmp" "$RUN_DIR/mode" || return 1
|
||||
sudo mkdir -p "$(dirname "$LAST_MODE_FILE")"
|
||||
_tmp2="$(dirname "$LAST_MODE_FILE")/.mode-$$"
|
||||
printf '%s' "$1" | sudo tee "$_tmp2" >/dev/null && sudo chmod 0644 "$_tmp2" || return 1
|
||||
sudo mv -f "$_tmp2" "$LAST_MODE_FILE"
|
||||
}
|
||||
|
||||
# Schreibt $RUN_DIR/control.json atomar mit 0644 - dasselbe Muster (Temp-Datei im
|
||||
@@ -612,8 +673,12 @@ autooff_arm_if_requested() {
|
||||
recovery_on() {
|
||||
parse_for_option recovery "$@"
|
||||
need_profile "$AP_CONNECTION"
|
||||
n=$(images | wc -l | tr -d ' ')
|
||||
[ "$n" -gt 0 ] || echo "Warning: $IMAGE_DIR holds no image - the station answers everything with 404" >&2
|
||||
# Explizit "recovery" statt current_mode(): dieser Aufruf ENTSCHEIDET gerade, dass
|
||||
# der naechste Start Rettung ist - write_mode() darunter schreibt das erst gleich.
|
||||
# current_mode() koennte hier noch "migration" von einem vorherigen Lauf zeigen.
|
||||
_setdir=$(imageset_dir "$(imageset_get)" recovery)
|
||||
n=$(imageset_images recovery | wc -l | tr -d ' ')
|
||||
[ "$n" -gt 0 ] || echo "Warning: $_setdir holds no image - the station answers everything with 404" >&2
|
||||
ap_switch "$AP_CONNECTION"
|
||||
write_mode "recovery"
|
||||
start_and_verify "$AP_CONNECTION" "recovery"
|
||||
@@ -656,8 +721,10 @@ migrate_on() {
|
||||
[ "$_for_seen" -eq 1 ] || _for_minutes=""
|
||||
need_profile "$MIGRATE_AP_CONNECTION"
|
||||
_set=$(imageset_get)
|
||||
_setdir=$(imageset_dir "$_set")
|
||||
n=$(migrate_images | wc -l | tr -d ' ')
|
||||
# Explizit "migration", aus demselben Grund wie in recovery_on(): dieser Aufruf legt
|
||||
# den naechsten Modus gerade erst fest.
|
||||
_setdir=$(imageset_dir "$_set" migration)
|
||||
n=$(imageset_images migration | wc -l | tr -d ' ')
|
||||
[ "$n" -gt 0 ] || echo "Warning: $_setdir holds no migration images - the station answers everything with 404" >&2
|
||||
# Faehrt ninlight-recovery (falls es laeuft) herunter, BEVOR qconnex-firmware
|
||||
# hochkommt, und prueft danach nach, dass wirklich nur eines aktiv ist.
|
||||
@@ -1052,8 +1119,12 @@ PY
|
||||
autooff_status_line
|
||||
printf 'wlan0 : %s\n' "$(nmcli -t --escape no -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2-)"
|
||||
printf 'Address : %s\n' "$(ip -4 -br addr show wlan0 2>/dev/null | awk '{print $3}')"
|
||||
# Die Rettungsabbilder des eingestellten Bildsatzes - unabhaengig von $_modus (der
|
||||
# Migrationsbildsatz hat kein passendes Trailer-Format). Fixrunde 1, Befund 2:
|
||||
# frueher stand hier "images" (flach in $IMAGE_DIR) - dort liegt seit dem
|
||||
# Deploy-Umbau nichts mehr.
|
||||
echo "Images :"
|
||||
images | while read -r f; do
|
||||
imageset_images recovery | while read -r f; do
|
||||
printf ' %-34s %s\n' "$(basename "$f")" \
|
||||
"$(python3 - "$f" <<'PY'
|
||||
import pathlib, sys
|
||||
@@ -1092,7 +1163,7 @@ display_cmd() {
|
||||
usage() {
|
||||
echo "Usage: ninlight-station on [--for <minutes>]|recovery {on [--for <minutes>]|off}|migrate {on [--listen] [--for <minutes>]|off}|arm [<target>]|listen|bildsatz [ohne-wlan|mit-wlan]|renew [<minutes>]|hold|display {test|clear|off}|off|status" >&2
|
||||
echo "" >&2
|
||||
echo " bildsatz Switch: which set of migration images is served." >&2
|
||||
echo " bildsatz Switch: which set of recovery/migration images is served." >&2
|
||||
echo " Without an argument it only reports. 'ohne-wlan' (default) serves" >&2
|
||||
echo " the builds from tools/build_nocreds.sh - the migrated lamp comes" >&2
|
||||
echo " up in its own onboarding access point. 'mit-wlan' serves the" >&2
|
||||
|
||||
Reference in New Issue
Block a user