Bruno Charest 6d8432169b
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
Add enhanced terminal history panel UI with animations, keyboard navigation, advanced filtering, search highlighting, and improved storage metrics display with detailed filesystem tables and ZFS/LVM support
2025-12-21 12:31:08 -05:00

170 lines
6.2 KiB
Python

"""
Routes API pour les métriques système et des hôtes.
"""
from datetime import timezone
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
import pytz
from app.core.dependencies import get_db, verify_api_key
from app.core.config import settings
from app.crud.host_metrics import HostMetricsRepository
from app.crud.app_setting import AppSettingRepository
from app.services import db
class CollectionScheduleRequest(BaseModel):
interval: str = "off"
router = APIRouter()
def _to_app_timezone(dt):
if dt is None:
return None
if getattr(dt, "tzinfo", None) is None:
dt = dt.replace(tzinfo=timezone.utc)
tz = pytz.timezone(settings.scheduler_timezone)
return dt.astimezone(tz)
@router.get("")
async def get_metrics(api_key_valid: bool = Depends(verify_api_key)):
"""Récupère les métriques système globales."""
return db.metrics
@router.get("/all-hosts")
async def get_all_hosts_metrics(
api_key_valid: bool = Depends(verify_api_key),
db_session: AsyncSession = Depends(get_db)
):
"""Récupère les métriques de tous les hôtes."""
try:
repo = HostMetricsRepository(db_session)
metrics_dict = await repo.get_all_latest()
# Convertir en dict host_id -> metrics
result = {}
for host_id, m in metrics_dict.items():
collected_at = _to_app_timezone(m.collected_at)
result[m.host_id] = {
"host_id": m.host_id,
"metric_type": m.metric_type,
"cpu_usage_percent": m.cpu_usage_percent,
"cpu_load_1m": m.cpu_load_1m,
"cpu_model": m.cpu_model,
"cpu_count": m.cpu_count,
"cpu_cores": getattr(m, "cpu_cores", None),
"cpu_threads": getattr(m, "cpu_threads", None),
"cpu_max_mhz": getattr(m, "cpu_max_mhz", None),
"cpu_temperature": getattr(m, "cpu_temperature", None),
"memory_usage_percent": m.memory_usage_percent,
"memory_total_mb": m.memory_total_mb,
"memory_used_mb": m.memory_used_mb,
"disk_root_usage_percent": m.disk_root_usage_percent,
"disk_root_total_gb": m.disk_root_total_gb,
"disk_root_used_gb": m.disk_root_used_gb,
"disk_info": getattr(m, "disk_info", None),
"disk_devices": getattr(m, "disk_devices", None),
"lvm_info": getattr(m, "lvm_info", None),
"zfs_info": getattr(m, "zfs_info", None),
"storage_details": getattr(m, "storage_details", None),
"os_name": m.os_name,
"uptime_human": m.uptime_human,
"last_collected": collected_at,
"collected_at": collected_at,
"collection_status": "success" if not m.error_message else "failed",
"error_message": m.error_message,
}
return result
except Exception as e:
# Si la table n'existe pas encore ou autre erreur
return {}
@router.get("/collection-schedule")
async def get_collection_schedule(
api_key_valid: bool = Depends(verify_api_key),
db_session: AsyncSession = Depends(get_db)
):
"""Récupère l'intervalle de collecte des métriques."""
try:
repo = AppSettingRepository(db_session)
setting = await repo.get("metrics_collection_interval")
interval = setting.value if setting else "off"
return {"interval": interval}
except Exception:
return {"interval": "off"}
@router.post("/collection-schedule")
async def set_collection_schedule(
request: CollectionScheduleRequest,
api_key_valid: bool = Depends(verify_api_key),
db_session: AsyncSession = Depends(get_db)
):
"""Définit l'intervalle de collecte des métriques."""
interval = request.interval
valid_intervals = ["off", "5min", "15min", "30min", "1h", "6h", "12h", "24h"]
if interval not in valid_intervals:
raise HTTPException(
status_code=400,
detail=f"Intervalle invalide. Valeurs acceptées: {valid_intervals}"
)
try:
repo = AppSettingRepository(db_session)
await repo.set("metrics_collection_interval", interval)
await db_session.commit()
return {"interval": interval, "message": f"Intervalle de collecte défini à {interval}"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/{host_id}")
async def get_host_metrics(
host_id: str,
api_key_valid: bool = Depends(verify_api_key),
db_session: AsyncSession = Depends(get_db)
):
"""Récupère les métriques d'un hôte spécifique."""
try:
repo = HostMetricsRepository(db_session)
metrics = await repo.get_latest_for_host(host_id)
if not metrics:
return {"host_id": host_id, "collection_status": "no_data"}
collected_at = _to_app_timezone(metrics.collected_at)
return {
"host_id": metrics.host_id,
"metric_type": metrics.metric_type,
"cpu_usage_percent": metrics.cpu_usage_percent,
"cpu_load_1m": metrics.cpu_load_1m,
"cpu_model": metrics.cpu_model,
"cpu_count": metrics.cpu_count,
"memory_usage_percent": metrics.memory_usage_percent,
"memory_total_mb": metrics.memory_total_mb,
"memory_used_mb": metrics.memory_used_mb,
"disk_root_usage_percent": metrics.disk_root_usage_percent,
"disk_root_total_gb": metrics.disk_root_total_gb,
"disk_root_used_gb": metrics.disk_root_used_gb,
"disk_info": metrics.disk_info,
"os_name": metrics.os_name,
"uptime_human": metrics.uptime_human,
"last_collected": collected_at,
"collected_at": collected_at,
"collection_status": "success" if not metrics.error_message else "failed",
"error_message": metrics.error_message,
}
except Exception as e:
return {"host_id": host_id, "collection_status": "error", "error_message": str(e)}