fix(backrest): use Connect-RPC endpoints with Basic Auth

This commit is contained in:
2026-04-06 13:18:07 +00:00
parent a940b585e8
commit 9e35e51bbf
@@ -14,38 +14,43 @@ class BackrestClient(BaseHTTPClient):
def __init__(self, settings: Settings) -> None: def __init__(self, settings: Settings) -> None:
super().__init__(settings, "backrest", settings.backrest_base_url) 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: async def fetch_status(self) -> BackrestSnapshot:
snapshot = BackrestSnapshot() snapshot = BackrestSnapshot()
if not self.base_url: if not self.base_url:
logger.info("backrest skipped: base URL missing") logger.info("backrest skipped: base URL missing")
return snapshot return snapshot
# Backrest uses Connect-RPC: POST /v1.Backrest/{Method} auth = self._auth()
try:
data = await self._request_json("POST", "/v1.Backrest/GetConfig", json={})
except Exception as exc:
logger.warning("backrest fetch_status GetConfig failed: %s", exc)
return snapshot
# Get config (repo list) via Connect-RPC
data = await self._request_json(
"POST", "/v1.Backrest/GetConfig",
json={},
auth=auth,
)
if not isinstance(data, dict): if not isinstance(data, dict):
return snapshot return snapshot
repos = data.get("repos") or [] repos = data.get("repos") or []
repo_count = len(repos) if isinstance(repos, list) else 0 repo_count = len(repos) if isinstance(repos, list) else 0
# Fetch recent operations for backup status # Get recent operations via Connect-RPC
last_backup_age_hours: float | None = None last_backup_age_hours: float | None = None
error_count = 0 error_count = 0
last_backup_status = "unknown" last_backup_status = "unknown"
try: ops_data = await self._request_json(
ops_data = await self._request_json( "POST", "/v1.Backrest/GetOperations",
"POST", json={"lastN": 20},
"/v1.Backrest/GetOperations", auth=auth,
json={"lastN": 20}, )
) if isinstance(ops_data, dict):
ops = ops_data.get("operations") or [] if isinstance(ops_data, dict) else [] ops = ops_data.get("operations") or []
# backupOp is a oneof field serialised directly at the operation level in proto3 JSON
backup_ops = [ backup_ops = [
op for op in ops op for op in ops
if isinstance(op, dict) and op.get("backupOp") is not None if isinstance(op, dict) and op.get("backupOp") is not None
@@ -61,13 +66,12 @@ class BackrestClient(BaseHTTPClient):
now = datetime.now(timezone.utc) now = datetime.now(timezone.utc)
last_backup_age_hours = round((now - ended).total_seconds() / 3600, 1) last_backup_age_hours = round((now - ended).total_seconds() / 3600, 1)
status_str = latest.get("status", "") status_str = latest.get("status", "")
last_backup_status = ( if status_str == "STATUS_SUCCESS":
"ok" if status_str == "STATUS_SUCCESS" last_backup_status = "ok"
else "error" if status_str == "STATUS_ERROR" elif status_str == "STATUS_ERROR":
else "unknown" last_backup_status = "error"
) else:
except Exception as exc: last_backup_status = "unknown"
logger.warning("backrest fetch_status GetOperations failed: %s", exc)
return BackrestSnapshot( return BackrestSnapshot(
source_status="online", source_status="online",