README: Web-Oberflaeche vollstaendig dokumentiert; "pvesnap-web <vmid>"
Der Abschnitt zur Web-Oberflaeche beschreibt jetzt beides ausfuehrlich: die Einrichtung als Dienst ueber install.sh --with-webexplorer --port (mit Beispielen fuer eigene Adresse und --no-start), das Nachtraegliche Aendern ueber /etc/pvesnap/web.conf und die ueblichen systemctl-Befehle - sowie den Start von Hand mit einer Tabelle aller Parameter und Beispielen fuer die typischen Faelle: SSH-Tunnel, Backup-Team mit VM.Backup statt VM.Snapshot, einzelner Dienstleister ueber --allow-user, Zugangsschluessel statt Anmeldung, freies Verzeichnis, Aufraeumen. Der Explorer hat ebenfalls eine Parametertabelle bekommen. Dabei fiel auf, dass "pvesnap-web <vmid>" ohne Snapshot-Namen bisher gar nichts bewirkte - man bekam trotzdem die vollstaendige Gastliste. Jetzt schraenkt die Angabe die Oberflaeche wirklich auf diesen Gast ein, und zwar auch gegen Aufrufe ueber die Adresszeile. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
3acbebce6f
commit
ab610a1f5a
@@ -369,9 +369,20 @@ pvesnap-explorer --cleanup
|
|||||||
pvesnap-explorer # Gast und Snapshot auswählen
|
pvesnap-explorer # Gast und Snapshot auswählen
|
||||||
pvesnap-explorer 802 # Snapshot von VM 802 auswählen
|
pvesnap-explorer 802 # Snapshot von VM 802 auswählen
|
||||||
pvesnap-explorer 802 <snapname> # direkt öffnen
|
pvesnap-explorer 802 <snapname> # direkt öffnen
|
||||||
|
pvesnap-explorer --local /srv/restore # rechtes Fenster startet dort
|
||||||
pvesnap-explorer --path /mnt/x # beliebiges Verzeichnis (zum Ausprobieren)
|
pvesnap-explorer --path /mnt/x # beliebiges Verzeichnis (zum Ausprobieren)
|
||||||
|
pvesnap-explorer --cleanup # hängengebliebene Einbindungen lösen
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| Parameter | Vorgabe | Bedeutung |
|
||||||
|
|---|---|---|
|
||||||
|
| `vmid` | — | Gast direkt vorwählen |
|
||||||
|
| `snapshot` | — | Snapshot direkt vorwählen |
|
||||||
|
| `-l`, `--local <pfad>` | aktuelles Verzeichnis | Startverzeichnis im rechten Fenster |
|
||||||
|
| `-p`, `--path <pfad>` | — | beliebiges Verzeichnis öffnen, ohne Proxmox zu fragen |
|
||||||
|
| `--cleanup` | — | hängengebliebene Einbindungen lösen und beenden |
|
||||||
|
| `-v`, `--verbose` | — | ausführliches Protokoll |
|
||||||
|
|
||||||
Links der Snapshot, rechts der lokale Rechner:
|
Links der Snapshot, rechts der lokale Rechner:
|
||||||
|
|
||||||
| Taste | |
|
| Taste | |
|
||||||
@@ -401,28 +412,94 @@ bleiben Verweise.
|
|||||||
|
|
||||||
### `pvesnap-web` — im Browser herunterladen
|
### `pvesnap-web` — im Browser herunterladen
|
||||||
|
|
||||||
Als Dienst (empfohlen, überlebt Neustarts):
|
#### Als Dienst einrichten
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./install.sh --with-webexplorer --port 8823
|
./install.sh --with-webexplorer --port 8823
|
||||||
```
|
```
|
||||||
|
|
||||||
Danach läuft die Oberfläche dauerhaft auf `http://<host>:8823/`. Port, Adresse
|
Danach läuft die Oberfläche dauerhaft auf `http://<host>:8823/` und startet mit
|
||||||
und Anmeldeart stehen in `/etc/pvesnap/web.conf`:
|
dem System. Ohne `--port` bricht das Skript ab — der Port hat keine sinnvolle
|
||||||
|
Vorgabe, die zu jedem Host passt.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./install.sh --with-webexplorer --port 8443 --bind 10.0.0.5 # nur auf einer IP
|
||||||
|
./install.sh --with-webexplorer --port 8823 --no-start # erst später starten
|
||||||
|
```
|
||||||
|
|
||||||
|
Alle Aufrufparameter des Dienstes stehen in **`/etc/pvesnap/web.conf`**:
|
||||||
|
|
||||||
```
|
```
|
||||||
PVESNAP_WEB_ARGS=--bind 0.0.0.0 --port 8823 --auth pve
|
PVESNAP_WEB_ARGS=--bind 0.0.0.0 --port 8823 --auth pve
|
||||||
```
|
```
|
||||||
|
|
||||||
Nach Änderungen `systemctl restart pvesnap-web`. Oder von Hand für einen
|
Dort lässt sich alles nachträglich ändern — Port, Adresse, Anmeldeart, Rechte:
|
||||||
einzelnen Einsatz:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pvesnap-web # Gast und Snapshot im Browser wählen
|
nano /etc/pvesnap/web.conf
|
||||||
pvesnap-web 802 <snapname> # diesen Snapshot gleich öffnen
|
systemctl restart pvesnap-web
|
||||||
pvesnap-web --path /verzeichnis # beliebiges Verzeichnis (ohne Proxmox)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Dienst verwalten:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl status pvesnap-web # läuft er?
|
||||||
|
systemctl restart pvesnap-web # nach Änderungen in web.conf
|
||||||
|
systemctl stop pvesnap-web # anhalten (hängt offene Snapshots aus)
|
||||||
|
systemctl disable pvesnap-web # nicht mehr automatisch starten
|
||||||
|
journalctl -u pvesnap-web -f # Protokoll, auch fehlgeschlagene Anmeldungen
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Von Hand starten
|
||||||
|
|
||||||
|
Für einen einmaligen Einsatz, ohne etwas zu installieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pvesnap-web # Gast und Snapshot im Browser wählen
|
||||||
|
pvesnap-web 802 # nur diesen Gast anbieten
|
||||||
|
pvesnap-web 802 autosnap-taeglich-20260731-023000 # Snapshot gleich öffnen
|
||||||
|
```
|
||||||
|
|
||||||
|
| Parameter | Vorgabe | Bedeutung |
|
||||||
|
|---|---|---|
|
||||||
|
| `-P`, `--port <nummer>` | `8823` | Port, auf dem gelauscht wird |
|
||||||
|
| `-b`, `--bind <adresse>` | `0.0.0.0` | Netzwerkadresse; `127.0.0.1` = nur lokal |
|
||||||
|
| `-a`, `--auth pve\|token\|none` | `pve` | Anmeldeart, siehe unten |
|
||||||
|
| `--require-privilege <recht>` | `VM.Snapshot` | nötiges Recht auf dem Gast |
|
||||||
|
| `--allow-user <user@realm>` | — | dieser Benutzer darf alles (mehrfach möglich) |
|
||||||
|
| `-t`, `--token <schlüssel>` | zufällig | Zugangsschlüssel selbst vorgeben |
|
||||||
|
| `--no-token` | — | Kurzform für `--auth none` |
|
||||||
|
| `-p`, `--path <verzeichnis>` | — | beliebiges Verzeichnis statt eines Snapshots |
|
||||||
|
| `--cleanup` | — | hängengebliebene Einbindungen lösen und beenden |
|
||||||
|
| `-v`, `--verbose` | — | ausführliches Protokoll |
|
||||||
|
| `-V`, `--version` | — | Version anzeigen |
|
||||||
|
|
||||||
|
Beispiele:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Nur lokal lauschen, dazu vom Arbeitsplatz einen SSH-Tunnel legen
|
||||||
|
pvesnap-web --bind 127.0.0.1 --port 8823
|
||||||
|
# am eigenen Rechner: ssh -L 8823:localhost:8823 root@pve
|
||||||
|
# dann im Browser: http://localhost:8823/
|
||||||
|
|
||||||
|
# Ein Backup-Team soll ran, ohne Snapshot-Rechte zu haben
|
||||||
|
pvesnap-web --port 8823 --require-privilege VM.Backup
|
||||||
|
|
||||||
|
# Ein einzelner Dienstleister, unabhängig von den Proxmox-Rechten
|
||||||
|
pvesnap-web --port 8823 --allow-user dienstleister@pve
|
||||||
|
|
||||||
|
# Schnell etwas herausgeben, ohne Proxmox-Benutzer (Schlüssel in der Adresse)
|
||||||
|
pvesnap-web --port 8823 --auth token
|
||||||
|
|
||||||
|
# Ein beliebiges Verzeichnis freigeben, z. B. ein bereits gemountetes Backup
|
||||||
|
pvesnap-web --path /mnt/restore --port 8823
|
||||||
|
|
||||||
|
# Nach einem Absturz aufräumen
|
||||||
|
pvesnap-web --cleanup
|
||||||
|
```
|
||||||
|
|
||||||
|
Mit `pvesnap-web --help` gibt es dieselbe Übersicht im Terminal.
|
||||||
|
|
||||||
**Anmeldung mit den Proxmox-Benutzern.** Die Oberfläche zeigt dieselbe
|
**Anmeldung mit den Proxmox-Benutzern.** Die Oberfläche zeigt dieselbe
|
||||||
Anmeldemaske wie Proxmox — Benutzername, Passwort, Realm-Auswahl. Geprüft wird
|
Anmeldemaske wie Proxmox — Benutzername, Passwort, Realm-Auswahl. Geprüft wird
|
||||||
über `POST /access/ticket` auf der lokalen Proxmox-API, also genau den Weg, den
|
über `POST /access/ticket` auf der lokalen Proxmox-API, also genau den Weg, den
|
||||||
|
|||||||
@@ -85,13 +85,16 @@ class AppState:
|
|||||||
"""Was gerade geoeffnet ist. Es ist immer hoechstens ein Snapshot offen."""
|
"""Was gerade geoeffnet ist. Es ist immer hoechstens ein Snapshot offen."""
|
||||||
|
|
||||||
def __init__(self, token="", proxmox=None, fixed_path="", auth_mode="token",
|
def __init__(self, token="", proxmox=None, fixed_path="", auth_mode="token",
|
||||||
privilege=DEFAULT_PRIVILEGE, allowed_users=()):
|
privilege=DEFAULT_PRIVILEGE, allowed_users=(), only_vmid=None):
|
||||||
self.token = token
|
self.token = token
|
||||||
self.proxmox = proxmox
|
self.proxmox = proxmox
|
||||||
self.fixed_path = fixed_path
|
self.fixed_path = fixed_path
|
||||||
self.auth_mode = auth_mode # pve | token | none
|
self.auth_mode = auth_mode # pve | token | none
|
||||||
self.privilege = privilege
|
self.privilege = privilege
|
||||||
self.allowed_users = tuple(allowed_users or ())
|
self.allowed_users = tuple(allowed_users or ())
|
||||||
|
# Wurde beim Start eine VMID angegeben, gibt es auch nur diesen Gast -
|
||||||
|
# weder in der Liste noch ueber die Adresszeile.
|
||||||
|
self.only_vmid = only_vmid
|
||||||
self.sessions = Sessions()
|
self.sessions = Sessions()
|
||||||
self.session = None
|
self.session = None
|
||||||
self.guest = None
|
self.guest = None
|
||||||
@@ -107,6 +110,8 @@ class AppState:
|
|||||||
def visible_guests(self, userid):
|
def visible_guests(self, userid):
|
||||||
"""Nur die Gaeste, in die dieser Benutzer hineinsehen darf."""
|
"""Nur die Gaeste, in die dieser Benutzer hineinsehen darf."""
|
||||||
guests = self.proxmox.inventory(refresh=True)
|
guests = self.proxmox.inventory(refresh=True)
|
||||||
|
if self.only_vmid:
|
||||||
|
guests = [g for g in guests if g.vmid == self.only_vmid]
|
||||||
if self.auth_mode != "pve":
|
if self.auth_mode != "pve":
|
||||||
return guests
|
return guests
|
||||||
tree = permissions(userid)
|
tree = permissions(userid)
|
||||||
@@ -114,6 +119,8 @@ class AppState:
|
|||||||
if may_access(userid, g, self.privilege, tree, self.allowed_users)]
|
if may_access(userid, g, self.privilege, tree, self.allowed_users)]
|
||||||
|
|
||||||
def may_open(self, userid, guest):
|
def may_open(self, userid, guest):
|
||||||
|
if self.only_vmid and guest.vmid != self.only_vmid:
|
||||||
|
return False
|
||||||
if self.auth_mode != "pve":
|
if self.auth_mode != "pve":
|
||||||
return True
|
return True
|
||||||
return may_access(userid, guest, self.privilege, None, self.allowed_users)
|
return may_access(userid, guest, self.privilege, None, self.allowed_users)
|
||||||
@@ -905,7 +912,7 @@ def main(argv=None):
|
|||||||
token = (args.token or secrets.token_urlsafe(18)) if mode == "token" else ""
|
token = (args.token or secrets.token_urlsafe(18)) if mode == "token" else ""
|
||||||
state = AppState(token=token, proxmox=proxmox, fixed_path=args.path or "",
|
state = AppState(token=token, proxmox=proxmox, fixed_path=args.path or "",
|
||||||
auth_mode=mode, privilege=args.require_privilege,
|
auth_mode=mode, privilege=args.require_privilege,
|
||||||
allowed_users=args.allow_user)
|
allowed_users=args.allow_user, only_vmid=args.vmid)
|
||||||
|
|
||||||
if args.vmid and args.snapshot and proxmox:
|
if args.vmid and args.snapshot and proxmox:
|
||||||
guest = next((g for g in proxmox.inventory() if g.vmid == args.vmid), None)
|
guest = next((g for g in proxmox.inventory() if g.vmid == args.vmid), None)
|
||||||
|
|||||||
Reference in New Issue
Block a user