All checks were successful
Build and Release / build-and-release (push) Successful in 1m7s
Implements clean structured data collection eliminating all string metric parsing bugs. Collectors now populate AgentData directly with type-safe field access. Key improvements: - Mount points preserved correctly (/ and /boot instead of root/boot) - Tmpfs discovery added to memory collector - Temperature data flows as typed f32 fields - Zero string parsing overhead - Complete removal of MetricCollectionManager bridge - Direct ZMQ transmission of structured JSON All functionality maintained: service tracking, notifications, status evaluation, and multi-host monitoring.
100 lines
3.7 KiB
Rust
100 lines
3.7 KiB
Rust
use async_trait::async_trait;
|
|
use cm_dashboard_shared::AgentData;
|
|
use std::fs;
|
|
use std::process::Command;
|
|
use tracing::debug;
|
|
|
|
use super::{Collector, CollectorError};
|
|
use crate::config::NixOSConfig;
|
|
|
|
/// NixOS system information collector with structured data output
|
|
///
|
|
/// This collector gathers NixOS-specific information like:
|
|
/// - System generation/build information
|
|
/// - Version information
|
|
/// - Agent version from Nix store path
|
|
pub struct NixOSCollector {
|
|
config: NixOSConfig,
|
|
}
|
|
|
|
impl NixOSCollector {
|
|
pub fn new(config: NixOSConfig) -> Self {
|
|
Self { config }
|
|
}
|
|
|
|
/// Collect NixOS system information and populate AgentData
|
|
async fn collect_nixos_info(&self, agent_data: &mut AgentData) -> Result<(), CollectorError> {
|
|
debug!("Collecting NixOS system information");
|
|
|
|
// Set hostname (this is universal, not NixOS-specific)
|
|
agent_data.hostname = self.get_hostname().await.unwrap_or_else(|| "unknown".to_string());
|
|
|
|
// Set agent version from environment or Nix store path
|
|
agent_data.agent_version = self.get_agent_version().await;
|
|
|
|
// Set current timestamp
|
|
agent_data.timestamp = chrono::Utc::now().timestamp() as u64;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Get system hostname
|
|
async fn get_hostname(&self) -> Option<String> {
|
|
match fs::read_to_string("/etc/hostname") {
|
|
Ok(hostname) => Some(hostname.trim().to_string()),
|
|
Err(_) => {
|
|
// Fallback to hostname command
|
|
match Command::new("hostname").output() {
|
|
Ok(output) => Some(String::from_utf8_lossy(&output.stdout).trim().to_string()),
|
|
Err(_) => None,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Get agent version from Nix store path or environment
|
|
async fn get_agent_version(&self) -> String {
|
|
// Try to extract version from the current executable path (Nix store)
|
|
if let Ok(current_exe) = std::env::current_exe() {
|
|
if let Some(exe_path) = current_exe.to_str() {
|
|
if exe_path.starts_with("/nix/store/") {
|
|
// Extract version from Nix store path
|
|
// Path format: /nix/store/hash-cm-dashboard-agent-v0.1.138/bin/cm-dashboard-agent
|
|
if let Some(store_part) = exe_path.strip_prefix("/nix/store/") {
|
|
if let Some(dash_pos) = store_part.find('-') {
|
|
let package_part = &store_part[dash_pos + 1..];
|
|
if let Some(bin_pos) = package_part.find("/bin/") {
|
|
let package_name = &package_part[..bin_pos];
|
|
// Extract version from package name
|
|
if let Some(version_start) = package_name.rfind("-v") {
|
|
return package_name[version_start + 1..].to_string();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback to environment variable or default
|
|
std::env::var("CM_DASHBOARD_VERSION").unwrap_or_else(|_| "unknown".to_string())
|
|
}
|
|
|
|
/// Get NixOS system generation (build) information
|
|
async fn get_nixos_generation(&self) -> Option<String> {
|
|
match Command::new("nixos-version").output() {
|
|
Ok(output) => {
|
|
let version_str = String::from_utf8_lossy(&output.stdout);
|
|
Some(version_str.trim().to_string())
|
|
}
|
|
Err(_) => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl Collector for NixOSCollector {
|
|
async fn collect_structured(&self, agent_data: &mut AgentData) -> Result<(), CollectorError> {
|
|
self.collect_nixos_info(agent_data).await
|
|
}
|
|
} |