121 lines
4.8 KiB
Python
121 lines
4.8 KiB
Python
"""
|
|
Service de gestion du statut de bootstrap des hôtes.
|
|
"""
|
|
|
|
import asyncio
|
|
from datetime import datetime, timezone
|
|
from typing import Dict, Optional
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.database import async_session_maker
|
|
|
|
|
|
class BootstrapStatusService:
|
|
"""Service pour gérer le statut de bootstrap des hôtes.
|
|
|
|
Cette version utilise la base de données SQLite via SQLAlchemy async.
|
|
Note: Le modèle BD utilise host_id (FK), mais ce service utilise host_name
|
|
pour la compatibilité avec le code existant. Il fait la correspondance via HostRepository.
|
|
"""
|
|
|
|
def __init__(self):
|
|
# Cache en mémoire pour éviter les requêtes BD répétées
|
|
self._cache: Dict[str, Dict] = {}
|
|
|
|
async def _get_host_id_by_name(self, session: AsyncSession, host_name: str) -> Optional[str]:
|
|
"""Récupère l'ID d'un hôte par son nom."""
|
|
from app.crud.host import HostRepository
|
|
repo = HostRepository(session)
|
|
host = await repo.get_by_name(host_name)
|
|
return host.id if host else None
|
|
|
|
def set_bootstrap_status(self, host_name: str, success: bool, details: str = None) -> Dict:
|
|
"""Enregistre le statut de bootstrap d'un hôte (version synchrone avec cache)."""
|
|
status_data = {
|
|
"bootstrap_ok": success,
|
|
"bootstrap_date": datetime.now(timezone.utc).isoformat(),
|
|
"details": details
|
|
}
|
|
self._cache[host_name] = status_data
|
|
|
|
# Planifier la sauvegarde en BD de manière asynchrone
|
|
asyncio.create_task(self._save_to_db(host_name, success, details))
|
|
|
|
return status_data
|
|
|
|
async def _save_to_db(self, host_name: str, success: bool, details: str = None):
|
|
"""Sauvegarde le statut dans la BD."""
|
|
try:
|
|
async with async_session_maker() as session:
|
|
host_id = await self._get_host_id_by_name(session, host_name)
|
|
if not host_id:
|
|
print(f"Host '{host_name}' non trouvé en BD pour bootstrap status")
|
|
return
|
|
|
|
from app.crud.bootstrap_status import BootstrapStatusRepository
|
|
repo = BootstrapStatusRepository(session)
|
|
await repo.create(
|
|
host_id=host_id,
|
|
status="success" if success else "failed",
|
|
last_attempt=datetime.now(timezone.utc),
|
|
error_message=None if success else details,
|
|
)
|
|
await session.commit()
|
|
except Exception as e:
|
|
print(f"Erreur sauvegarde bootstrap status en BD: {e}")
|
|
|
|
def get_bootstrap_status(self, host_name: str) -> Dict:
|
|
"""Récupère le statut de bootstrap d'un hôte depuis le cache."""
|
|
return self._cache.get(host_name, {
|
|
"bootstrap_ok": False,
|
|
"bootstrap_date": None,
|
|
"details": None
|
|
})
|
|
|
|
def get_all_status(self) -> Dict[str, Dict]:
|
|
"""Récupère le statut de tous les hôtes depuis le cache."""
|
|
return self._cache.copy()
|
|
|
|
def remove_host(self, host_name: str) -> bool:
|
|
"""Supprime le statut d'un hôte du cache."""
|
|
if host_name in self._cache:
|
|
del self._cache[host_name]
|
|
return True
|
|
return False
|
|
|
|
async def load_from_db(self):
|
|
"""Charge tous les statuts depuis la BD dans le cache (appelé au démarrage)."""
|
|
try:
|
|
async with async_session_maker() as session:
|
|
from sqlalchemy import select
|
|
from app.models.bootstrap_status import BootstrapStatus
|
|
from app.models.host import Host
|
|
|
|
# Récupérer tous les derniers statuts avec les noms d'hôtes
|
|
stmt = (
|
|
select(BootstrapStatus, Host.name)
|
|
.join(Host, BootstrapStatus.host_id == Host.id)
|
|
.order_by(BootstrapStatus.created_at.desc())
|
|
)
|
|
result = await session.execute(stmt)
|
|
|
|
# Garder seulement le dernier statut par hôte
|
|
seen_hosts = set()
|
|
for bs, host_name in result:
|
|
if host_name not in seen_hosts:
|
|
self._cache[host_name] = {
|
|
"bootstrap_ok": bs.status == "success",
|
|
"bootstrap_date": bs.last_attempt.isoformat() if bs.last_attempt else bs.created_at.isoformat(),
|
|
"details": bs.error_message
|
|
}
|
|
seen_hosts.add(host_name)
|
|
|
|
print(f"📋 {len(self._cache)} statut(s) bootstrap chargé(s) depuis la BD")
|
|
except Exception as e:
|
|
print(f"Erreur chargement bootstrap status depuis BD: {e}")
|
|
|
|
|
|
# Instance singleton du service
|
|
bootstrap_status_service = BootstrapStatusService()
|