fix: ein fehlendes Laufwerk darf Rippy nicht am Starten hindern
Ampel / ampel (push) Successful in 40s

WAS: Die `devices:`-Eintraege fliegen aus docker-compose.yml. Was dieser
Host wirklich hat, ermittelt deploy/geraete-override.sh und schreibt es in
docker-compose.override.yml — die zieht Compose von allein dazu, der
Befehl bleibt `docker compose up -d`.

WARUM (Vorfall heute, 28.08.2026): Das USB-Laufwerk haengt nicht mehr an
der VM. Ein ganz normaler Deploy legte daraufhin api, worker UND ui still:

  Error response from daemon: error gathering device information while
  adding custom device "/dev/sr0": no such file or directory

Ein `devices:`-Eintrag ist eine STARTBEDINGUNG — und keiner der drei
Container braucht zum STARTEN ein Laufwerk. Rippy war unten, und die
Meldung stand mitten im Build-Rauschen (dieselbe Klasse wie das geschluckte
`|| echo` beim .env-Kopieren am 26.07.).

DER WIDERSPRUCH WAR AELTER ALS DER VORFALL: install.sh sagt bei fehlendem
Laufwerk ausdruecklich "die Installation laeuft trotzdem durch; diese
Maschine dient dann als reine KOMPRIMIER-Maschine" — die Compose-Datei sah
das anders. Eine Maschine ohne Laufwerk ist ein VORGESEHENER Betriebsfall:
der Windows-Worker und der GPU-Encoder sind genau das.

Das Skript uebernimmt die Erkennung aus install.sh unveraendert: sr- und
sg-Knoten ueber die SCSI-Adresse in /sys abgeglichen, nicht geraten. Und
es schreibt die Override AUCH dann, wenn kein Laufwerk da ist — sonst
bliebe eine alte Datei mit /dev/sr0 liegen und der Fehler waere derselbe,
nur schwerer zu finden, weil sie gitignored ist und in keinem Diff auftaucht.

