fix: Rechte-Bug und Passwort-Leck im NM-Profil, Loesch-Bug in deploy.sh
setup_pi.sh sourcte /etc/ninlight-station.conf (0600 root:root) als unprivilegierter Benutzer und scheiterte damit bei jedem Lauf, bevor das NetworkManager-Profil angelegt wurde. Die Konfiguration wird jetzt per "sudo cat" gelesen; ninlight-station macht denselben Fallback fuer den dokumentierten Aufruf als normaler Benutzer, ohne die Datei fuer alle lesbar zu machen. Das AP-Profil wird nicht mehr per "nmcli ... wifi-sec.psk $PSK" angelegt (das WLAN-Passwort waere sonst fuer jeden lokalen Prozess in der Kommandozeile sichtbar), sondern als NetworkManager-Keyfile (0600 root:root) geschrieben und per "nmcli connection load" eingelesen. deploy.sh loeschte bei einem gezielten Deploy eines einzelnen Geraetetyps per "rsync --delete" alle Images anderer Geraetetypen aus dem live ausgelieferten Verzeichnis. --delete laeuft jetzt nur noch beim Vollabgleich (kein target-Argument); ein gezielter Deploy ersetzt nur die genannten Dateien. Dabei zusaetzlich -c (Checksumme statt Groesse+Zeitstempel) ergaenzt, sonst uebersieht rsync ein neues Image mit zufaellig gleicher Byte-Groesse. Ausserdem meldet deploy.sh jetzt einen fehlgeschlagenen Dienst-Neustart als Fehler statt ihn mit "Dienst laeuft nicht" zu verwechseln. Stub-Tests unter tools/station/tests/test_deploy.sh (ssh/rsync im PATH ersetzt, Installationsschritt laeuft gegen ein Sandbox-Verzeichnis) decken beide Bugfixes sowie die bereits bestehenden Faelle ab: Image besteht die Trailer-Pruefung nicht, keine Images gefunden. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
fda732d6c4
commit
d23b0d4e02
+49
-8
@@ -12,12 +12,17 @@ MKIMAGE="$ROOT/tools/mkimage/nl_mkimage.py"
|
|||||||
|
|
||||||
declare -a FILES=()
|
declare -a FILES=()
|
||||||
if [ $# -gt 0 ]; then
|
if [ $# -gt 0 ]; then
|
||||||
|
# Gezielter Deploy: nur die genannten Geraetetypen werden ersetzt, alle
|
||||||
|
# anderen Images im Zielverzeichnis bleiben unangetastet (siehe FULL_SYNC
|
||||||
|
# unten).
|
||||||
|
FULL_SYNC=0
|
||||||
for t in "$@"; do
|
for t in "$@"; do
|
||||||
f="$ROOT/build/$t/ninlight_${t}_ota.img"
|
f="$ROOT/build/$t/ninlight_${t}_ota.img"
|
||||||
[ -f "$f" ] || { echo "Fehler: $f fehlt - erst bauen" >&2; exit 1; }
|
[ -f "$f" ] || { echo "Fehler: $f fehlt - erst bauen" >&2; exit 1; }
|
||||||
FILES+=("$f")
|
FILES+=("$f")
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
|
FULL_SYNC=1
|
||||||
while IFS= read -r f; do FILES+=("$f"); done < <(find "$ROOT/build" -maxdepth 2 -name 'ninlight_*_ota.img' | sort)
|
while IFS= read -r f; do 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; }
|
[ ${#FILES[@]} -gt 0 ] || { echo "Fehler: keine Images unter $ROOT/build gefunden" >&2; exit 1; }
|
||||||
fi
|
fi
|
||||||
@@ -40,16 +45,52 @@ for f in "${FILES[@]}"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
echo "== uebertragen =="
|
echo "== uebertragen =="
|
||||||
rsync -a --delete "$STAGE/" "$HOST:/tmp/ninlight-images/"
|
# -c (Inhaltsvergleich per Checksumme statt Groesse+Zeitstempel): ein neues
|
||||||
|
# Image kann zufaellig dieselbe Byte-Groesse wie das alte haben, und bei
|
||||||
|
# schnell aufeinanderfolgenden Deploys reicht rsyncs Sekundenaufloesung fuer
|
||||||
|
# den Zeitstempel nicht, um das als Aenderung zu erkennen. Ohne -c wuerde
|
||||||
|
# rsync ein solches Update dann stillschweigend ueberspringen.
|
||||||
|
#
|
||||||
|
# /tmp/ninlight-images auf dem Pi ist nur eine fluechtige Ablage fuer diesen
|
||||||
|
# Lauf - hier darf --delete unbedingt ran, das betrifft nicht das live
|
||||||
|
# ausgelieferte Verzeichnis.
|
||||||
|
rsync -a -c --delete "$STAGE/" "$HOST:/tmp/ninlight-images/"
|
||||||
rsync -a "$HERE/server.py" "$HERE/ninlight-station" "$HERE/ninlight-station.service" "$HOST:/tmp/"
|
rsync -a "$HERE/server.py" "$HERE/ninlight-station" "$HERE/ninlight-station.service" "$HOST:/tmp/"
|
||||||
ssh "$HOST" 'set -e
|
# Pfade als Variablen mit Default: so kann ein Test die Installation gegen
|
||||||
sudo install -d -m 0755 /opt/ninlight-station/images
|
# ein Sandbox-Verzeichnis statt gegen echte Systempfade laufen lassen.
|
||||||
sudo rsync -a --delete /tmp/ninlight-images/ /opt/ninlight-station/images/
|
ssh "$HOST" bash -s -- "$FULL_SYNC" <<'REMOTE'
|
||||||
sudo install -m 0755 /tmp/server.py /opt/ninlight-station/server.py
|
set -e
|
||||||
sudo install -m 0755 /tmp/ninlight-station /usr/local/bin/ninlight-station
|
FULL_SYNC=$1
|
||||||
sudo install -m 0644 /tmp/ninlight-station.service /etc/systemd/system/ninlight-station.service
|
ROOT_DIR=${NINLIGHT_STATION_ROOT:-/opt/ninlight-station}
|
||||||
|
BIN_PATH=${NINLIGHT_STATION_BIN:-/usr/local/bin/ninlight-station}
|
||||||
|
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"
|
||||||
|
sudo rsync -a -c --delete /tmp/ninlight-images/ "$ROOT_DIR/images/"
|
||||||
|
else
|
||||||
|
# Gezielter Deploy: nur die uebertragenen Dateien ersetzen/ergaenzen, alle
|
||||||
|
# anderen Geraetetypen im Zielverzeichnis bleiben erhalten (kein --delete).
|
||||||
|
echo " gezielter Deploy - andere Geraetetypen im Zielverzeichnis bleiben erhalten"
|
||||||
|
sudo rsync -a -c /tmp/ninlight-images/ "$ROOT_DIR/images/"
|
||||||
|
fi
|
||||||
|
sudo install -m 0755 /tmp/server.py "$ROOT_DIR/server.py"
|
||||||
|
sudo install -m 0755 /tmp/ninlight-station "$BIN_PATH"
|
||||||
|
sudo install -m 0644 /tmp/ninlight-station.service "$UNIT_PATH"
|
||||||
rm -rf /tmp/ninlight-images /tmp/server.py /tmp/ninlight-station /tmp/ninlight-station.service
|
rm -rf /tmp/ninlight-images /tmp/server.py /tmp/ninlight-station /tmp/ninlight-station.service
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
systemctl is-active --quiet ninlight-station && { sudo systemctl restart ninlight-station; echo " Dienst neu gestartet"; } || echo " Dienst laeuft nicht (Station ist aus)"'
|
if systemctl is-active --quiet ninlight-station; then
|
||||||
|
if sudo systemctl restart ninlight-station; then
|
||||||
|
echo " Dienst neu gestartet"
|
||||||
|
else
|
||||||
|
echo " Fehler: Dienst lief, Neustart nach dem Deploy ist aber fehlgeschlagen" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " Dienst laeuft nicht (Station ist aus)"
|
||||||
|
fi
|
||||||
|
REMOTE
|
||||||
|
|
||||||
echo "fertig."
|
echo "fertig."
|
||||||
|
|||||||
@@ -9,9 +9,19 @@
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
CONF=/etc/ninlight-station.conf
|
CONF=/etc/ninlight-station.conf
|
||||||
[ -r "$CONF" ] || { echo "Fehler: $CONF fehlt - zuerst tools/station/setup_pi.sh ausfuehren" >&2; exit 1; }
|
if [ -r "$CONF" ]; then
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
. "$CONF"
|
. "$CONF"
|
||||||
|
elif [ -e "$CONF" ]; then
|
||||||
|
# $CONF ist 0600 root:root, damit das Passwort nicht fuer jeden lesbar
|
||||||
|
# ist. Der dokumentierte Aufruf "ssh <pi-host> ninlight-station on" laeuft
|
||||||
|
# aber als normaler Benutzer - "sudo cat" liest die Datei ein, ohne ihre
|
||||||
|
# Rechte aufzuweichen.
|
||||||
|
eval "$(sudo cat "$CONF")"
|
||||||
|
else
|
||||||
|
echo "Fehler: $CONF fehlt - zuerst tools/station/setup_pi.sh ausfuehren" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
for _key in SSID PSK IMAGE_DIR HOME_CONNECTION AP_CONNECTION; do
|
for _key in SSID PSK IMAGE_DIR HOME_CONNECTION AP_CONNECTION; do
|
||||||
eval "test -n \"\${$_key-}\"" || {
|
eval "test -n \"\${$_key-}\"" || {
|
||||||
|
|||||||
+53
-16
@@ -37,23 +37,60 @@ ssh "$HOST" 'set -e
|
|||||||
echo " installiert"'
|
echo " installiert"'
|
||||||
|
|
||||||
echo "== NetworkManager-Profil =="
|
echo "== NetworkManager-Profil =="
|
||||||
ssh "$HOST" 'set -e
|
# Zwei Dinge, die man an einer echten Lampenstation nicht falsch machen darf:
|
||||||
. /etc/ninlight-station.conf
|
# - /etc/ninlight-station.conf ist 0600 root:root (das Passwort soll nicht
|
||||||
if nmcli -t -f NAME con show | grep -qx "$AP_CONNECTION"; then
|
# jeder lesen koennen). Der SSH-Benutzer ist aber nicht root, direktes
|
||||||
sudo nmcli con mod "$AP_CONNECTION" \
|
# ". /etc/ninlight-station.conf" wuerde also mit "Permission denied"
|
||||||
802-11-wireless.ssid "$SSID" wifi-sec.psk "$PSK" \
|
# abbrechen. "sudo cat" + eval liest sie dennoch ein, ohne die Rechte der
|
||||||
ipv4.addresses 192.168.8.1/24 ipv4.method shared \
|
# Datei aufzuweichen.
|
||||||
connection.autoconnect no
|
# - "nmcli ... wifi-sec.psk $PSK" wuerde das Passwort als Kommandozeilen-
|
||||||
echo " Profil $AP_CONNECTION aktualisiert"
|
# argument an einen Prozess uebergeben - fuer jeden lokalen Benutzer per
|
||||||
|
# "ps"/"/proc/<pid>/cmdline" sichtbar. Deshalb wird das Verbindungsprofil
|
||||||
|
# stattdessen direkt als NetworkManager-Keyfile (0600 root:root)
|
||||||
|
# geschrieben; das Passwort landet nur in einer Root-Datei, nie in einer
|
||||||
|
# Prozessliste.
|
||||||
|
ssh "$HOST" bash -s <<'REMOTE'
|
||||||
|
set -e
|
||||||
|
eval "$(sudo cat /etc/ninlight-station.conf)"
|
||||||
|
CONN_FILE="/etc/NetworkManager/system-connections/${AP_CONNECTION}.nmconnection"
|
||||||
|
if sudo test -f "$CONN_FILE"; then
|
||||||
|
UUID=$(sudo sed -n 's/^uuid=//p' "$CONN_FILE" | head -n1)
|
||||||
|
ACTION="aktualisiert"
|
||||||
else
|
else
|
||||||
sudo nmcli con add type wifi ifname wlan0 con-name "$AP_CONNECTION" ssid "$SSID" \
|
UUID=$(cat /proc/sys/kernel/random/uuid)
|
||||||
802-11-wireless.mode ap 802-11-wireless.band bg 802-11-wireless.channel 6 \
|
ACTION="angelegt"
|
||||||
wifi-sec.key-mgmt wpa-psk wifi-sec.proto rsn wifi-sec.pairwise ccmp wifi-sec.group ccmp \
|
fi
|
||||||
wifi-sec.psk "$PSK" \
|
TMP=$(mktemp)
|
||||||
ipv4.method shared ipv4.addresses 192.168.8.1/24 ipv6.method disabled \
|
trap 'rm -f "$TMP"' EXIT
|
||||||
connection.autoconnect no >/dev/null
|
{
|
||||||
echo " Profil $AP_CONNECTION angelegt"
|
printf '%s\n' '[connection]'
|
||||||
fi'
|
printf 'id=%s\n' "$AP_CONNECTION"
|
||||||
|
printf 'uuid=%s\n' "$UUID"
|
||||||
|
printf '%s\n' 'type=wifi'
|
||||||
|
printf '%s\n' 'interface-name=wlan0'
|
||||||
|
printf '%s\n' 'autoconnect=false'
|
||||||
|
printf '\n%s\n' '[wifi]'
|
||||||
|
printf '%s\n' 'mode=ap'
|
||||||
|
printf 'ssid=%s\n' "$SSID"
|
||||||
|
printf '%s\n' 'band=bg'
|
||||||
|
printf '%s\n' 'channel=6'
|
||||||
|
printf '\n%s\n' '[wifi-security]'
|
||||||
|
printf '%s\n' 'key-mgmt=wpa-psk'
|
||||||
|
printf '%s\n' 'proto=rsn'
|
||||||
|
printf '%s\n' 'pairwise=ccmp;'
|
||||||
|
printf '%s\n' 'group=ccmp;'
|
||||||
|
printf 'psk=%s\n' "$PSK"
|
||||||
|
printf '\n%s\n' '[ipv4]'
|
||||||
|
printf '%s\n' 'method=shared'
|
||||||
|
printf '%s\n' 'address1=192.168.8.1/24'
|
||||||
|
printf '\n%s\n' '[ipv6]'
|
||||||
|
printf '%s\n' 'method=disabled'
|
||||||
|
} >"$TMP"
|
||||||
|
sudo install -o root -g root -m 0600 "$TMP" "$CONN_FILE"
|
||||||
|
rm -f "$TMP"
|
||||||
|
sudo nmcli connection load "$CONN_FILE" >/dev/null
|
||||||
|
echo " Profil $AP_CONNECTION $ACTION"
|
||||||
|
REMOTE
|
||||||
|
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
|
|
||||||
|
|||||||
Executable
+259
@@ -0,0 +1,259 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Stub-Tests fuer deploy.sh - ohne Pi ausfuehrbar.
|
||||||
|
#
|
||||||
|
# ssh/rsync werden im PATH durch Stubs ersetzt: ssh fuehrt das per Heredoc
|
||||||
|
# uebergebene Remote-Skript lokal aus (statt es an einen echten Pi zu
|
||||||
|
# schicken), rsync uebersetzt "host:pfad"-Ziele auf den blossen lokalen Pfad
|
||||||
|
# und ruft dann den echten rsync auf. So laeuft die komplette Logik von
|
||||||
|
# deploy.sh - inklusive des Installationsschritts, der normalerweise per SSH
|
||||||
|
# auf dem Pi passiert - tatsaechlich, aber vollstaendig gegen ein Sandbox-
|
||||||
|
# Verzeichnis (NINLIGHT_STATION_ROOT/…) statt gegen echte Systempfade.
|
||||||
|
#
|
||||||
|
# Aufruf: tools/station/tests/test_deploy.sh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
STATION_DIR=$(cd "$HERE/.." && pwd)
|
||||||
|
REAL_RSYNC=$(command -v rsync)
|
||||||
|
|
||||||
|
TMPROOT=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$TMPROOT"' EXIT
|
||||||
|
|
||||||
|
FAILED=0
|
||||||
|
pass() { echo "ok - $1"; }
|
||||||
|
fail() { echo "FEHLER - $1" >&2; FAILED=1; }
|
||||||
|
|
||||||
|
# --- Sandbox-Repo aufbauen: tools/station/deploy.sh + tools/mkimage/nl_mkimage.py + build/ ---
|
||||||
|
setup_sandbox() {
|
||||||
|
local sandbox=$1
|
||||||
|
rm -rf "$sandbox"
|
||||||
|
mkdir -p "$sandbox/tools/station" "$sandbox/tools/mkimage" "$sandbox/build"
|
||||||
|
cp "$STATION_DIR/deploy.sh" "$sandbox/tools/station/deploy.sh"
|
||||||
|
chmod +x "$sandbox/tools/station/deploy.sh"
|
||||||
|
# Inhalt irrelevant, die Dateien muessen nur existieren (werden "uebertragen").
|
||||||
|
echo "# dummy" >"$sandbox/tools/station/server.py"
|
||||||
|
echo "# dummy" >"$sandbox/tools/station/ninlight-station"
|
||||||
|
echo "# dummy" >"$sandbox/tools/station/ninlight-station.service"
|
||||||
|
|
||||||
|
# Fake nl_mkimage.py --verify: verhaelt sich wie das echte Tool (eine Zeile
|
||||||
|
# "<geraet> <version> <bytes>" auf stdout bei Erfolg, Exit 0; eine Zeile auf
|
||||||
|
# stderr bei Fehlschlag, Exit 1), aber steuerbar per Umgebungsvariable
|
||||||
|
# MKIMAGE_FAIL_SUBSTR: enthaelt der zu pruefende Dateiname diesen Teilstring,
|
||||||
|
# schlaegt die Pruefung fehl.
|
||||||
|
cat >"$sandbox/tools/mkimage/nl_mkimage.py" <<'PY'
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
args = sys.argv[1:]
|
||||||
|
f = args[args.index("--verify") + 1]
|
||||||
|
target = args[args.index("--expect-device") + 1]
|
||||||
|
fail_substr = os.environ.get("MKIMAGE_FAIL_SUBSTR", "")
|
||||||
|
if fail_substr and fail_substr in f:
|
||||||
|
print(f"Fehler: {f} besteht die Trailer-Pruefung nicht (Test-Stub)", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
size = os.path.getsize(f)
|
||||||
|
print(f"{target} 1.0.0 {size}")
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Stub-Kommandos fuer ssh/rsync im PATH ---
|
||||||
|
setup_stubbin() {
|
||||||
|
local bindir=$1 log=$2
|
||||||
|
mkdir -p "$bindir"
|
||||||
|
|
||||||
|
cat >"$bindir/ssh" <<EOF
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
echo "STUB ssh \$*" >>"$log"
|
||||||
|
host=\$1; shift
|
||||||
|
"\$@"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >"$bindir/rsync" <<EOF
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
echo "STUB rsync \$*" >>"$log"
|
||||||
|
args=()
|
||||||
|
for a in "\$@"; do
|
||||||
|
case "\$a" in
|
||||||
|
-*) args+=("\$a") ;;
|
||||||
|
*:*) args+=("\${a#*:}") ;;
|
||||||
|
*) args+=("\$a") ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
exec "$REAL_RSYNC" "\${args[@]}"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >"$bindir/scp" <<EOF
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
echo "STUB scp \$* - deploy.sh sollte scp nicht aufrufen" >>"$log"
|
||||||
|
exit 1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >"$bindir/sudo" <<EOF
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
echo "STUB sudo \$*" >>"$log"
|
||||||
|
exec "\$@"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >"$bindir/systemctl" <<EOF
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
echo "STUB systemctl \$*" >>"$log"
|
||||||
|
case "\$1" in
|
||||||
|
is-active) exit "\${FAKE_SYSTEMCTL_ACTIVE_EXIT:-1}" ;;
|
||||||
|
restart) exit "\${FAKE_SYSTEMCTL_RESTART_EXIT:-0}" ;;
|
||||||
|
*) exit 0 ;;
|
||||||
|
esac
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x "$bindir"/ssh "$bindir"/rsync "$bindir"/scp "$bindir"/sudo "$bindir"/systemctl
|
||||||
|
}
|
||||||
|
|
||||||
|
run_deploy() {
|
||||||
|
# Fuehrt deploy.sh mit stubbtem PATH aus; Ausgabe landet in $OUT, Exit-Code in $?.
|
||||||
|
local sandbox=$1; shift
|
||||||
|
# Auf dem echten Pi existieren /usr/local/bin und /etc/systemd/system schon;
|
||||||
|
# in der Sandbox muessen sie fuer "install" eigens angelegt werden.
|
||||||
|
mkdir -p "$SANDBOX_STATE/usr/local/bin" "$SANDBOX_STATE/etc/systemd/system"
|
||||||
|
PATH="$STUBBIN:$PATH" \
|
||||||
|
NINLIGHT_STATION_ROOT="$SANDBOX_STATE/opt/ninlight-station" \
|
||||||
|
NINLIGHT_STATION_BIN="$SANDBOX_STATE/usr/local/bin/ninlight-station" \
|
||||||
|
NINLIGHT_STATION_UNIT="$SANDBOX_STATE/etc/systemd/system/ninlight-station.service" \
|
||||||
|
"$sandbox/tools/station/deploy.sh" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== Szenario 1: Image besteht die Trailer-Pruefung nicht -> nichts uebertragen ==="
|
||||||
|
SANDBOX="$TMPROOT/s1"; STUBBIN="$TMPROOT/bin1"; LOG="$TMPROOT/s1.log"; SANDBOX_STATE="$TMPROOT/s1-state"
|
||||||
|
setup_sandbox "$SANDBOX"
|
||||||
|
setup_stubbin "$STUBBIN" "$LOG"
|
||||||
|
mkdir -p "$SANDBOX/build/foo"
|
||||||
|
echo "dummy" >"$SANDBOX/build/foo/ninlight_foo_ota.img"
|
||||||
|
: >"$LOG"
|
||||||
|
set +e
|
||||||
|
OUT=$(MKIMAGE_FAIL_SUBSTR=foo run_deploy "$SANDBOX" pi-test foo 2>&1)
|
||||||
|
RC=$?
|
||||||
|
set -e
|
||||||
|
if [ "$RC" -ne 0 ]; then pass "Exit-Code != 0 ($RC)"; else fail "Exit-Code war 0"; fi
|
||||||
|
if echo "$OUT" | grep -q "besteht die Trailer-Pruefung nicht"; then
|
||||||
|
pass "Fehlermeldung zur Trailer-Pruefung vorhanden"
|
||||||
|
else
|
||||||
|
fail "Fehlermeldung zur Trailer-Pruefung fehlt"
|
||||||
|
fi
|
||||||
|
if ! grep -q "STUB ssh\|STUB rsync\|STUB scp" "$LOG"; then
|
||||||
|
pass "kein ssh/rsync/scp aufgerufen - nichts wurde uebertragen"
|
||||||
|
else
|
||||||
|
fail "ssh/rsync/scp wurde trotz fehlgeschlagener Pruefung aufgerufen: $(cat "$LOG")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== Szenario 2: keine Images unter build/ gefunden ==="
|
||||||
|
SANDBOX="$TMPROOT/s2"; STUBBIN="$TMPROOT/bin2"; LOG="$TMPROOT/s2.log"; SANDBOX_STATE="$TMPROOT/s2-state"
|
||||||
|
setup_sandbox "$SANDBOX"
|
||||||
|
setup_stubbin "$STUBBIN" "$LOG"
|
||||||
|
: >"$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"; fi
|
||||||
|
if echo "$OUT" | grep -q "keine Images unter"; then
|
||||||
|
pass "Fehlermeldung zu fehlenden Images vorhanden"
|
||||||
|
else
|
||||||
|
fail "Fehlermeldung zu fehlenden Images fehlt"
|
||||||
|
fi
|
||||||
|
if ! grep -q "STUB" "$LOG" 2>/dev/null; then
|
||||||
|
pass "kein Transfer-Kommando aufgerufen"
|
||||||
|
else
|
||||||
|
fail "ein Transfer-Kommando wurde trotz fehlender Images aufgerufen: $(cat "$LOG")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== Szenario 3: gezielter Deploy eines Geraetetyps laesst andere Images auf dem Ziel unangetastet (Critical 2) ==="
|
||||||
|
SANDBOX="$TMPROOT/s3"; STUBBIN="$TMPROOT/bin3"; LOG="$TMPROOT/s3.log"; SANDBOX_STATE="$TMPROOT/s3-state"
|
||||||
|
setup_sandbox "$SANDBOX"
|
||||||
|
setup_stubbin "$STUBBIN" "$LOG"
|
||||||
|
mkdir -p "$SANDBOX/build/foo" "$SANDBOX/build/bar"
|
||||||
|
echo "foo-image-neu" >"$SANDBOX/build/foo/ninlight_foo_ota.img"
|
||||||
|
echo "bar-image" >"$SANDBOX/build/bar/ninlight_bar_ota.img"
|
||||||
|
# Zielverzeichnis simuliert einen vorherigen Voll-Deploy: Images fuer foo UND bar liegen schon da.
|
||||||
|
mkdir -p "$SANDBOX_STATE/opt/ninlight-station/images"
|
||||||
|
echo "foo-image-alt" >"$SANDBOX_STATE/opt/ninlight-station/images/ninlight_foo_ota.img"
|
||||||
|
echo "bar-image" >"$SANDBOX_STATE/opt/ninlight-station/images/ninlight_bar_ota.img"
|
||||||
|
: >"$LOG"
|
||||||
|
set +e
|
||||||
|
OUT=$(run_deploy "$SANDBOX" pi-test foo 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 "andere Geraetetypen im Zielverzeichnis bleiben erhalten"; then
|
||||||
|
pass "Ausgabe kuendigt gezielten Deploy ohne --delete an"
|
||||||
|
else
|
||||||
|
fail "Ausgabe erwaehnt den gezielten Deploy nicht"
|
||||||
|
fi
|
||||||
|
if [ -f "$SANDBOX_STATE/opt/ninlight-station/images/ninlight_bar_ota.img" ]; then
|
||||||
|
pass "Image des NICHT ausgewaehlten Geraetetyps (bar) blieb erhalten"
|
||||||
|
else
|
||||||
|
fail "Image des nicht ausgewaehlten Geraetetyps (bar) wurde geloescht - Critical 2 nicht behoben"
|
||||||
|
fi
|
||||||
|
if [ -f "$SANDBOX_STATE/opt/ninlight-station/images/ninlight_foo_ota.img" ] \
|
||||||
|
&& [ "$(cat "$SANDBOX_STATE/opt/ninlight-station/images/ninlight_foo_ota.img")" = "foo-image-neu" ]; then
|
||||||
|
pass "Image des ausgewaehlten Geraetetyps (foo) wurde aktualisiert"
|
||||||
|
else
|
||||||
|
fail "Image des ausgewaehlten Geraetetyps (foo) wurde nicht aktualisiert"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== Szenario 4: Voll-Deploy (kein target) entfernt veraltete Images - zur Abgrenzung von Szenario 3 ==="
|
||||||
|
SANDBOX="$TMPROOT/s4"; STUBBIN="$TMPROOT/bin4"; LOG="$TMPROOT/s4.log"; SANDBOX_STATE="$TMPROOT/s4-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"
|
||||||
|
: >"$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 [ ! -f "$SANDBOX_STATE/opt/ninlight-station/images/ninlight_veraltet_ota.img" ]; then
|
||||||
|
pass "veraltetes Image wurde beim Voll-Deploy entfernt (--delete wirkt weiterhin, wenn gewollt)"
|
||||||
|
else
|
||||||
|
fail "veraltetes Image wurde beim Voll-Deploy NICHT entfernt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== Szenario 5: Dienst laeuft, Neustart nach dem Deploy schlaegt fehl -> Exit != 0 (Minor) ==="
|
||||||
|
SANDBOX="$TMPROOT/s5"; STUBBIN="$TMPROOT/bin5"; LOG="$TMPROOT/s5.log"; SANDBOX_STATE="$TMPROOT/s5-state"
|
||||||
|
setup_sandbox "$SANDBOX"
|
||||||
|
setup_stubbin "$STUBBIN" "$LOG"
|
||||||
|
mkdir -p "$SANDBOX/build/foo" "$SANDBOX_STATE/usr/local/bin" "$SANDBOX_STATE/etc/systemd/system"
|
||||||
|
echo "foo-image" >"$SANDBOX/build/foo/ninlight_foo_ota.img"
|
||||||
|
: >"$LOG"
|
||||||
|
set +e
|
||||||
|
OUT=$(FAKE_SYSTEMCTL_ACTIVE_EXIT=0 FAKE_SYSTEMCTL_RESTART_EXIT=1 \
|
||||||
|
PATH="$STUBBIN:$PATH" \
|
||||||
|
NINLIGHT_STATION_ROOT="$SANDBOX_STATE/opt/ninlight-station" \
|
||||||
|
NINLIGHT_STATION_BIN="$SANDBOX_STATE/usr/local/bin/ninlight-station" \
|
||||||
|
NINLIGHT_STATION_UNIT="$SANDBOX_STATE/etc/systemd/system/ninlight-station.service" \
|
||||||
|
"$SANDBOX/tools/station/deploy.sh" pi-test foo 2>&1)
|
||||||
|
RC=$?
|
||||||
|
set -e
|
||||||
|
if [ "$RC" -ne 0 ]; then pass "Exit-Code != 0, wenn der Neustart fehlschlaegt ($RC)"; else fail "Exit-Code war 0, obwohl der Neustart fehlschlug"; fi
|
||||||
|
if echo "$OUT" | grep -q "Neustart nach dem Deploy ist aber fehlgeschlagen"; then
|
||||||
|
pass "Fehlermeldung unterscheidet Neustart-Fehlschlag von 'Dienst laeuft nicht'"
|
||||||
|
else
|
||||||
|
fail "Fehlermeldung fehlt oder ist mehrdeutig"
|
||||||
|
fi
|
||||||
|
if echo "$OUT" | grep -q "Dienst laeuft nicht"; then
|
||||||
|
fail "faelschlich 'Dienst laeuft nicht' gemeldet, obwohl der Dienst lief"
|
||||||
|
else
|
||||||
|
pass "'Dienst laeuft nicht' wird nicht faelschlich gemeldet"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
if [ "$FAILED" -eq 0 ]; then
|
||||||
|
echo "Alle Tests bestanden."
|
||||||
|
else
|
||||||
|
echo "Mindestens ein Test ist fehlgeschlagen." >&2
|
||||||
|
fi
|
||||||
|
exit "$FAILED"
|
||||||
Reference in New Issue
Block a user