From fb91d8346f50f100c8cb1cb36f7cdccd8d1d488f Mon Sep 17 00:00:00 2001 From: Christoffer Martinsson Date: Sun, 12 Oct 2025 19:13:19 +0200 Subject: [PATCH] Testing --- agent/src/collectors/backup.rs | 149 ++++++++++++++++++++++++++------- 1 file changed, 119 insertions(+), 30 deletions(-) diff --git a/agent/src/collectors/backup.rs b/agent/src/collectors/backup.rs index f149af5..4d17f8f 100644 --- a/agent/src/collectors/backup.rs +++ b/agent/src/collectors/backup.rs @@ -6,6 +6,7 @@ use std::process::Stdio; use std::time::Duration; use tokio::process::Command; use tokio::time::timeout; +use tokio::fs; use super::{AgentType, Collector, CollectorError, CollectorOutput}; @@ -34,6 +35,24 @@ impl BackupCollector { } } + async fn get_borgbackup_metrics(&self) -> Result { + // Read metrics from the borgbackup JSON file + let metrics_path = "/var/lib/backup/backup-metrics.json"; + + let content = fs::read_to_string(metrics_path) + .await + .map_err(|e| CollectorError::IoError { + message: format!("Failed to read backup metrics file: {}", e), + })?; + + let metrics: BorgbackupMetrics = serde_json::from_str(&content) + .map_err(|e| CollectorError::ParseError { + message: format!("Failed to parse backup metrics JSON: {}", e), + })?; + + Ok(metrics) + } + async fn get_restic_snapshots(&self) -> Result { let repo = self .restic_repo @@ -290,8 +309,66 @@ impl Collector for BackupCollector { } async fn collect(&self) -> Result { - // Get restic repository stats - let restic_stats = self.get_restic_snapshots().await; + // Try to get borgbackup metrics first, fall back to restic if not available + let borgbackup_result = self.get_borgbackup_metrics().await; + + let (backup_info, overall_status) = match borgbackup_result { + Ok(borg_metrics) => { + // Parse borgbackup timestamp to DateTime + let last_success = chrono::DateTime::from_timestamp(borg_metrics.timestamp, 0); + + // Determine status from borgbackup data + let status = match borg_metrics.status.as_str() { + "success" => BackupStatus::Healthy, + "warning" => BackupStatus::Warning, + "failed" => BackupStatus::Failed, + _ => BackupStatus::Unknown, + }; + + let backup_info = BackupInfo { + last_success, + last_failure: None, // borgbackup metrics don't include failure info + size_gb: borg_metrics.repository.total_repository_size_bytes as f32 / (1024.0 * 1024.0 * 1024.0), + snapshot_count: borg_metrics.repository.total_archives as u32, + }; + + (backup_info, status) + }, + Err(_) => { + // Fall back to restic if borgbackup metrics not available + let restic_stats = self.get_restic_snapshots().await; + let last_failure = self.get_backup_logs_for_failures().await.unwrap_or(None); + + // Get backup service status for fallback determination + let service_data = self + .get_backup_service_status() + .await + .unwrap_or(BackupServiceData { + enabled: false, + pending_jobs: 0, + last_message: None, + }); + + let overall_status = self.determine_backup_status(&restic_stats, &service_data, last_failure); + + let backup_info = match &restic_stats { + Ok(stats) => BackupInfo { + last_success: stats.last_success, + last_failure, + size_gb: stats.total_size as f32 / (1024.0 * 1024.0 * 1024.0), + snapshot_count: stats.snapshot_count, + }, + Err(_) => BackupInfo { + last_success: None, + last_failure, + size_gb: 0.0, + snapshot_count: 0, + }, + }; + + (backup_info, overall_status) + } + }; // Get backup service status let service_data = self @@ -303,34 +380,6 @@ impl Collector for BackupCollector { last_message: None, }); - // Check for recent failures - let last_failure = self.get_backup_logs_for_failures().await.unwrap_or(None); - - // Determine overall backup status - let overall_status = - self.determine_backup_status(&restic_stats, &service_data, last_failure); - - let (backup_info, _size_gb) = match &restic_stats { - Ok(stats) => ( - BackupInfo { - last_success: stats.last_success, - last_failure, - size_gb: stats.total_size as f32 / (1024.0 * 1024.0 * 1024.0), - snapshot_count: stats.snapshot_count, - }, - stats.total_size as f32 / (1024.0 * 1024.0 * 1024.0), - ), - Err(_) => ( - BackupInfo { - last_success: None, - last_failure, - size_gb: 0.0, - snapshot_count: 0, - }, - 0.0, - ), - }; - let backup_metrics = json!({ "overall_status": overall_status, "backup": backup_info, @@ -386,3 +435,43 @@ struct JournalEntry { #[serde(rename = "__REALTIME_TIMESTAMP")] realtime_timestamp: String, } + +// Borgbackup metrics structure from backup script +#[derive(Debug, Deserialize)] +struct BorgbackupMetrics { + backup_name: String, + start_time: String, + end_time: String, + duration_seconds: i64, + status: String, + exit_codes: ExitCodes, + repository: Repository, + backup_disk: BackupDisk, + timestamp: i64, +} + +#[derive(Debug, Deserialize)] +struct ExitCodes { + global: i32, + backup: i32, + prune: i32, + compact: i32, +} + +#[derive(Debug, Deserialize)] +struct Repository { + total_archives: i32, + latest_archive_size_bytes: i64, + total_repository_size_bytes: i64, + path: String, +} + +#[derive(Debug, Deserialize)] +struct BackupDisk { + device: String, + health: String, + total_bytes: i64, + used_bytes: i64, + available_bytes: i64, + usage_percent: f32, +}