deploy.sh ruft es vor dem Start auf.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-08-28 09:35:48 +02:00
co-authored by Claude Opus 5
parent 95705c8d88
commit 05ab655116
3 changed files with 148 additions and 12 deletions
+12
View File
@@ -95,6 +95,18 @@ fi
sed -i '/^RIPPY_VERSION=/d' .env
echo "RIPPY_VERSION=$(git rev-parse --short HEAD)" >> .env
# Geraete dieses Hosts ermitteln, BEVOR gestartet wird.
# Ohne diesen Schritt haengt der Start an einem `devices:`-Eintrag, den es
# vielleicht nicht mehr gibt — am 28.08.2026 legte genau das die ganze
# Installation stillt, weil das USB-Laufwerk abgezogen war (Herleitung im Kopf
# von docker-compose.yml). Das Skript schreibt die Override immer neu, auch
# wenn kein Laufwerk da ist.
if [ -x ./deploy/geraete-override.sh ]; then
./deploy/geraete-override.sh .
else
echo "WARNUNG: deploy/geraete-override.sh fehlt — starte ohne Geraete-Erkennung."
fi
docker compose -p rippy up -d --build $DIENST
docker compose -p rippy ps --format 'table {{.Name}}\t{{.Status}}'
REMOTE
+112
View File
@@ -0,0 +1,112 @@
#!/usr/bin/env bash
#
# Erzeugt docker-compose.override.yml mit den optischen Laufwerken DIESES Hosts.
#
# ## Warum es das gibt (Vorfall 28.08.2026)
#
# In docker-compose.yml stand:
#
# devices:
# - ${OPTICAL_SR:-/dev/sr0}:/dev/sr0
#
# Das ist eine STARTBEDINGUNG. Fehlt das Laufwerk, startet der Container nicht:
#
# Error response from daemon: error gathering device information while
# adding custom device "/dev/sr0": no such file or directory
#
# Genau das ist passiert, als das USB-Laufwerk von der VM abgezogen wurde: Ein
# ganz normaler Deploy legte api, worker UND ui still — obwohl keiner der drei
# ein Laufwerk zum Starten braucht. Rippy war unten, und die Meldung stand
# mitten im Build-Rauschen.
#
# Der Widerspruch war schon vorher da: `install.sh` sagt bei fehlendem Laufwerk
# ausdrücklich „die Installation läuft trotzdem durch; diese Maschine dient dann
# als reine KOMPRIMIER-Maschine" — die Compose-Datei sah das anders. Eine
# Maschine ohne Laufwerk ist ein vorgesehener Betriebsfall (der Windows-Worker
# und der GPU-Encoder sind genau das).
#
# Seither steht in docker-compose.yml KEIN devices-Block mehr. Was dieser Host
# wirklich hat, landet in docker-compose.override.yml — die zieht Compose von
# allein dazu (`docker compose up` braucht keinen extra Schalter), und sie ist
# gitignored, weil die Geräteknoten je Rechner anders heißen.
#
# Aufruf: ./deploy/geraete-override.sh [zielverzeichnis]
# (ohne Argument: das aktuelle Verzeichnis)
#
set -u
ZIEL="${1:-.}"
DATEI="$ZIEL/docker-compose.override.yml"
# MakeMKV spricht Laufwerke über die SCSI-Generic-Schicht an und braucht deshalb
# ZWEI Knoten: /dev/srN und den passenden /dev/sgM. Welche sg-Nummer dazugehört,
# ist je Host anders — sie wird über die SCSI-Adresse ermittelt statt geraten.
# Beide Knoten zeigen in /sys auf dasselbe Geräteverzeichnis (z. B. 3:0:0:0).
# (Dieselbe Herleitung wie in install.sh, Prüfung 2/5.)
SR=""
SG=""
LAUFWERK=""
for srpfad in /sys/block/sr*; do
[ -e "$srpfad" ] || continue
srname=$(basename "$srpfad")
adresse=$(basename "$(readlink -f "$srpfad/device" 2>/dev/null)" 2>/dev/null)
[ -n "$adresse" ] || continue
for sgpfad in /sys/class/scsi_generic/sg*; do
[ -e "$sgpfad" ] || continue
if [ "$(basename "$(readlink -f "$sgpfad/device" 2>/dev/null)" 2>/dev/null)" = "$adresse" ]; then
SR="/dev/$srname"
SG="/dev/$(basename "$sgpfad")"
LAUFWERK="$(cat "$srpfad/device/vendor" 2>/dev/null) $(cat "$srpfad/device/model" 2>/dev/null)"
break 2
fi
done
done
kopf() {
cat <<KOPF
# ERZEUGT von deploy/geraete-override.sh — nicht von Hand ändern.
# Diese Datei ist gitignored: Die Geräteknoten heißen auf jedem Rechner anders.
# Neu erzeugen nach jedem An- oder Abstecken eines Laufwerks:
# ./deploy/geraete-override.sh && docker compose up -d
KOPF
}
if [ -z "$SR" ]; then
# KEIN Laufwerk. Wichtig: trotzdem eine gültige Datei schreiben und die alte
# damit überschreiben. Bliebe eine alte Override mit /dev/sr0 liegen, wäre der
# Fehler beim nächsten Start genau derselbe — nur schwerer zu finden, weil die
# Datei gitignored ist und in keinem Diff auftaucht.
{
kopf
echo "#"
echo "# Auf diesem Host wurde KEIN optisches Laufwerk gefunden."
echo "# Rippy läuft damit als reine Komprimier-Maschine — das ist ein"
echo "# vorgesehener Betriebsfall, kein Fehler. Zum Rippen das Laufwerk"
echo "# anstecken (in einer VM: USB-Passthrough) und dieses Skript erneut"
echo "# aufrufen."
echo "services: {}"
} > "$DATEI"
echo "Kein optisches Laufwerk gefunden — $DATEI ohne Geräte geschrieben."
echo "Rippy startet und kann komprimieren; Rippen geht erst mit Laufwerk."
exit 0
fi
{
kopf
echo "#"
echo "# Gefunden: $(echo "$LAUFWERK" | tr -s ' ')"
echo "# $SR + $SG (über die SCSI-Adresse abgeglichen, nicht geraten)"
cat <<YAML
services:
api:
devices:
- $SR:/dev/sr0
worker:
devices:
- $SR:/dev/sr0
- $SG:/dev/sg1
YAML
} > "$DATEI"
echo "Laufwerk gefunden: $(echo "$LAUFWERK" | tr -s ' ')"
echo " $SR + $SG -> $DATEI"
+24 -12
View File
@@ -3,7 +3,24 @@
# Geräte-Zugriff (22.07./23.07.-Lehre): Optische Laufwerke MÜSSEN als devices:
# eingebunden werden. Bind-Mounts unter volumes: geben dem Container zwar den
# Geräteknoten, aber KEINE Berechtigung im Device-Cgroup → jedes open() scheitert
# mit EPERM. Voraussetzung: Die VM sieht das Laufwerk (USB-Passthrough auf pve).
# mit EPERM.
#
# ⚠️ ABER NICHT HIER (Vorfall 28.08.2026): Ein `devices:`-Eintrag ist eine
# STARTBEDINGUNG. Als das USB-Laufwerk von der VM abgezogen wurde, legte ein
# ganz normaler Deploy api, worker UND ui still — obwohl keiner der drei zum
# Starten ein Laufwerk braucht:
#
# Error response from daemon: error gathering device information while
# adding custom device "/dev/sr0": no such file or directory
#
# Der Widerspruch war älter: install.sh sagt bei fehlendem Laufwerk
# ausdrücklich „läuft trotzdem durch, dann ist das eine reine
# KOMPRIMIER-Maschine" — diese Datei sah das anders.
#
# Deshalb stehen die Geräte jetzt in docker-compose.override.yml, erzeugt von
# `deploy/geraete-override.sh`. Compose zieht die Override von allein dazu;
# `docker compose up -d` bleibt derselbe Befehl. Nach jedem An- oder Abstecken
# eines Laufwerks das Skript erneut aufrufen.
services:
api:
@@ -54,8 +71,7 @@ services:
- temp:/app/temp
# MakeMKV-Datenverzeichnis (dasselbe wie im Worker, siehe dort).
- ${MAKEMKV_DATA_HOST:-/srv/rippy/makemkv}:/app/makemkv-data
devices:
- ${OPTICAL_SR:-/dev/sr0}:/dev/sr0
# devices: siehe Kopf — kommen aus docker-compose.override.yml
networks:
- rippy-net
depends_on:
@@ -118,15 +134,11 @@ services:
# Ohne diesen Mount löschte JEDER `up -d --build` beides; die
# Fehlermeldung schickte den Nutzer zu einer Datei, die es nicht mehr gab.
- ${MAKEMKV_DATA_HOST:-/srv/rippy/makemkv}:/root/.MakeMKV
devices:
# Host-Geräteknoten via .env (OPTICAL_SR/OPTICAL_SG) — je Rechner ANDERS!
# MakeMKV spricht Laufwerke über die SCSI-Generic-Schicht an; ohne den
# passenden sg-Knoten findet es „keine usable optical drives". Den sg-Knoten
# des Laufwerks auf DIESEM Host ermitteln (lsscsi -g) und in die .env eintragen.
# Achtung: nach USB-Reconnect zur Laufzeit kann die sg-Nummer wandern →
# Container neu starten. Defaults (sr0/sg1) passen für den Ursprungs-Host.
- ${OPTICAL_SR:-/dev/sr0}:/dev/sr0
- ${OPTICAL_SG:-/dev/sg1}:/dev/sg1
# devices: siehe Kopf dieser Datei — die optischen Knoten dieses Hosts
# stehen in docker-compose.override.yml (deploy/geraete-override.sh).
# MakeMKV braucht BEIDE: /dev/srN und den passenden /dev/sgM; welche
# sg-Nummer dazugehoert, ist je Host anders und wird dort ueber die
# SCSI-Adresse abgeglichen statt geraten.
networks:
- rippy-net
depends_on: