proxmox-cluster-network-cha.../README.md

402 lines
13 KiB
Markdown

# Proxmox Cluster Network Changer
Migriert ein komplettes Proxmox-Cluster (inkl. Ceph) von einem Netzwerk in ein anderes.
**Problem:** Wenn man bei einem Proxmox-Cluster die IPs ändert, verliert man das Quorum und `/etc/pve` wird read-only — dann kann man weder Corosync noch Ceph über das Cluster-Dateisystem konfigurieren. Dieses Tool löst das Problem durch eine koordinierte Migration aller Nodes.
## Features
- **Auto-Detect** aller Nodes, Bridges, IPs und Netzwerke
- Koordinierte Migration aller Nodes in einem Durchgang
- **Multi-NIC-Support** — erkennt automatisch Management-, Ceph-Public- und Ceph-Cluster-Bridges
- Ceph-Support (Public Network, Cluster Network, MON-Adressen)
- Funktioniert auch bei **gebrochenem Quorum** (z.B. wenn ein Node bereits manuell geändert wurde)
- **Rescue-Netzwerk** — temporäres Emergency-Netz wenn sich Nodes nicht mehr erreichen können
- **Passwort-Auth via `.env`** — unabhängig von `/etc/pve`, funktioniert immer
- Automatische Backups aller Konfigurationen vor der Migration
- Dry-Run-Modus zum gefahrlosen Testen
- Verifikation nach der Migration
## Voraussetzungen
- Python 3.9+ (auf Proxmox standardmäßig vorhanden)
- Root-Zugriff auf dem Node, auf dem das Tool läuft
- `sshpass` — wird beim ersten Start automatisch installiert falls nicht vorhanden
- Root-Passwort der Proxmox-Nodes (alle Nodes müssen das gleiche Passwort haben)
- Keine externen Python-Pakete nötig (nur stdlib)
## Installation
```bash
# Auf einen Proxmox-Node kopieren
scp -r proxmox-cluster-network-changer/ root@pve1:/root/
# Oder direkt klonen
cd /root
git clone <repo-url> proxmox-cluster-network-changer
# .env erstellen
cd proxmox-cluster-network-changer
cp .env.example .env
nano .env # SSH_PASSWORD=dein-root-passwort eintragen
```
## SSH-Authentifizierung
Das Tool nutzt `sshpass` mit dem Root-Passwort aus der `.env`-Datei. Key-basierte Auth funktioniert bei Proxmox nicht zuverlässig, weil `/etc/pve/priv/authorized_keys` verschwindet wenn `pve-cluster` gestoppt wird.
```bash
# .env-Datei erstellen
echo 'SSH_PASSWORD=dein-root-passwort' > .env
```
> **Hinweis:** Alle Nodes müssen das gleiche Root-Passwort haben (bei Proxmox-Clustern üblich).
## Verwendung
### Aktuelle Konfiguration anzeigen (Discovery)
```bash
python3 main.py --discover
```
Zeigt an:
- Alle Cluster-Nodes mit IPs
- Corosync-Konfiguration
- Ceph-Netzwerke und MON-Hosts
- Quorum-Status
- Welche Nodes erreichbar sind
### Dry-Run (nichts wird geändert)
```bash
python3 main.py --dry-run
```
Durchläuft den kompletten Prozess, zeigt alle geplanten Änderungen an, schreibt aber nichts.
### Migration durchführen
```bash
python3 main.py
```
Das Tool führt interaktiv durch den Prozess:
```
============================================================
Proxmox Cluster Network Changer
============================================================
[SSH] Passwort-Authentifizierung aktiv (via sshpass)
=== Phase 1: Discovery ===
[Corosync]
Cluster: mycluster
Nodes gefunden: 4
- pve1 (ID: 1) -> 192.168.0.101
- pve2 (ID: 2) -> 192.168.0.102
- pve3 (ID: 3) -> 192.168.0.103
- pve4 (ID: 4) -> 192.168.0.104
[Ceph]
Public Network: 192.168.0.0/24
Cluster Network: 10.0.1.0/24
=== Phase 2: Migration planen ===
[Netzwerk-Erkennung]
vmbr0: Management/Corosync (192.168.0.0/24)
vmbr1: Ceph Cluster (10.0.1.0/24)
[Management-Netzwerk (Corosync)]
Aktuell: 192.168.0.0/24
Neues Management-Netzwerk (z.B. 172.0.2.0/16): 172.0.2.0/16
Neues Gateway [172.0.0.1]: 172.0.2.1
[Management IP-Mapping]
pve1: 192.168.0.101 -> [172.0.2.101]:
pve2: 192.168.0.102 -> [172.0.2.102]:
[Ceph Netzwerke]
Ceph Public: gleich wie Management -> wird automatisch mit umgezogen
Ceph Cluster (10.0.1.0/24) auf separater NIC -> eigenes Mapping
Migration durchführen? [j/N]: j
```
Das Tool erkennt automatisch welche Bridges welche Netzwerke tragen.
Wenn Ceph Public/Cluster auf separaten NICs liegen, werden die IPs einzeln pro Node abgefragt.
### Optionen
| Option | Beschreibung |
|---|---|
| `--dry-run` | Nur anzeigen, nichts ändern |
| `--discover` | Nur aktuelle Config anzeigen |
| `--rescue` | Rescue-Modus: Emergency-Netzwerk einrichten |
| `--rescue-commands SUBNET` | Nur Rescue-Befehle ausgeben (z.B. `10.99.99.0/24`) |
| `--ssh-port PORT` | SSH-Port (Standard: 22) |
| `--env-file PFAD` | Pfad zur .env-Datei (Standard: `.env`) |
### `.env`-Datei
| Variable | Beschreibung |
|---|---|
| `SSH_PASSWORD` | **Pflicht.** Root-Passwort für SSH (alle Nodes gleich) |
| `SSH_USER` | SSH-Benutzer (Standard: `root`) |
## Was wird geändert?
| Datei | Wo | Was |
|---|---|---|
| `/etc/network/interfaces` | Jeder Node | Alle Bridge-IPs (Management, Ceph), Gateway |
| `/etc/hosts` | Jeder Node | Hostname-zu-IP-Zuordnung |
| `/etc/corosync/corosync.conf` | Jeder Node | Corosync Ring-Adressen |
| `/etc/pve/ceph.conf` | Cluster-FS | public_network, cluster_network, MON-Adressen |
## Migrationsablauf (Phase 4)
1. Neue Konfigurationen werden auf alle Nodes verteilt (Staging)
2. Corosync wird auf allen Nodes gestoppt
3. pve-cluster (pmxcfs) wird gestoppt → `/etc/pve` unmounted
4. Corosync-Config wird direkt geschrieben (`/etc/corosync/corosync.conf`)
5. `/etc/hosts` wird aktualisiert
6. `/etc/network/interfaces` wird aktualisiert + Netzwerk-Reload:
- Remote-Nodes zuerst (fire-and-forget via `nohup`)
- Lokaler Node zuletzt
- Verifikation der neuen IPs mit Retry
7. Services starten (pve-cluster, corosync), Quorum abwarten, Ceph aktualisieren
> SSH funktioniert durchgehend via `sshpass` — unabhängig von `/etc/pve`.
## Rescue-Netzwerk (Emergency Mode)
**Szenario:** PVE01 hat bereits eine neue IP, PVE02-04 sind noch im alten Netz. Kein Node kann die anderen erreichen.
### Schnell: Nur Befehle anzeigen
```bash
python3 main.py --rescue-commands 10.99.99.0/24
```
Ausgabe:
```
RESCUE BEFEHLE
Subnetz: 10.99.99.0/24 | Bridge: vmbr0
pve1 (192.168.0.101):
ip addr add 10.99.99.1/24 dev vmbr0
pve2 (192.168.0.102):
ip addr add 10.99.99.2/24 dev vmbr0
pve3 (192.168.0.103):
ip addr add 10.99.99.3/24 dev vmbr0
pve4 (192.168.0.104):
ip addr add 10.99.99.4/24 dev vmbr0
Zum Entfernen:
ip addr del 10.99.99.1/24 dev vmbr0 # pve1
ip addr del 10.99.99.2/24 dev vmbr0 # pve2
ip addr del 10.99.99.3/24 dev vmbr0 # pve3
ip addr del 10.99.99.4/24 dev vmbr0 # pve4
```
Diese Befehle über IPMI/iLO/iDRAC/KVM-Konsole auf jedem Node ausführen.
### Interaktiv: Rescue + Migration
```bash
python3 main.py --rescue
```
oder einfach starten — wenn Nodes nicht erreichbar sind, wird automatisch gefragt:
```bash
python3 main.py
```
```
3 Node(s) nicht erreichbar.
Rescue-Netzwerk einrichten? [J/n]: j
```
Ablauf:
1. Du gibst ein freies Subnetz an (z.B. `10.99.99.0/24`)
2. Das Tool zeigt für jeden Node den `ip addr add` Befehl
3. Auf dem lokalen Node wird die IP automatisch gesetzt
4. Du führst die Befehle auf den anderen Nodes per Konsole aus
5. Das Tool testet die Verbindung und liest die Configs
6. Danach läuft die normale Migration
7. Rescue-IPs werden durch `ifreload -a` automatisch entfernt
### Wann brauche ich das?
- Ein oder mehrere Nodes haben bereits manuell eine neue IP bekommen
- Die Nodes liegen in verschiedenen Subnetzen
- SSH zwischen den Nodes funktioniert nicht mehr
- Du hast aber noch Zugriff auf die Konsolen (IPMI/iLO/iDRAC/KVM)
## Gebrochenes Quorum
Wenn bereits ein Node manuell geändert wurde und das Quorum verloren ist:
- Das Tool erkennt den Zustand automatisch in der Discovery-Phase
- Nicht erreichbare Nodes werden per Hostname gesucht
- Configs werden direkt geschrieben (nicht über `/etc/pve/`)
- Nach dem Netzwerk-Reload wird `pvecm expected 1` genutzt, um Quorum zu erzwingen
- Danach wird Ceph über das Cluster-Dateisystem aktualisiert
## Backups
Vor der Migration werden automatisch Backups erstellt:
```
/root/network-migration-backup-20260304_143022/
├── etc_network_interfaces
├── etc_hosts
├── etc_corosync_corosync.conf
├── etc_ceph_ceph.conf
├── etc_pve_corosync.conf
└── etc_pve_ceph.conf
```
### Restore (manuell)
```bash
# Beispiel: Netzwerk-Config wiederherstellen
cp /root/network-migration-backup-*/etc_network_interfaces /etc/network/interfaces
ifreload -a
# Corosync wiederherstellen
cp /root/network-migration-backup-*/etc_corosync_corosync.conf /etc/corosync/corosync.conf
systemctl restart corosync
```
## Empfohlene Reihenfolge bei Problemen
1. `pvecm status` — Cluster-Status prüfen
2. `pvecm expected 1` — Quorum erzwingen (Notfall)
3. `ceph -s` — Ceph-Status prüfen
4. `ceph -w` — Ceph-Recovery beobachten
5. `journalctl -u corosync` — Corosync-Logs prüfen
6. `journalctl -u pve-cluster` — pmxcfs-Logs prüfen
### Workaround: Ceph MON-Map manuell aktualisieren
Falls nach der Migration `ceph-mon` und `ceph-mgr` nicht starten (z.B. weil eine ältere Version des Tools die MON-Map nicht aktualisiert hat), muss die Ceph MON-Map manuell korrigiert werden. Die MON-Map ist eine interne Datenbank in der die MON-Adressen gespeichert sind — ein reines Update der `ceph.conf` reicht nicht.
**Auf jedem Node ausführen:**
```bash
# 1. MON stoppen
systemctl stop ceph-mon@$(hostname)
# 2. Aktuelle MON-Map extrahieren und prüfen
ceph-mon -i $(hostname) --extract-monmap /tmp/monmap
monmaptool --print /tmp/monmap
# 3. Alte Einträge entfernen (für jeden MON-Node)
monmaptool --rm pve1 /tmp/monmap
monmaptool --rm pve2 /tmp/monmap
monmaptool --rm pve3 /tmp/monmap
# 4. Neue Einträge mit neuen IPs hinzufügen
monmaptool --addv pve1 [v2:172.0.2.101:3300/0,v1:172.0.2.101:6789/0] /tmp/monmap
monmaptool --addv pve2 [v2:172.0.2.102:3300/0,v1:172.0.2.102:6789/0] /tmp/monmap
monmaptool --addv pve3 [v2:172.0.2.103:3300/0,v1:172.0.2.103:6789/0] /tmp/monmap
# 5. Ergebnis prüfen
monmaptool --print /tmp/monmap
# 6. Aktualisierte MON-Map zurückschreiben
ceph-mon -i $(hostname) --inject-monmap /tmp/monmap
# 7. Services starten
systemctl start ceph-mon@$(hostname)
systemctl restart ceph-mgr@$(hostname)
systemctl restart ceph-osd.target
# 8. Aufräumen
rm -f /tmp/monmap
```
> **Hinweis:** Node-Namen und IPs an das eigene Setup anpassen. Schritte 3+4 müssen alle MON-Nodes des Clusters enthalten, nicht nur den lokalen. Aktuelle Versionen des Tools aktualisieren die MON-Map automatisch.
## Hinweise
- Das Tool muss als **root** ausgeführt werden
- Alle Nodes müssen das gleiche Root-Passwort haben
- VMs/CTs werden **nicht** automatisch migriert oder gestoppt — das Netzwerk wird im laufenden Betrieb geändert
- Nach der Migration sollten VM-Netzwerke (Bridges in VM-Configs) geprüft werden, falls diese sich auf spezifische IPs beziehen
- Die Emergency-IPs (`ip addr add`) sind temporär und werden durch `ifreload -a` automatisch entfernt
- Bridges werden automatisch erkannt — keine manuelle Angabe nötig
- Beim Netzwerk-Reload werden Remote-Nodes zuerst umgestellt (fire-and-forget), der lokale Node zuletzt — so schneidet sich das Tool nicht selbst die Verbindung ab
- Getestet mit Proxmox VE 7.x und 8.x
## Projektstruktur
```
proxmox-cluster-network-changer/
├── main.py # Entry-Point, CLI, .env-Loader
├── discovery.py # Phase 1: Cluster-Config lesen & parsen
├── planner.py # Phase 2: IP-Mapping, neue Configs generieren
├── backup.py # Phase 3: Backup aller Configs
├── migrator.py # Phase 4: Migration durchführen (7 Schritte)
├── verifier.py # Phase 5: Post-Migration Checks
├── rescue.py # Rescue-Netzwerk (Emergency Mode)
├── ssh_manager.py # SSH via sshpass (Passwort-Auth)
├── config_parser.py # Parser für Corosync/Ceph/Network Configs
├── models.py # Dataclasses (NodeInfo, CorosyncConfig, etc.)
├── .env.example # Vorlage für SSH-Credentials
└── requirements.txt # Keine externen Dependencies
```
## Typische Szenarien
### Szenario 1: Normaler Umzug (alles funktioniert noch)
```bash
echo 'SSH_PASSWORD=dein-passwort' > .env
python3 main.py --dry-run # Erst testen
python3 main.py # Dann ausführen
```
### Szenario 2: Ein Node wurde bereits manuell geändert
PVE01 hat schon die neue IP, PVE02-04 noch die alte. Kein SSH möglich.
```bash
# Option A: Rescue-Befehle anzeigen und manuell ausführen
python3 main.py --rescue-commands 10.99.99.0/24
# -> Befehle auf allen Nodes per IPMI/KVM eingeben
# -> Dann normal starten:
python3 main.py --rescue
# Option B: Einfach starten, das Tool fragt automatisch
python3 main.py
# -> "3 Node(s) nicht erreichbar. Rescue-Netzwerk einrichten? [J/n]"
```
### Szenario 3: Nur Discovery (schauen was los ist)
```bash
python3 main.py --discover
```
### Szenario 4: Cluster komplett kaputt, kein Quorum
```bash
python3 main.py --rescue
# Das Tool:
# 1. Richtet Emergency-Netzwerk ein
# 2. Liest Configs über Emergency-IPs
# 3. Migriert alles
# 4. Erzwingt Quorum mit 'pvecm expected 1'
# 5. Schreibt Ceph-Config direkt (nicht über /etc/pve)
# 6. Räumt Emergency-IPs auf
```