All checks were successful
Build and Release / build-and-release (push) Successful in 2m39s
Fully restored CM Dashboard as a complete monitoring system with working status evaluation and email notifications. COMPLETED PHASES: ✅ Phase 1: Fixed storage display issues - Use lsblk instead of findmnt (eliminates /nix/store bind mount) - Fixed NVMe SMART parsing (Temperature: and Percentage Used:) - Added sudo to smartctl for permissions - Consistent filesystem and tmpfs sorting ✅ Phase 2a: Fixed missing NixOS build information - Added build_version field to AgentData - NixOS collector now populates build info - Dashboard shows actual build instead of "unknown" ✅ Phase 2b: Restored status evaluation system - Added status fields to all structured data types - CPU: load and temperature status evaluation - Memory: usage status evaluation - Storage: temperature, health, and filesystem usage status - All collectors now use their threshold configurations ✅ Phase 3: Restored notification system - Status change detection between collection cycles - Email alerts on status degradation (OK→Warning/Critical) - Detailed notification content with metric values - Full NotificationManager integration CORE FUNCTIONALITY RESTORED: - Real-time monitoring with proper status evaluation - Email notifications on threshold violations - Correct storage display (nvme0n1 T: 28°C W: 1%) - Complete status-aware infrastructure monitoring - Dashboard is now a monitoring system, not just data viewer The CM Dashboard monitoring system is fully operational.
173 lines
4.7 KiB
Rust
173 lines
4.7 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use crate::Status;
|
|
|
|
/// Complete structured data from an agent
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AgentData {
|
|
pub hostname: String,
|
|
pub agent_version: String,
|
|
pub build_version: Option<String>,
|
|
pub timestamp: u64,
|
|
pub system: SystemData,
|
|
pub services: Vec<ServiceData>,
|
|
pub backup: BackupData,
|
|
}
|
|
|
|
/// System-level monitoring data
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct SystemData {
|
|
pub cpu: CpuData,
|
|
pub memory: MemoryData,
|
|
pub storage: StorageData,
|
|
}
|
|
|
|
/// CPU monitoring data
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct CpuData {
|
|
pub load_1min: f32,
|
|
pub load_5min: f32,
|
|
pub load_15min: f32,
|
|
pub frequency_mhz: f32,
|
|
pub temperature_celsius: Option<f32>,
|
|
pub load_status: Status,
|
|
pub temperature_status: Status,
|
|
}
|
|
|
|
/// Memory monitoring data
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct MemoryData {
|
|
pub usage_percent: f32,
|
|
pub total_gb: f32,
|
|
pub used_gb: f32,
|
|
pub available_gb: f32,
|
|
pub swap_total_gb: f32,
|
|
pub swap_used_gb: f32,
|
|
pub tmpfs: Vec<TmpfsData>,
|
|
pub usage_status: Status,
|
|
}
|
|
|
|
/// Tmpfs filesystem data
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct TmpfsData {
|
|
pub mount: String,
|
|
pub usage_percent: f32,
|
|
pub used_gb: f32,
|
|
pub total_gb: f32,
|
|
}
|
|
|
|
/// Storage monitoring data
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct StorageData {
|
|
pub drives: Vec<DriveData>,
|
|
pub pools: Vec<PoolData>,
|
|
}
|
|
|
|
/// Individual drive data
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct DriveData {
|
|
pub name: String,
|
|
pub health: String,
|
|
pub temperature_celsius: Option<f32>,
|
|
pub wear_percent: Option<f32>,
|
|
pub filesystems: Vec<FilesystemData>,
|
|
pub temperature_status: Status,
|
|
pub health_status: Status,
|
|
}
|
|
|
|
/// Filesystem on a drive
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct FilesystemData {
|
|
pub mount: String,
|
|
pub usage_percent: f32,
|
|
pub used_gb: f32,
|
|
pub total_gb: f32,
|
|
pub usage_status: Status,
|
|
}
|
|
|
|
/// Storage pool (MergerFS, RAID, etc.)
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct PoolData {
|
|
pub name: String,
|
|
pub mount: String,
|
|
pub pool_type: String, // "mergerfs", "raid", etc.
|
|
pub health: String,
|
|
pub usage_percent: f32,
|
|
pub used_gb: f32,
|
|
pub total_gb: f32,
|
|
pub data_drives: Vec<PoolDriveData>,
|
|
pub parity_drives: Vec<PoolDriveData>,
|
|
}
|
|
|
|
/// Drive in a storage pool
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct PoolDriveData {
|
|
pub name: String,
|
|
pub temperature_celsius: Option<f32>,
|
|
pub wear_percent: Option<f32>,
|
|
pub health: String,
|
|
}
|
|
|
|
/// Service monitoring data
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ServiceData {
|
|
pub name: String,
|
|
pub status: String, // "active", "inactive", "failed"
|
|
pub memory_mb: f32,
|
|
pub disk_gb: f32,
|
|
pub user_stopped: bool,
|
|
}
|
|
|
|
/// Backup system data
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct BackupData {
|
|
pub status: String,
|
|
pub last_run: Option<u64>,
|
|
pub next_scheduled: Option<u64>,
|
|
pub total_size_gb: Option<f32>,
|
|
pub repository_health: Option<String>,
|
|
}
|
|
|
|
impl AgentData {
|
|
/// Create new agent data with current timestamp
|
|
pub fn new(hostname: String, agent_version: String) -> Self {
|
|
Self {
|
|
hostname,
|
|
agent_version,
|
|
build_version: None,
|
|
timestamp: chrono::Utc::now().timestamp() as u64,
|
|
system: SystemData {
|
|
cpu: CpuData {
|
|
load_1min: 0.0,
|
|
load_5min: 0.0,
|
|
load_15min: 0.0,
|
|
frequency_mhz: 0.0,
|
|
temperature_celsius: None,
|
|
load_status: Status::Unknown,
|
|
temperature_status: Status::Unknown,
|
|
},
|
|
memory: MemoryData {
|
|
usage_percent: 0.0,
|
|
total_gb: 0.0,
|
|
used_gb: 0.0,
|
|
available_gb: 0.0,
|
|
swap_total_gb: 0.0,
|
|
swap_used_gb: 0.0,
|
|
tmpfs: Vec::new(),
|
|
usage_status: Status::Unknown,
|
|
},
|
|
storage: StorageData {
|
|
drives: Vec::new(),
|
|
pools: Vec::new(),
|
|
},
|
|
},
|
|
services: Vec::new(),
|
|
backup: BackupData {
|
|
status: "unknown".to_string(),
|
|
last_run: None,
|
|
next_scheduled: None,
|
|
total_size_gb: None,
|
|
repository_health: None,
|
|
},
|
|
}
|
|
}
|
|
} |