Handbuch auf MkDocs-Basis, mit Bildschirmfotos aus dem Programm

26 Kapitel in vier Teilen, in der Reihenfolge, in der man sie braucht:
erst sichern, dann Dateien holen, dann ganze Maschinen wiederherstellen,
dahinter der Nachschlagteil.

Gebaut wird mit MkDocs + Material. Bewusst ohne Netzabhaengigkeiten:
keine Schriften vom CDN (font: false), Volltextsuche mit deutschem
Stemming liegt neben den Seiten. Im Notfall steht vielleicht das halbe
Netz - dann nuetzt eine Doku im Internet nichts.

  handbuch/bauen.sh              baut handbuch/site/
  handbuch/bauen.sh ansehen      Vorschau auf 127.0.0.1:8000

install.sh nimmt das gebaute Handbuch mit nach
/usr/share/doc/pvesnap/handbuch/ - falls es vorliegt. Auf dem Host selbst
wird nichts gebaut, mkdocs gehoert nicht auf einen Hypervisor.

Die 28 Bildschirmfotos sind nicht abfotografiert, sondern erzeugt: Der
echte Programmcode laeuft in einem Pseudo-Terminal gegen einen erfundenen
Proxmox-Host (Attrappen fuer pvesh, perl und rbd), pyte baut den Bildschirm
nach, heraus faellt ein SVG. Damit stimmen sie garantiert mit dem Programm
ueberein, sind reproduzierbar und enthalten keine echten Daten. Die
Werkstatt dafuer liegt unter handbuch/werkstatt/ samt LIESMICH.md.

