homelab_automation/app/crud/host_metrics.py

122 lines
4.6 KiB
Python

from __future__ import annotations
from datetime import datetime, timedelta
from typing import Optional, List, Dict, Any
from sqlalchemy import select, delete, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.host_metrics import HostMetrics
class HostMetricsRepository:
"""Repository pour gérer les métriques des hôtes"""
def __init__(self, session: AsyncSession):
self.session = session
async def create(self, **fields) -> HostMetrics:
"""Crée une nouvelle entrée de métriques"""
metrics = HostMetrics(**fields)
self.session.add(metrics)
await self.session.flush()
return metrics
async def get(self, metrics_id: int) -> Optional[HostMetrics]:
"""Récupère une entrée de métriques par son ID"""
stmt = select(HostMetrics).where(HostMetrics.id == metrics_id)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
async def get_latest_for_host(self, host_id: str, metric_type: str = None) -> Optional[HostMetrics]:
"""Récupère les dernières métriques pour un hôte"""
stmt = select(HostMetrics).where(HostMetrics.host_id == host_id)
if metric_type:
stmt = stmt.where(HostMetrics.metric_type == metric_type)
stmt = stmt.order_by(HostMetrics.collected_at.desc()).limit(1)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
async def list_for_host(
self,
host_id: str,
metric_type: str = None,
limit: int = 100,
offset: int = 0
) -> List[HostMetrics]:
"""Liste les métriques pour un hôte avec pagination"""
stmt = select(HostMetrics).where(HostMetrics.host_id == host_id)
if metric_type:
stmt = stmt.where(HostMetrics.metric_type == metric_type)
stmt = stmt.order_by(HostMetrics.collected_at.desc()).offset(offset).limit(limit)
result = await self.session.execute(stmt)
return list(result.scalars().all())
async def get_all_latest(self, metric_type: str = "system_info") -> Dict[str, HostMetrics]:
"""Récupère les dernières métriques pour tous les hôtes
Returns:
Dict mapping host_id to latest HostMetrics
"""
# Sous-requête pour obtenir la date max par host_id
subq = (
select(
HostMetrics.host_id,
func.max(HostMetrics.collected_at).label("max_collected")
)
.where(HostMetrics.metric_type == metric_type)
.group_by(HostMetrics.host_id)
.subquery()
)
# Jointure pour récupérer les enregistrements complets
stmt = (
select(HostMetrics)
.join(
subq,
(HostMetrics.host_id == subq.c.host_id) &
(HostMetrics.collected_at == subq.c.max_collected)
)
.where(HostMetrics.metric_type == metric_type)
)
result = await self.session.execute(stmt)
metrics_list = result.scalars().all()
return {m.host_id: m for m in metrics_list}
async def cleanup_old_metrics(self, days_to_keep: int = 30) -> int:
"""Supprime les métriques plus anciennes que le nombre de jours spécifié
Returns:
Nombre d'entrées supprimées
"""
cutoff_date = datetime.utcnow() - timedelta(days=days_to_keep)
stmt = delete(HostMetrics).where(HostMetrics.collected_at < cutoff_date)
result = await self.session.execute(stmt)
return result.rowcount
async def get_metrics_history(
self,
host_id: str,
metric_type: str = "system_info",
hours: int = 24
) -> List[HostMetrics]:
"""Récupère l'historique des métriques pour les dernières heures"""
cutoff = datetime.utcnow() - timedelta(hours=hours)
stmt = (
select(HostMetrics)
.where(HostMetrics.host_id == host_id)
.where(HostMetrics.metric_type == metric_type)
.where(HostMetrics.collected_at >= cutoff)
.order_by(HostMetrics.collected_at.asc())
)
result = await self.session.execute(stmt)
return list(result.scalars().all())
async def count_for_host(self, host_id: str) -> int:
"""Compte le nombre d'entrées de métriques pour un hôte"""
stmt = select(func.count(HostMetrics.id)).where(HostMetrics.host_id == host_id)
result = await self.session.execute(stmt)
return result.scalar() or 0