All checks were successful
Build and Release / build-and-release (push) Successful in 1m19s
- Remove all debug println statements - Remove unused service_tracker module - Remove unused struct fields and methods - Remove empty placeholder files (cpu.rs, memory.rs, defaults.rs) - Fix all compiler warnings - Clean build with zero warnings Version bump to 0.1.159
149 lines
5.2 KiB
Rust
149 lines
5.2 KiB
Rust
use async_trait::async_trait;
|
|
use cm_dashboard_shared::{AgentData, BackupData, BackupDiskData};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::collections::HashMap;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
use tracing::debug;
|
|
|
|
use super::{Collector, CollectorError};
|
|
|
|
/// Backup collector that reads backup status from TOML files with structured data output
|
|
pub struct BackupCollector {
|
|
/// Path to backup status file
|
|
status_file_path: String,
|
|
}
|
|
|
|
impl BackupCollector {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
status_file_path: "/var/lib/backup/backup-status.toml".to_string(),
|
|
}
|
|
}
|
|
|
|
/// Read backup status from TOML file
|
|
async fn read_backup_status(&self) -> Result<Option<BackupStatusToml>, CollectorError> {
|
|
if !Path::new(&self.status_file_path).exists() {
|
|
debug!("Backup status file not found: {}", self.status_file_path);
|
|
return Ok(None);
|
|
}
|
|
|
|
let content = fs::read_to_string(&self.status_file_path)
|
|
.map_err(|e| CollectorError::SystemRead {
|
|
path: self.status_file_path.clone(),
|
|
error: e.to_string(),
|
|
})?;
|
|
|
|
let status: BackupStatusToml = toml::from_str(&content)
|
|
.map_err(|e| CollectorError::Parse {
|
|
value: content.clone(),
|
|
error: format!("Failed to parse backup status TOML: {}", e),
|
|
})?;
|
|
|
|
Ok(Some(status))
|
|
}
|
|
|
|
/// Convert BackupStatusToml to BackupData and populate AgentData
|
|
async fn populate_backup_data(&self, agent_data: &mut AgentData) -> Result<(), CollectorError> {
|
|
if let Some(backup_status) = self.read_backup_status().await? {
|
|
// Use raw start_time string from TOML
|
|
|
|
// Extract disk information
|
|
let repository_disk = if let Some(disk_space) = &backup_status.disk_space {
|
|
Some(BackupDiskData {
|
|
serial: backup_status.disk_serial_number.clone().unwrap_or_else(|| "Unknown".to_string()),
|
|
usage_percent: disk_space.usage_percent as f32,
|
|
used_gb: disk_space.used_gb as f32,
|
|
total_gb: disk_space.total_gb as f32,
|
|
wear_percent: backup_status.disk_wear_percent,
|
|
temperature_celsius: None, // Not available in current TOML
|
|
})
|
|
} else if let Some(serial) = &backup_status.disk_serial_number {
|
|
// Fallback: create minimal disk info if we have serial but no disk_space
|
|
Some(BackupDiskData {
|
|
serial: serial.clone(),
|
|
usage_percent: 0.0,
|
|
used_gb: 0.0,
|
|
total_gb: 0.0,
|
|
wear_percent: backup_status.disk_wear_percent,
|
|
temperature_celsius: None,
|
|
})
|
|
} else {
|
|
None
|
|
};
|
|
|
|
// Calculate total repository size from services
|
|
let total_size_gb = backup_status.services
|
|
.values()
|
|
.map(|service| service.repo_size_bytes as f32 / (1024.0 * 1024.0 * 1024.0))
|
|
.sum::<f32>();
|
|
|
|
let backup_data = BackupData {
|
|
status: backup_status.status,
|
|
total_size_gb: Some(total_size_gb),
|
|
repository_health: Some("ok".to_string()), // Derive from status if needed
|
|
repository_disk,
|
|
last_backup_size_gb: None, // Not available in current TOML format
|
|
start_time_raw: Some(backup_status.start_time),
|
|
};
|
|
|
|
agent_data.backup = backup_data;
|
|
} else {
|
|
// No backup status available - set default values
|
|
agent_data.backup = BackupData {
|
|
status: "unavailable".to_string(),
|
|
total_size_gb: None,
|
|
repository_health: None,
|
|
repository_disk: None,
|
|
last_backup_size_gb: None,
|
|
start_time_raw: None,
|
|
};
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl Collector for BackupCollector {
|
|
async fn collect_structured(&self, agent_data: &mut AgentData) -> Result<(), CollectorError> {
|
|
debug!("Collecting backup status");
|
|
self.populate_backup_data(agent_data).await
|
|
}
|
|
}
|
|
|
|
/// TOML structure for backup status file
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
struct BackupStatusToml {
|
|
pub backup_name: String,
|
|
pub start_time: String,
|
|
pub current_time: String,
|
|
pub duration_seconds: i64,
|
|
pub status: String,
|
|
pub last_updated: String,
|
|
pub disk_space: Option<DiskSpace>,
|
|
pub disk_product_name: Option<String>,
|
|
pub disk_serial_number: Option<String>,
|
|
pub disk_wear_percent: Option<f32>,
|
|
pub services: HashMap<String, ServiceStatus>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
struct DiskSpace {
|
|
pub total_bytes: u64,
|
|
pub used_bytes: u64,
|
|
pub available_bytes: u64,
|
|
pub total_gb: f64,
|
|
pub used_gb: f64,
|
|
pub available_gb: f64,
|
|
pub usage_percent: f64,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
struct ServiceStatus {
|
|
pub status: String,
|
|
pub exit_code: i64,
|
|
pub repo_path: String,
|
|
pub archive_count: i64,
|
|
pub repo_size_bytes: u64,
|
|
} |