fix(mounts): Ergebnis pruefen statt glauben - "mount" meldet Erfolg und liefert nicht
Ampel / ampel (push) Successful in 28s

Nachtrag zum vorigen Commit, weil der die Freigabe noch nicht zurueckbrachte.
Dreimal reproduziert: Beim API-Start meldete `mount` Rueckgabewert 0, das Log
schrieb "rippy: eingehaengt", /proc/mounts zeigte GENAU EINE korrekt aussehende
Schicht mit den richtigen Optionen - und `timeout 6 ls /app/media/rippy` lief
trotzdem in die Zeitgrenze. Derselbe Ablauf ein zweites Mal, per POST
/storage-mounts/rippy/repair, stellte sie sofort her (30 s, danach erreichbar).

Der erste SMB-Sitzungsaufbau kurz nach dem Container-Start geht also gelegentlich
schief, ohne es zu melden. Ein Rueckgabewert von `mount` beweist deshalb nichts.

Jetzt: Nach dem Mount wird geprueft, ob die Freigabe ANTWORTET (ist_erreichbar,
harte Grenze). Wenn nicht, einmal loesen und neu mounten. Hilft auch das nicht,
fliegt ein Fehler mit Klartext - dann steht im Log "FEHLER" statt "eingehaengt",
was schlicht die Wahrheit ist, und der Nutzer bekommt den Hinweis auf die
Reparatur-Funktion statt eines Rips, der spaeter still scheitert.

Damit ist die Kette geschlossen: os.path.isdir kann nicht mehr im Kernel haengen
(voriger Commit), die Rohdaten-Schleife stirbt nicht mehr daran, und ein Mount
gilt erst als hergestellt, wenn er antwortet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-26 13:46:37 +02:00
parent a15623cc70
commit 87537bf3e5
2 changed files with 67 additions and 13 deletions
+33 -12
View File
@@ -299,18 +299,39 @@ def mounten(name: str, typ: str, quelle: str, optionen: str = "",
else:
raise RuntimeError(f"Unbekannter Typ: {typ} (nfs oder cifs)")
ergebnis = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if ergebnis.returncode != 0:
fehler = (ergebnis.stderr or ergebnis.stdout or "").strip()
hinweis = ""
if "error(13)" in fehler or "Permission denied" in fehler:
hinweis = (
" — Zugriff verweigert: Benutzer/Passwort prüfen; ohne "
"Angaben versucht Rippy einen Gast-Zugriff, den Windows/"
"NAS meist ablehnen."
)
raise RuntimeError(f"mount schlug fehl: {fehler[:300]}{hinweis}")
return schreibtest(ziel)
# Zwei Versuche. Grund (26.07.2026, dreimal reproduziert): Beim API-Start
# meldete `mount` Erfolg — und die Freigabe antwortete danach trotzdem
# nicht (`timeout 6 ls` lief in die Grenze, eine einzige, korrekt
# aussehende Mount-Schicht in /proc/mounts). Derselbe Ablauf ein zweites
# Mal, per POST /storage-mounts/<name>/repair, stellte sie sofort her.
# Der erste SMB-Sitzungsaufbau kurz nach dem Container-Start geht also
# gelegentlich schief, ohne es zu melden.
#
# Deshalb wird das Ergebnis GEPRÜFT statt geglaubt: Antwortet die
# Freigabe nach dem Mount nicht, wird einmal gelöst und neu gemountet.
# Und wenn das auch nicht hilft, fliegt ein Fehler — dann steht im Log
# „FEHLER" statt „eingehängt", was schlicht die Wahrheit ist.
for versuch in (1, 2):
ergebnis = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if ergebnis.returncode != 0:
fehler = (ergebnis.stderr or ergebnis.stdout or "").strip()
hinweis = ""
if "error(13)" in fehler or "Permission denied" in fehler:
hinweis = (
" — Zugriff verweigert: Benutzer/Passwort prüfen; ohne "
"Angaben versucht Rippy einen Gast-Zugriff, den Windows/"
"NAS meist ablehnen."
)
raise RuntimeError(f"mount schlug fehl: {fehler[:300]}{hinweis}")
if ist_erreichbar(name):
return schreibtest(ziel)
if versuch == 1:
_lazy_umount(ziel)
raise RuntimeError(
f"{quelle} wurde eingehängt, antwortet aber nicht (zwei Versuche). "
"Läuft die Freigabe? Bei einem NAS im Ruhezustand hilft meist ein "
"erneutes Einhängen über Einstellungen → Speicherziele → Reparieren."
)
finally:
if creds_datei:
try: