update storage.cfg

This commit is contained in:
duffyduck 2026-03-05 08:27:01 +01:00
parent 4a9bb2f0f2
commit 4bb9b93baf
2 changed files with 95 additions and 32 deletions

View File

@ -471,7 +471,7 @@ ceph -s
### 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.
Nach der Migration kann CephFS nicht erreichbar sein, weil der Kernel-Mount noch die alten MON-IPs cached. Das passiert unabhängig davon, ob `monhost` in der `storage.cfg` steht oder nicht. Aktuelle Versionen des Tools machen den Remount automatisch.
**Symptom:** CephFS-Storage zeigt Fehler in der GUI, `mount | grep ceph` zeigt alte IPs:
@ -479,27 +479,37 @@ Falls CephFS oder RBD-Storage nach der Migration nicht gemountet werden können,
172.0.4.1,172.0.4.2,172.0.4.3:/ on /mnt/pve/cephfs type ceph (...)
```
**Lösung:**
**Fall 1: Keine `monhost`-Einträge in storage.cfg (Standard bei Proxmox)**
Proxmox holt sich die MON-IPs automatisch aus `/etc/ceph/ceph.conf`. Es reicht ein Remount:
```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:
# Auf JEDEM Node:
umount /mnt/pve/cephfs
mount /mnt/pve/cephfs
# Oder auf allen Nodes per Neustart des Storage-Dienstes:
systemctl restart pve-ha-lrm
# Prüfen ob die neuen IPs verwendet werden:
mount | grep ceph
```
> **Hinweis:** Die Storage-Namen (`cephfs`, `local-rbd`) können bei jedem Setup anders heißen. Mit `pvesm status` werden alle konfigurierten Storages angezeigt.
**Fall 2: Explizite `monhost`-Einträge in storage.cfg**
```bash
# 1. Prüfen ob monhost-Einträge vorhanden sind:
grep monhost /etc/pve/storage.cfg
# 2. Falls ja, 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 data --monhost 192.168.101.1,192.168.101.2,192.168.101.3
# 4. Dann Remount auf JEDEM Node:
umount /mnt/pve/cephfs
mount /mnt/pve/cephfs
```
> **Hinweis:** Die Storage-Namen (`cephfs`, `data`) können bei jedem Setup anders heißen. Mit `pvesm status` werden alle konfigurierten Storages angezeigt.
## Hinweise

View File

@ -391,10 +391,11 @@ class Migrator:
if configs.get('ceph'):
self._update_ceph(plan, configs)
# Update storage.cfg (CephFS/RBD monhost entries)
# Update storage.cfg (CephFS/RBD monhost entries) and remount CephFS
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)
self._remount_cephfs(plan)
# Cleanup staging directories
print("\n Staging-Verzeichnisse aufräumen...")
@ -436,11 +437,12 @@ class Migrator:
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.
"""Update /etc/pve/storage.cfg with new MON IPs and remount CephFS.
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.
CephFS and RBD storage entries may contain a 'monhost' field with
MON IP addresses. If present, these must be updated. Additionally,
active CephFS mounts use the old IPs in the kernel and need a remount
regardless of whether monhost is in storage.cfg or not.
"""
print("\n [Storage] /etc/pve/storage.cfg prüfen...")
@ -459,17 +461,14 @@ class Migrator:
print(f" [Storage] WARNUNG: storage.cfg nicht lesbar: {err}")
return
# Check if any old IPs are present
# Check if any old IPs are present in storage.cfg
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
if needs_update:
# Replace old IPs with new IPs
new_content = content
for old_ip, new_ip in ip_mapping.items():
@ -480,6 +479,60 @@ class Migrator:
print(" [Storage] /etc/pve/storage.cfg aktualisiert (monhost IPs ersetzt)")
else:
print(f" [Storage] FEHLER: {msg}")
else:
print(" [Storage] Keine alten IPs in storage.cfg (monhost wird aus ceph.conf gelesen)")
def _remount_cephfs(self, plan: MigrationPlan):
"""Remount CephFS on all nodes after migration.
The kernel CephFS mount caches the old MON IPs. Even if ceph.conf
is updated, the existing mount still uses the old addresses.
A remount picks up the new IPs from the updated config.
"""
# Check if any CephFS mounts exist on the local node
rc, mounts, _ = self.ssh.execute_local("mount -t ceph 2>/dev/null")
if rc != 0 or not mounts or not mounts.strip():
return
# Extract CephFS mount points (skip non-cephfs mounts)
mount_points = []
for line in mounts.strip().split('\n'):
# Format: 1.2.3.4,5.6.7.8:/ on /mnt/pve/cephfs type ceph (...)
if ' type ceph ' in line:
parts = line.split(' on ')
if len(parts) >= 2:
mp = parts[1].split(' type ')[0].strip()
mount_points.append(mp)
if not mount_points:
return
print(f"\n [CephFS] {len(mount_points)} Mount(s) gefunden, Remount auf allen Nodes...")
for node in plan.nodes:
if not node.is_reachable:
continue
new_host = node.new_ip if not node.is_local else node.ssh_host
for mp in mount_points:
if node.is_local or True: # Remount on all nodes
rc, _, err = self.ssh.run_on_node(
new_host,
f"umount {mp} 2>/dev/null; mount {mp}",
node.is_local, timeout=30,
)
if rc == 0:
print(f" [{node.name}] CephFS {mp} remounted")
else:
# Mount might not exist on this node yet, try just mount
rc2, _, _ = self.ssh.run_on_node(
new_host, f"mount {mp} 2>/dev/null",
node.is_local, timeout=30,
)
if rc2 == 0:
print(f" [{node.name}] CephFS {mp} mounted")
else:
print(f" [{node.name}] CephFS {mp} WARNUNG: Remount fehlgeschlagen: {err}")
def _wait_for_quorum(self, timeout: int = 60) -> bool:
"""Wait for cluster quorum to be established."""