Bruno Charest 68a9b0f390
Some checks failed
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
Remove Node.js cache files containing npm vulnerability data for vitest and vite packages
2025-12-15 20:36:06 -05:00

115 lines
3.5 KiB
Python

"""
Routes API pour les health checks.
"""
from datetime import datetime, timezone
import sys
from fastapi import APIRouter, Depends, HTTPException
from app.core.dependencies import verify_api_key
from app.schemas.health import HealthCheck
from app.schemas.common import LogEntry, SystemMetrics
from app.services import ws_manager, db
router = APIRouter()
@router.get("", response_model=SystemMetrics)
async def get_metrics(api_key_valid: bool = Depends(verify_api_key)):
"""Récupère les métriques système."""
return db.metrics
@router.get("/global")
async def global_health_check():
"""Endpoint de healthcheck global utilisé par Docker.
Ne nécessite pas de clé API pour permettre aux orchestrateurs
de vérifier l'état du service facilement.
"""
return {
"status": "ok",
"service": "homelab-automation-api",
"timestamp": datetime.now(timezone.utc).isoformat()
}
@router.get("/runtime")
async def runtime_info(api_key_valid: bool = Depends(verify_api_key)):
"""Runtime diagnostics (python executable, asyncssh availability)."""
try:
import asyncssh # type: ignore
asyncssh_ok = True
asyncssh_version = getattr(asyncssh, "__version__", None)
except Exception as e:
asyncssh_ok = False
asyncssh_version = None
asyncssh_error = str(e)
else:
asyncssh_error = None
return {
"python_executable": sys.executable,
"python_version": sys.version,
"asyncssh_available": asyncssh_ok,
"asyncssh_version": asyncssh_version,
"asyncssh_error": asyncssh_error,
}
@router.get("/{host_name}", response_model=HealthCheck)
async def check_host_health(host_name: str, api_key_valid: bool = Depends(verify_api_key)):
"""Effectue un health check sur un hôte spécifique."""
host = next((h for h in db.hosts if h.name == host_name), None)
if not host:
raise HTTPException(status_code=404, detail="Hôte non trouvé")
# Simuler un health check
health_check = HealthCheck(
host=host_name,
ssh_ok=host.status == "online",
ansible_ok=host.status == "online",
sudo_ok=host.status == "online",
reachable=host.status != "offline",
response_time=0.123 if host.status == "online" else None,
error_message=None if host.status != "offline" else "Hôte injoignable"
)
# Mettre à jour le statut runtime
new_status = "online" if health_check.reachable else "offline"
db.update_host_status(host_name, new_status, host.os)
log_entry = LogEntry(
timestamp=datetime.now(timezone.utc),
level="INFO" if health_check.reachable else "ERROR",
message=f"Health check {'réussi' if health_check.reachable else 'échoué'} pour {host_name}",
source="health_check",
host=host_name
)
db.logs.insert(0, log_entry)
await ws_manager.broadcast({
"type": "health_check",
"data": health_check.dict()
})
return health_check
@router.post("/refresh")
async def refresh_hosts(api_key_valid: bool = Depends(verify_api_key)):
"""Force le rechargement des hôtes depuis l'inventaire Ansible."""
from app.services import ansible_service
ansible_service.invalidate_cache()
hosts = db.refresh_hosts()
await ws_manager.broadcast({
"type": "hosts_refreshed",
"data": {"count": len(hosts)}
})
return {"message": f"{len(hosts)} hôtes rechargés depuis l'inventaire Ansible"}