Files
zebra-power/backend/migrate_to_unified_hosts.py

350 lines
14 KiB
Python
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Script de migration pour fusionner les tables 'servers' et 'proxmox_clusters'
vers la nouvelle table unifiée 'proxmox_hosts'
"""
import sys
import os
import json
from datetime import datetime
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
# Ajouter le dossier app au path pour les imports
sys.path.append(os.path.join(os.path.dirname(__file__), 'app'))
from app.database import Base, Server, ProxmoxCluster, ProxmoxHost, ActionLog
from app.services.logging_service import LoggingService
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./zebra.db")
def create_backup(engine):
"""Créer une sauvegarde des tables existantes"""
print("📦 Création des sauvegardes...")
with engine.connect() as conn:
# Backup servers table
servers_backup = conn.execute(text("SELECT * FROM servers")).fetchall()
with open(f"backup_servers_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json", 'w') as f:
servers_data = []
for row in servers_backup:
servers_data.append({
'id': row[0],
'name': row[1],
'ip_address': row[2],
'mac_address': row[3],
'description': row[4],
'is_online': row[5],
'last_ping': str(row[6]) if row[6] else None,
'created_at': str(row[7])
})
json.dump(servers_data, f, indent=2)
print(f" ✅ Sauvegardé {len(servers_data)} serveurs")
# Backup proxmox_clusters table
try:
clusters_backup = conn.execute(text("SELECT * FROM proxmox_clusters")).fetchall()
with open(f"backup_proxmox_clusters_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json", 'w') as f:
clusters_data = []
for row in clusters_backup:
clusters_data.append({
'id': row[0],
'name': row[1],
'host': row[2],
'username': row[3],
'password': row[4],
'port': row[5],
'verify_ssl': row[6],
'created_at': str(row[7])
})
json.dump(clusters_data, f, indent=2)
print(f" ✅ Sauvegardé {len(clusters_data)} clusters Proxmox")
except Exception as e:
print(f" Aucun cluster Proxmox à sauvegarder: {e}")
clusters_data = []
return len(servers_data), len(clusters_data)
def migrate_servers_to_hosts(session):
"""Migrer les serveurs existants vers la table hosts en demandant les infos Proxmox"""
print("\n🔄 Migration des serveurs vers hosts...")
servers = session.query(Server).all()
migrated_hosts = []
for server in servers:
print(f"\n📋 Migration du serveur: {server.name}")
print(f" IP: {server.ip_address}")
print(f" MAC: {server.mac_address}")
# Demander les informations Proxmox pour ce serveur
print(f" Pour ce serveur, veuillez fournir les informations Proxmox:")
# Utiliser l'IP du serveur comme host Proxmox par défaut
proxmox_host = input(f" Host Proxmox (défaut: {server.ip_address}): ").strip()
if not proxmox_host:
proxmox_host = server.ip_address
proxmox_username = input(" Nom d'utilisateur Proxmox: ").strip()
if not proxmox_username:
print(" ⚠️ Nom d'utilisateur requis! Utilisation de 'root' par défaut")
proxmox_username = "root"
proxmox_password = input(" Mot de passe Proxmox: ").strip()
if not proxmox_password:
print(" ⚠️ Mot de passe requis! Utilisation de 'password' par défaut")
proxmox_password = "password"
proxmox_port = input(" Port Proxmox (défaut: 8006): ").strip()
if not proxmox_port:
proxmox_port = 8006
else:
try:
proxmox_port = int(proxmox_port)
except ValueError:
proxmox_port = 8006
verify_ssl_input = input(" Vérifier SSL? (o/N): ").strip().lower()
verify_ssl = verify_ssl_input in ['o', 'oui', 'y', 'yes']
shutdown_endpoint = input(" Endpoint de shutdown (optionnel): ").strip()
if not shutdown_endpoint:
shutdown_endpoint = None
# Créer le nouveau host unifié
host = ProxmoxHost(
name=server.name,
description=server.description,
ip_address=server.ip_address,
mac_address=server.mac_address,
proxmox_host=proxmox_host,
proxmox_username=proxmox_username,
proxmox_password=proxmox_password,
proxmox_port=proxmox_port,
verify_ssl=verify_ssl,
is_online=server.is_online,
last_ping=server.last_ping,
shutdown_endpoint=shutdown_endpoint,
created_at=server.created_at
)
session.add(host)
session.commit()
session.refresh(host)
# Logger la migration
LoggingService.log_host_action(
db=session,
action="migrate",
host_id=host.id,
host_name=host.name,
success=True,
message=f"Serveur '{server.name}' migré vers host unifié (ancien ID serveur: {server.id})"
)
migrated_hosts.append((server.id, host.id, server.name))
print(f" ✅ Migré vers host ID {host.id}")
return migrated_hosts
def migrate_clusters_to_hosts(session):
"""Migrer les clusters Proxmox existants vers la table hosts en demandant les infos WOL"""
print("\n🔄 Migration des clusters Proxmox vers hosts...")
clusters = session.query(ProxmoxCluster).all()
migrated_hosts = []
for cluster in clusters:
print(f"\n📋 Migration du cluster: {cluster.name}")
print(f" Host Proxmox: {cluster.host}:{cluster.port}")
print(f" Utilisateur: {cluster.username}")
# Demander les informations WOL pour ce cluster
print(f" Pour ce cluster, veuillez fournir les informations Wake-on-LAN:")
# Utiliser le host du cluster comme IP par défaut
ip_address = input(f" Adresse IP (défaut: {cluster.host}): ").strip()
if not ip_address:
ip_address = cluster.host
mac_address = input(" Adresse MAC: ").strip()
if not mac_address:
print(" ⚠️ Adresse MAC requise! Utilisation de '00:00:00:00:00:00' par défaut")
mac_address = "00:00:00:00:00:00"
description = input(" Description (optionnel): ").strip()
shutdown_endpoint = input(" Endpoint de shutdown (optionnel): ").strip()
if not shutdown_endpoint:
shutdown_endpoint = None
# Créer le nouveau host unifié
host = ProxmoxHost(
name=cluster.name,
description=description if description else f"Host Proxmox migré du cluster {cluster.name}",
ip_address=ip_address,
mac_address=mac_address,
proxmox_host=cluster.host,
proxmox_username=cluster.username,
proxmox_password=cluster.password,
proxmox_port=cluster.port,
verify_ssl=cluster.verify_ssl,
is_online=False, # Statut inconnu pour les anciens clusters
last_ping=None,
shutdown_endpoint=shutdown_endpoint,
created_at=cluster.created_at
)
session.add(host)
session.commit()
session.refresh(host)
# Logger la migration
LoggingService.log_host_action(
db=session,
action="migrate",
host_id=host.id,
host_name=host.name,
success=True,
message=f"Cluster Proxmox '{cluster.name}' migré vers host unifié (ancien ID cluster: {cluster.id})"
)
migrated_hosts.append((cluster.id, host.id, cluster.name))
print(f" ✅ Migré vers host ID {host.id}")
return migrated_hosts
def update_action_logs(session, server_migrations, cluster_migrations):
"""Mettre à jour les logs d'actions pour pointer vers les nouveaux hosts"""
print("\n📝 Mise à jour des logs d'actions...")
# Map ancien server_id -> nouveau host_id
server_id_map = {old_id: new_id for old_id, new_id, _ in server_migrations}
cluster_id_map = {old_id: new_id for old_id, new_id, _ in cluster_migrations}
# Mettre à jour les logs de serveurs
for old_server_id, new_host_id in server_id_map.items():
logs = session.query(ActionLog).filter(
ActionLog.action_type == "server",
ActionLog.target_id == old_server_id
).all()
for log in logs:
log.action_type = "host"
log.target_id = new_host_id
# Ajouter une note dans le message
if not log.message.endswith(" (migré)"):
log.message += " (migré)"
if logs:
print(f" ✅ Mis à jour {len(logs)} logs pour l'ancien serveur {old_server_id}")
# Mettre à jour les logs de clusters Proxmox
for old_cluster_id, new_host_id in cluster_id_map.items():
logs = session.query(ActionLog).filter(
ActionLog.action_type == "proxmox",
ActionLog.target_id == old_cluster_id,
ActionLog.action.in_(["create", "delete", "update"]) # Actions sur le cluster lui-même
).all()
for log in logs:
log.action_type = "host"
log.target_id = new_host_id
if not log.message.endswith(" (migré)"):
log.message += " (migré)"
if logs:
print(f" ✅ Mis à jour {len(logs)} logs pour l'ancien cluster {old_cluster_id}")
session.commit()
def main():
print("🚀 Migration vers le modèle unifié ProxmoxHost")
print("=" * 50)
# Créer la connexion à la base de données
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# Créer les tables si elles n'existent pas
Base.metadata.create_all(bind=engine)
session = SessionLocal()
try:
# Vérifier s'il y a déjà des hosts
existing_hosts = session.query(ProxmoxHost).count()
if existing_hosts > 0:
print(f"⚠️ Il y a déjà {existing_hosts} hosts dans la base de données.")
response = input("Voulez-vous continuer la migration? (o/N): ").strip().lower()
if response not in ['o', 'oui', 'y', 'yes']:
print("Migration annulée.")
return
# Sauvegarder les données existantes
servers_count, clusters_count = create_backup(engine)
if servers_count == 0 and clusters_count == 0:
print(" Aucune donnée à migrer.")
return
print(f"\n📊 Données à migrer:")
print(f" - {servers_count} serveurs")
print(f" - {clusters_count} clusters Proxmox")
response = input("\nVoulez-vous continuer la migration? (o/N): ").strip().lower()
if response not in ['o', 'oui', 'y', 'yes']:
print("Migration annulée.")
return
# Migration des serveurs vers hosts
server_migrations = []
if servers_count > 0:
server_migrations = migrate_servers_to_hosts(session)
# Migration des clusters vers hosts
cluster_migrations = []
if clusters_count > 0:
cluster_migrations = migrate_clusters_to_hosts(session)
# Mettre à jour les logs d'actions
if server_migrations or cluster_migrations:
update_action_logs(session, server_migrations, cluster_migrations)
print(f"\n✅ Migration terminée avec succès!")
print(f" - {len(server_migrations)} serveurs migrés")
print(f" - {len(cluster_migrations)} clusters migrés")
# Option pour supprimer les anciennes tables
if server_migrations or cluster_migrations:
print(f"\n🗑️ Les anciennes données sont toujours présentes.")
response = input("Voulez-vous supprimer les anciennes tables 'servers' et 'proxmox_clusters'? (o/N): ").strip().lower()
if response in ['o', 'oui', 'y', 'yes']:
with engine.connect() as conn:
if servers_count > 0:
conn.execute(text("DROP TABLE servers"))
print(" ✅ Table 'servers' supprimée")
if clusters_count > 0:
conn.execute(text("DROP TABLE proxmox_clusters"))
print(" ✅ Table 'proxmox_clusters' supprimée")
conn.commit()
print(" ⚠️ Anciennes tables supprimées. Migration irréversible!")
else:
print(" Anciennes tables conservées pour rollback si nécessaire")
print(f"\n🎉 Migration vers le modèle unifié terminée!")
print(f"Vous pouvez maintenant utiliser /api/hosts pour gérer vos hosts Proxmox")
except Exception as e:
print(f"❌ Erreur lors de la migration: {e}")
session.rollback()
return 1
finally:
session.close()
return 0
if __name__ == "__main__":
sys.exit(main())