from fastapi import APIRouter, Depends from sqlalchemy import func, select, text from sqlalchemy.orm import Session from app.config import get_settings from app.database import get_db from app.models import Event from app.services.host_health import count_stale_hosts from app.version import APP_NAME, APP_VERSION router = APIRouter(tags=["health"]) def build_health_payload(db: Session) -> dict: db_status = "ok" try: db.execute(text("SELECT 1")) except Exception: db_status = "error" hosts_stale = 0 last_event_received_at: str | None = None if db_status == "ok": settings = get_settings() hosts_stale = count_stale_hosts(db, settings.sac_heartbeat_stale_minutes) last_received = db.scalar(select(func.max(Event.received_at))) if last_received is not None: last_event_received_at = last_received.isoformat() overall = "ok" if db_status == "ok" else "degraded" if db_status == "ok" and hosts_stale > 0: overall = "degraded" return { "status": overall, "database": db_status, "service": "security-alert-center", "name": APP_NAME, "version": APP_VERSION, "hosts_stale": hosts_stale, "last_event_received_at": last_event_received_at, } @router.get("/health") def health(db: Session = Depends(get_db)) -> dict: return build_health_payload(db) @router.get("/healthz") def healthz(db: Session = Depends(get_db)) -> dict: """Kubernetes-style alias; same payload as /health.""" return build_health_payload(db)