from __future__ import annotations import logging from datetime import datetime, timezone from app.clients.base import BaseHTTPClient from app.config import Settings from app.models.sources import BackrestSnapshot logger = logging.getLogger(__name__) class BackrestClient(BaseHTTPClient): def __init__(self, settings: Settings) -> None: super().__init__(settings, "backrest", settings.backrest_base_url) def _auth(self) -> tuple[str, str] | None: if self.settings.backrest_username and self.settings.backrest_password: return (self.settings.backrest_username, self.settings.backrest_password) return None async def fetch_status(self) -> BackrestSnapshot: snapshot = BackrestSnapshot() if not self.base_url: logger.info("backrest skipped: base URL missing") return snapshot auth = self._auth() # Get config (repo list) via Connect-RPC data = await self._request_json( "POST", "/v1.Backrest/GetConfig", json={}, auth=auth, ) if not isinstance(data, dict): return snapshot repos = data.get("repos") or [] repo_count = len(repos) if isinstance(repos, list) else 0 # Get recent operations via Connect-RPC last_backup_age_hours: float | None = None error_count = 0 last_backup_status = "unknown" ops_data = await self._request_json( "POST", "/v1.Backrest/GetOperations", json={"lastN": 20}, auth=auth, ) if isinstance(ops_data, dict): ops = ops_data.get("operations") or [] backup_ops = [ op for op in ops if isinstance(op, dict) and op.get("backupOp") is not None ] error_ops = [op for op in backup_ops if op.get("status") == "STATUS_ERROR"] error_count = len(error_ops) if backup_ops: latest = backup_ops[0] ts = latest.get("unixTimeEndMs") if ts: ended = datetime.fromtimestamp(int(ts) / 1000, tz=timezone.utc) now = datetime.now(timezone.utc) last_backup_age_hours = round((now - ended).total_seconds() / 3600, 1) status_str = latest.get("status", "") if status_str == "STATUS_SUCCESS": last_backup_status = "ok" elif status_str == "STATUS_ERROR": last_backup_status = "error" else: last_backup_status = "unknown" return BackrestSnapshot( source_status="online", repo_count=repo_count, last_backup_age_hours=last_backup_age_hours, last_backup_status=last_backup_status, error_count=error_count, )