update ssh keys authorization file
This commit is contained in:
parent
2ad6a8dbc4
commit
82ddb25c01
|
|
@ -91,11 +91,15 @@ def parse_ceph_conf(content: str) -> CephConfig:
|
|||
if m:
|
||||
config.cluster_network = m.group(1)
|
||||
|
||||
# Extract mon_host
|
||||
# Extract mon_host (can be comma-separated, space-separated, or both)
|
||||
m = re.search(r'mon.host\s*=\s*(.+)', content)
|
||||
if m:
|
||||
hosts_str = m.group(1).strip()
|
||||
config.mon_hosts = [h.strip() for h in hosts_str.split(',') if h.strip()]
|
||||
# Split by comma or whitespace
|
||||
config.mon_hosts = [
|
||||
h.strip() for h in re.split(r'[,\s]+', hosts_str)
|
||||
if h.strip()
|
||||
]
|
||||
|
||||
# Extract [mon.X] sections
|
||||
mon_sections = re.findall(
|
||||
|
|
|
|||
84
migrator.py
84
migrator.py
|
|
@ -36,33 +36,39 @@ class Migrator:
|
|||
if not self._distribute_configs(plan, configs, dry_run):
|
||||
return False
|
||||
|
||||
# Step 2: Stop Corosync on all nodes
|
||||
print("\n[2/7] Corosync stoppen auf allen Nodes...")
|
||||
# Step 2: Preserve SSH keys before stopping pve-cluster
|
||||
# /etc/pve/priv/authorized_keys gets unmounted when pve-cluster stops!
|
||||
print("\n[2/8] SSH-Keys sichern (werden nach pve-cluster stop benötigt)...")
|
||||
if not self._preserve_ssh_keys(reachable_nodes, dry_run):
|
||||
return False
|
||||
|
||||
# Step 3: Stop Corosync on all nodes
|
||||
print("\n[3/8] Corosync stoppen auf allen Nodes...")
|
||||
if not self._stop_corosync(reachable_nodes, dry_run):
|
||||
return False
|
||||
|
||||
# Step 3: Stop pve-cluster (pmxcfs) to release corosync.conf
|
||||
print("\n[3/7] pve-cluster stoppen...")
|
||||
# Step 4: Stop pve-cluster (pmxcfs) to release corosync.conf
|
||||
print("\n[4/8] pve-cluster stoppen...")
|
||||
if not self._stop_pve_cluster(reachable_nodes, dry_run):
|
||||
return False
|
||||
|
||||
# Step 4: Write corosync config directly
|
||||
print("\n[4/7] Corosync-Konfiguration aktualisieren...")
|
||||
# Step 5: Write corosync config directly
|
||||
print("\n[5/8] Corosync-Konfiguration aktualisieren...")
|
||||
if not self._update_corosync(reachable_nodes, configs, dry_run):
|
||||
return False
|
||||
|
||||
# Step 5: Update /etc/hosts on all nodes
|
||||
print("\n[5/7] /etc/hosts aktualisieren...")
|
||||
# Step 6: Update /etc/hosts on all nodes
|
||||
print("\n[6/8] /etc/hosts aktualisieren...")
|
||||
if not self._update_hosts(plan, configs, dry_run):
|
||||
return False
|
||||
|
||||
# Step 6: Update network interfaces and restart networking
|
||||
print("\n[6/7] Netzwerk-Interfaces aktualisieren und Netzwerk neu starten...")
|
||||
# Step 7: Update network interfaces and restart networking
|
||||
print("\n[7/8] Netzwerk-Interfaces aktualisieren und Netzwerk neu starten...")
|
||||
if not self._update_network(plan, configs, dry_run):
|
||||
return False
|
||||
|
||||
# Step 7: Start services back up
|
||||
print("\n[7/7] Services starten...")
|
||||
# Step 8: Start services back up
|
||||
print("\n[8/8] Services starten...")
|
||||
if not self._start_services(plan, configs, dry_run):
|
||||
return False
|
||||
|
||||
|
|
@ -157,6 +163,56 @@ class Migrator:
|
|||
|
||||
return True
|
||||
|
||||
def _preserve_ssh_keys(self, nodes: list, dry_run: bool) -> bool:
|
||||
"""Copy /etc/pve/priv/authorized_keys to ~/.ssh/ on all nodes.
|
||||
|
||||
When pve-cluster (pmxcfs) is stopped, /etc/pve gets unmounted and
|
||||
the cluster SSH keys disappear. This breaks SSH between nodes.
|
||||
We temporarily copy them to ~/.ssh/authorized_keys so SSH keeps working.
|
||||
"""
|
||||
for node in nodes:
|
||||
if dry_run:
|
||||
print(f" [{node.name}] Würde SSH-Keys sichern")
|
||||
continue
|
||||
|
||||
# Append pve keys to ~/.ssh/authorized_keys (avoid duplicates)
|
||||
cmd = (
|
||||
"if [ -f /etc/pve/priv/authorized_keys ]; then "
|
||||
" mkdir -p /root/.ssh && "
|
||||
" cp /root/.ssh/authorized_keys /root/.ssh/authorized_keys.pre_migration 2>/dev/null; "
|
||||
" cat /etc/pve/priv/authorized_keys >> /root/.ssh/authorized_keys && "
|
||||
" sort -u -o /root/.ssh/authorized_keys /root/.ssh/authorized_keys && "
|
||||
" chmod 600 /root/.ssh/authorized_keys && "
|
||||
" echo ok; "
|
||||
"else "
|
||||
" echo no_pve_keys; "
|
||||
"fi"
|
||||
)
|
||||
rc, stdout, err = self.ssh.run_on_node(
|
||||
node.ssh_host, cmd, node.is_local
|
||||
)
|
||||
if rc == 0 and "ok" in stdout:
|
||||
print(f" [{node.name}] SSH-Keys gesichert")
|
||||
elif "no_pve_keys" in stdout:
|
||||
print(f" [{node.name}] Keine PVE-Keys gefunden (übersprungen)")
|
||||
else:
|
||||
print(f" [{node.name}] WARNUNG SSH-Keys: {err}")
|
||||
return True
|
||||
|
||||
def _restore_ssh_keys(self, nodes: list):
|
||||
"""Restore original ~/.ssh/authorized_keys after migration."""
|
||||
for node in nodes:
|
||||
new_host = node.new_ip if not node.is_local else node.ssh_host
|
||||
cmd = (
|
||||
"if [ -f /root/.ssh/authorized_keys.pre_migration ]; then "
|
||||
" mv /root/.ssh/authorized_keys.pre_migration /root/.ssh/authorized_keys && "
|
||||
" echo restored; "
|
||||
"else "
|
||||
" echo no_backup; "
|
||||
"fi"
|
||||
)
|
||||
self.ssh.run_on_node(new_host, cmd, node.is_local)
|
||||
|
||||
def _stop_corosync(self, nodes: list, dry_run: bool) -> bool:
|
||||
"""Stop corosync on all nodes."""
|
||||
for node in nodes:
|
||||
|
|
@ -337,6 +393,10 @@ class Migrator:
|
|||
if configs.get('ceph'):
|
||||
self._update_ceph(plan, configs)
|
||||
|
||||
# Restore original SSH keys (pve-cluster manages them again now)
|
||||
print("\n SSH-Keys wiederherstellen...")
|
||||
self._restore_ssh_keys(plan.nodes)
|
||||
|
||||
# Cleanup staging directories
|
||||
print("\n Staging-Verzeichnisse aufräumen...")
|
||||
for node in plan.nodes:
|
||||
|
|
|
|||
35
planner.py
35
planner.py
|
|
@ -34,12 +34,39 @@ class Planner:
|
|||
# Detect old network from first node
|
||||
if nodes:
|
||||
old_ip = ipaddress.ip_address(nodes[0].current_ip)
|
||||
for iface in nodes[0].interfaces:
|
||||
if iface.address == str(old_ip):
|
||||
plan.old_network = f"{ipaddress.ip_network(f'{iface.address}/{iface.cidr}', strict=False)}"
|
||||
plan.bridge_name = iface.name
|
||||
# Try to find matching interface
|
||||
for node in nodes:
|
||||
for iface in node.interfaces:
|
||||
if iface.address == str(old_ip) or (
|
||||
iface.address and iface.cidr and
|
||||
ipaddress.ip_address(iface.address) in
|
||||
ipaddress.ip_network(f'{iface.address}/{iface.cidr}', strict=False) and
|
||||
old_ip in ipaddress.ip_network(f'{iface.address}/{iface.cidr}', strict=False)
|
||||
):
|
||||
plan.old_network = str(ipaddress.ip_network(
|
||||
f'{iface.address}/{iface.cidr}', strict=False
|
||||
))
|
||||
plan.bridge_name = iface.name
|
||||
break
|
||||
if plan.old_network:
|
||||
break
|
||||
|
||||
# Fallback: try to guess from corosync IPs
|
||||
if not plan.old_network:
|
||||
# Find common network from all corosync node IPs
|
||||
for cidr_guess in [24, 16, 8]:
|
||||
net = ipaddress.ip_network(
|
||||
f'{nodes[0].current_ip}/{cidr_guess}', strict=False
|
||||
)
|
||||
if all(ipaddress.ip_address(n.current_ip) in net for n in nodes):
|
||||
plan.old_network = str(net)
|
||||
break
|
||||
|
||||
if plan.old_network:
|
||||
print(f" Erkanntes altes Netzwerk: {plan.old_network}")
|
||||
else:
|
||||
print(" [!] Altes Netzwerk konnte nicht erkannt werden")
|
||||
|
||||
# Generate IP mapping suggestions
|
||||
print("\n[IP-Mapping]")
|
||||
print("Für jeden Node wird eine neue IP benötigt.\n")
|
||||
|
|
|
|||
Loading…
Reference in New Issue