Nebenbei: die Schlussmeldung von install.sh warb noch mit --exchange,
das mit dem eingebauten Austauschlaufwerk weggefallen ist.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
duffyduck
2026-08-09 12:39:30 +02:00
co-authored by Claude Opus 5
parent c484596702
commit 59e7224297
72 changed files with 7355 additions and 2 deletions
+139
View File
@@ -0,0 +1,139 @@
# Die Bildschirmfoto-Werkstatt
Die Bilder im Handbuch sind keine abfotografierten Terminals, sondern werden
erzeugt — aus dem **echten** Programmcode, gegen einen erfundenen Proxmox-Host.
```bash
./aufnehmen.sh # alle Bilder neu
./aufnehmen.sh explorer # nur die, deren Name "explorer" enthält
```
Ergebnis: `handbuch/docs/bilder/*.svg`
Das hat drei Gründe:
* **Sie stimmen.** Es läuft wirklich `pvesnap/recovery_ui.py`, nicht eine
Nachbildung. Ändert sich die Tastenleiste, ändert sich das Bild.
* **Sie sind reproduzierbar.** Derselbe Aufruf ergibt dasselbe Bild — gleiche
Daten, gleiche Uhrzeiten, gleiche Snapshot-Namen.
* **Kein echter Host wird angefasst.** Weder Daten noch Namen aus einer echten
Umgebung landen im Handbuch.
---
## Wie es funktioniert
```
scenes.py Liste aller Aufnahmen: Name, Szene, Tastenfolge, Titel
└─ probe.py startet eine Szene in einem Pseudo-Terminal
└─ stage.sh hängt die Kulisse an die richtigen Pfade (Namensraum)
└─ run.py biegt die Pfade im Programmcode um und ruft die Oberfläche auf
└─ pvesnap/… der echte Programmcode
└─ shot.py baut den Bildschirm nach und schreibt ihn als SVG
```
### `demo.py` — die Kulisse
Baut unter `werkstatt/demo/` ein erfundenes Rechenzentrum auf: zwei Nodes, zehn
Gäste, ein paar hundert Snapshots, zwei laufende Wiederherstellungen, drei
Austauschlaufwerke und einen Dateibaum für den Explorer.
Ein **fester Zeitpunkt** (`NOW`) sorgt dafür, dass zwei Aufnahmen derselben
Liste gleich aussehen — sonst würde die Beschreibung im Handbuch nicht mehr
zum Bild passen.
### `bin/pvesh`, `bin/perl`, `bin/rbd` — die Attrappen
pvesnap spricht mit Proxmox über genau drei Programme. Alle drei liegen hier als
kleine Python-Skripte, die aus `demo/state.json` antworten. Sie stehen im `PATH`
vor den echten.
Nichts davon verändert etwas — die schreibenden Aufrufe geben brav eine UPID
zurück und tun sonst nichts.
### `run.py` — die Pfade umbiegen
Setzt vor dem Start die Konstanten um, die sonst auf einen echten Host zeigen:
```python
recovery.REGISTRY = demo/lib/recovery.json
transfer.INDEX = demo/lib/transfer/index.json
transfer.CONF_ROOT = demo/pve/nodes
```
Der Programmcode selbst wird nicht angefasst. Die Bilder zeigen also wirklich
das, was auf dem Host auch zu sehen ist.
### `stage.sh` — die Pfade, die im Bild stehen
Der Explorer zeigt Pfade an. Im Handbuch sollen das die Pfade eines echten
Hosts sein (`/run/pvesnap/mnt/…`, `/root`, `/etc/pvesnap.conf`) und nicht die
Arbeitsverzeichnisse dieser Werkstatt.
Deshalb läuft jede Aufnahme in einem eigenen **Mount-Namensraum**
(`unshare -r -m`): Dort dürfen wir uns die Pfade hinbiegen, ohne am System
etwas zu verändern. `/etc` bekommt eine Overlay-Schicht, damit die
Konfiguration dort liegt, wo sie hingehört.
### `shot.py` — der Bildschirmnachbau
Startet das Programm in einem Pseudo-Terminal fester Größe (118 × 32), spielt
Tastendrücke ein, lässt [pyte](https://pypi.org/project/pyte/) den Bildschirm
nachbilden und schreibt das Ergebnis als SVG.
Zwei Feinheiten, die Zeit gekostet haben:
**`textLength` auf jedem Textstück.** Das SVG bettet keine Schrift ein — es
soll ja klein bleiben und offline funktionieren. Damit das Zeichenraster
trotzdem in jedem Browser sitzt, wird jede Zeichenkette fest vermessen.
**`NCURSES_NO_UTF8_ACS=1`.** ncurses zeichnet Rahmen sonst über den
Ersatzzeichensatz (`ESC ( 0`). pyte ignoriert das im UTF-8-Betrieb, und aus den
Linien würden Buchstaben (`lqqqk` statt `┌───┐`). Mit der Variablen liefert
ncurses echte Unicode-Rahmenzeichen.
---
## Eine Szene nachsehen
Zum Ausprobieren, ohne ein Bild zu schreiben — gibt den Bildschirm als Text aus:
```bash
../.venv/bin/python probe.py recovery
../.venv/bin/python probe.py recovery enter p
COLS=140 ROWS=40 ../.venv/bin/python probe.py explorer ab ab enter
```
Tastennamen: `ab auf links rechts enter tab esc space f2 f3 f5 f7 f9`,
alles andere wird als Zeichen geschickt.
Verfügbare Szenen stehen in `run.py` unter `SZENEN`.
---
## Eine Aufnahme hinzufügen
In `scenes.py` eine Zeile ergänzen:
```python
("recovery-neuerkram", "recovery", ["enter", "p"],
"root@pve1 — pvesnap-recovery"),
```
Fünftes Feld optional: Wartezeit in Sekunden, für Bildschirme, hinter denen
noch etwas arbeitet (sonst hält der Nachbau den letzten Stand fest, während im
Hintergrund noch ein Proxmox-Task läuft).
Braucht es dafür eine neue Szene, kommt sie in `run.py` dazu.
---
## Wenn etwas nicht klappt
| Symptom | Ursache |
|---|---|
| Bild ist leer oder zeigt einen Traceback | `scenes.py` meldet das selbst — mit `probe.py` nachsehen |
| Rahmen bestehen aus `lqqqk` | `NCURSES_NO_UTF8_ACS=1` fehlt in `probe.umgebung()` |
| Pfade zeigen ins Scratchpad | `unshare -r` ging nicht; `aufnehmen.sh` prüft das vorher |
| Pfeiltasten bewegen nichts | Es muss `\x1bOB` sein, nicht `\x1b[B` — curses schaltet auf den Anwendungsmodus |
| Ein Bildschirm hängt bei „bitte warten" | Eine Antwort der Attrappe fehlt; mit `log_level=DEBUG` sieht man den Aufruf |