update storage_cfg for cephfs mount and changed readme
This commit is contained in:
parent
9babedf6ca
commit
4a9bb2f0f2
33
README.md
33
README.md
|
|
@ -155,6 +155,7 @@ Wenn Ceph Public/Cluster auf separaten NICs liegen, werden die IPs einzeln pro N
|
||||||
| `/etc/hosts` | Jeder Node | Hostname-zu-IP-Zuordnung |
|
| `/etc/hosts` | Jeder Node | Hostname-zu-IP-Zuordnung |
|
||||||
| `/etc/corosync/corosync.conf` | Jeder Node | Corosync Ring-Adressen |
|
| `/etc/corosync/corosync.conf` | Jeder Node | Corosync Ring-Adressen |
|
||||||
| `/etc/pve/ceph.conf` | Cluster-FS | public_network, cluster_network, MON-Adressen |
|
| `/etc/pve/ceph.conf` | Cluster-FS | public_network, cluster_network, MON-Adressen |
|
||||||
|
| `/etc/pve/storage.cfg` | Cluster-FS | monhost-IPs für CephFS- und RBD-Storage |
|
||||||
|
|
||||||
## Migrationsablauf (Phase 4)
|
## Migrationsablauf (Phase 4)
|
||||||
|
|
||||||
|
|
@ -468,6 +469,38 @@ ceph -s
|
||||||
|
|
||||||
> **Hinweis:** Falls zusätzlich `clock skew detected` angezeigt wird, NTP auf den betroffenen Nodes prüfen: `systemctl status chrony` oder `systemctl status ntp`. Nach einer Migration mit Neustarts kann die Uhrzeit kurzzeitig abweichen — das korrigiert sich in der Regel automatisch.
|
> **Hinweis:** Falls zusätzlich `clock skew detected` angezeigt wird, NTP auf den betroffenen Nodes prüfen: `systemctl status chrony` oder `systemctl status ntp`. Nach einer Migration mit Neustarts kann die Uhrzeit kurzzeitig abweichen — das korrigiert sich in der Regel automatisch.
|
||||||
|
|
||||||
|
### Fehlerbehebung: CephFS/RBD-Storage nicht erreichbar nach Migration
|
||||||
|
|
||||||
|
Falls CephFS oder RBD-Storage nach der Migration nicht gemountet werden können, liegt es daran, dass in `/etc/pve/storage.cfg` noch die alten MON-IPs stehen. Aktuelle Versionen des Tools aktualisieren die `storage.cfg` automatisch.
|
||||||
|
|
||||||
|
**Symptom:** CephFS-Storage zeigt Fehler in der GUI, `mount | grep ceph` zeigt alte IPs:
|
||||||
|
|
||||||
|
```
|
||||||
|
172.0.4.1,172.0.4.2,172.0.4.3:/ on /mnt/pve/cephfs type ceph (...)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Prüfen welche IPs in storage.cfg stehen:
|
||||||
|
grep monhost /etc/pve/storage.cfg
|
||||||
|
|
||||||
|
# 2. monhost für CephFS aktualisieren (neue MON-IPs kommasepariert):
|
||||||
|
pvesm set cephfs --monhost 192.168.101.1,192.168.101.2,192.168.101.3
|
||||||
|
|
||||||
|
# 3. Falls RBD-Storage vorhanden:
|
||||||
|
pvesm set local-rbd --monhost 192.168.101.1,192.168.101.2,192.168.101.3
|
||||||
|
|
||||||
|
# 4. CephFS neu mounten:
|
||||||
|
umount /mnt/pve/cephfs
|
||||||
|
mount /mnt/pve/cephfs
|
||||||
|
|
||||||
|
# Oder auf allen Nodes per Neustart des Storage-Dienstes:
|
||||||
|
systemctl restart pve-ha-lrm
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Hinweis:** Die Storage-Namen (`cephfs`, `local-rbd`) können bei jedem Setup anders heißen. Mit `pvesm status` werden alle konfigurierten Storages angezeigt.
|
||||||
|
|
||||||
## Hinweise
|
## Hinweise
|
||||||
|
|
||||||
- Das Tool muss als **root** ausgeführt werden
|
- Das Tool muss als **root** ausgeführt werden
|
||||||
|
|
|
||||||
51
migrator.py
51
migrator.py
|
|
@ -391,6 +391,11 @@ class Migrator:
|
||||||
if configs.get('ceph'):
|
if configs.get('ceph'):
|
||||||
self._update_ceph(plan, configs)
|
self._update_ceph(plan, configs)
|
||||||
|
|
||||||
|
# Update storage.cfg (CephFS/RBD monhost entries)
|
||||||
|
ip_mapping = {n.current_ip: n.new_ip for n in plan.nodes if n.new_ip}
|
||||||
|
if ip_mapping:
|
||||||
|
self._update_storage_cfg(ip_mapping)
|
||||||
|
|
||||||
# Cleanup staging directories
|
# Cleanup staging directories
|
||||||
print("\n Staging-Verzeichnisse aufräumen...")
|
print("\n Staging-Verzeichnisse aufräumen...")
|
||||||
for node in plan.nodes:
|
for node in plan.nodes:
|
||||||
|
|
@ -430,6 +435,52 @@ class Migrator:
|
||||||
print(" [Corosync] WARNUNG: /etc/pve nicht beschreibbar!")
|
print(" [Corosync] WARNUNG: /etc/pve nicht beschreibbar!")
|
||||||
print(" [Corosync] Manuell ausführen: cp /etc/corosync/corosync.conf /etc/pve/corosync.conf")
|
print(" [Corosync] Manuell ausführen: cp /etc/corosync/corosync.conf /etc/pve/corosync.conf")
|
||||||
|
|
||||||
|
def _update_storage_cfg(self, ip_mapping: dict[str, str]):
|
||||||
|
"""Update /etc/pve/storage.cfg with new MON IPs.
|
||||||
|
|
||||||
|
CephFS and RBD storage entries contain a 'monhost' field with the
|
||||||
|
MON IP addresses. After a network migration these must be updated,
|
||||||
|
otherwise CephFS mounts and RBD connections fail.
|
||||||
|
"""
|
||||||
|
print("\n [Storage] /etc/pve/storage.cfg prüfen...")
|
||||||
|
|
||||||
|
# Check if /etc/pve is writable
|
||||||
|
rc, _, _ = self.ssh.execute_local(
|
||||||
|
"touch /etc/pve/.storage_test && rm -f /etc/pve/.storage_test"
|
||||||
|
)
|
||||||
|
if rc != 0:
|
||||||
|
print(" [Storage] WARNUNG: /etc/pve nicht beschreibbar!")
|
||||||
|
print(" [Storage] Manuell ausführen: pvesm set <storage> --monhost <neue-IPs>")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Read current storage.cfg
|
||||||
|
rc, content, err = self.ssh.execute_local("cat /etc/pve/storage.cfg")
|
||||||
|
if rc != 0 or not content:
|
||||||
|
print(f" [Storage] WARNUNG: storage.cfg nicht lesbar: {err}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if any old IPs are present
|
||||||
|
needs_update = False
|
||||||
|
for old_ip in ip_mapping:
|
||||||
|
if old_ip in content:
|
||||||
|
needs_update = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not needs_update:
|
||||||
|
print(" [Storage] Keine alten IPs in storage.cfg gefunden")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Replace old IPs with new IPs
|
||||||
|
new_content = content
|
||||||
|
for old_ip, new_ip in ip_mapping.items():
|
||||||
|
new_content = new_content.replace(old_ip, new_ip)
|
||||||
|
|
||||||
|
ok, msg = self.ssh.write_local_file("/etc/pve/storage.cfg", new_content)
|
||||||
|
if ok:
|
||||||
|
print(" [Storage] /etc/pve/storage.cfg aktualisiert (monhost IPs ersetzt)")
|
||||||
|
else:
|
||||||
|
print(f" [Storage] FEHLER: {msg}")
|
||||||
|
|
||||||
def _wait_for_quorum(self, timeout: int = 60) -> bool:
|
def _wait_for_quorum(self, timeout: int = 60) -> bool:
|
||||||
"""Wait for cluster quorum to be established."""
|
"""Wait for cluster quorum to be established."""
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue