All checks were successful
Build and Release / build-and-release (push) Successful in 1m24s
- Add get_git_commit() method to read /var/lib/cm-dashboard/git-commit - Replace NixOS build version with actual git commit hash - Show deployed commit hash as 'Build:' value for accurate tracking - Enable verification of which exact commit is deployed per host - Update version to 0.1.42
172 lines
6.2 KiB
Rust
172 lines
6.2 KiB
Rust
use async_trait::async_trait;
|
|
use cm_dashboard_shared::{Metric, MetricValue, Status, StatusTracker};
|
|
use std::process::Command;
|
|
use tracing::debug;
|
|
|
|
use super::{Collector, CollectorError};
|
|
use crate::config::NixOSConfig;
|
|
|
|
/// NixOS system information collector
|
|
///
|
|
/// Collects NixOS-specific system information including:
|
|
/// - NixOS version and build information
|
|
pub struct NixOSCollector {
|
|
}
|
|
|
|
impl NixOSCollector {
|
|
pub fn new(_config: NixOSConfig) -> Self {
|
|
Self {}
|
|
}
|
|
|
|
|
|
/// Get agent hash from binary path
|
|
fn get_agent_hash(&self) -> Result<String, Box<dyn std::error::Error>> {
|
|
// Get the path of the current executable
|
|
let exe_path = std::env::current_exe()?;
|
|
let exe_str = exe_path.to_string_lossy();
|
|
|
|
// Extract Nix store hash from path like /nix/store/fn804fh332mp8gz06qawminpj20xl25h-cm-dashboard-0.1.0/bin/cm-dashboard-agent
|
|
if let Some(store_path) = exe_str.strip_prefix("/nix/store/") {
|
|
if let Some(dash_pos) = store_path.find('-') {
|
|
return Ok(store_path[..dash_pos].to_string());
|
|
}
|
|
}
|
|
|
|
// Fallback to "unknown" if not in Nix store
|
|
Ok("unknown".to_string())
|
|
}
|
|
|
|
/// Get configuration hash from deployed nix store system
|
|
/// Get git commit hash from rebuild process
|
|
fn get_git_commit(&self) -> Result<String, Box<dyn std::error::Error>> {
|
|
let commit_file = "/var/lib/cm-dashboard/git-commit";
|
|
match std::fs::read_to_string(commit_file) {
|
|
Ok(content) => {
|
|
let commit_hash = content.trim();
|
|
if commit_hash.len() >= 7 {
|
|
Ok(commit_hash.to_string())
|
|
} else {
|
|
Err("Git commit hash too short".into())
|
|
}
|
|
}
|
|
Err(e) => Err(format!("Failed to read git commit file: {}", e).into())
|
|
}
|
|
}
|
|
|
|
fn get_config_hash(&self) -> Result<String, Box<dyn std::error::Error>> {
|
|
// Read the symlink target of /run/current-system to get nix store path
|
|
let output = Command::new("readlink")
|
|
.arg("/run/current-system")
|
|
.output()?;
|
|
|
|
if !output.status.success() {
|
|
return Err("readlink command failed".into());
|
|
}
|
|
|
|
let binding = String::from_utf8_lossy(&output.stdout);
|
|
let store_path = binding.trim();
|
|
|
|
// Extract hash from nix store path
|
|
// Format: /nix/store/HASH-nixos-system-HOSTNAME-VERSION
|
|
if let Some(hash_part) = store_path.strip_prefix("/nix/store/") {
|
|
if let Some(hash) = hash_part.split('-').next() {
|
|
if hash.len() >= 8 {
|
|
// Return first 8 characters of nix store hash
|
|
return Ok(hash[..8].to_string());
|
|
}
|
|
}
|
|
}
|
|
|
|
Err("Could not extract hash from nix store path".into())
|
|
}
|
|
|
|
}
|
|
|
|
#[async_trait]
|
|
impl Collector for NixOSCollector {
|
|
|
|
async fn collect(&self, _status_tracker: &mut StatusTracker) -> Result<Vec<Metric>, CollectorError> {
|
|
debug!("Collecting NixOS system information");
|
|
let mut metrics = Vec::new();
|
|
let timestamp = chrono::Utc::now().timestamp() as u64;
|
|
|
|
// Collect git commit information (shows what's actually deployed)
|
|
match self.get_git_commit() {
|
|
Ok(git_commit) => {
|
|
metrics.push(Metric {
|
|
name: "system_nixos_build".to_string(),
|
|
value: MetricValue::String(git_commit),
|
|
unit: None,
|
|
description: Some("Git commit hash of deployed configuration".to_string()),
|
|
status: Status::Ok,
|
|
timestamp,
|
|
});
|
|
}
|
|
Err(e) => {
|
|
debug!("Failed to get git commit: {}", e);
|
|
metrics.push(Metric {
|
|
name: "system_nixos_build".to_string(),
|
|
value: MetricValue::String("unknown".to_string()),
|
|
unit: None,
|
|
description: Some("Git commit hash (failed to detect)".to_string()),
|
|
status: Status::Unknown,
|
|
timestamp,
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// Collect config hash
|
|
match self.get_config_hash() {
|
|
Ok(hash) => {
|
|
metrics.push(Metric {
|
|
name: "system_config_hash".to_string(),
|
|
value: MetricValue::String(hash),
|
|
unit: None,
|
|
description: Some("NixOS deployed configuration hash".to_string()),
|
|
status: Status::Ok,
|
|
timestamp,
|
|
});
|
|
}
|
|
Err(e) => {
|
|
debug!("Failed to get config hash: {}", e);
|
|
metrics.push(Metric {
|
|
name: "system_config_hash".to_string(),
|
|
value: MetricValue::String("unknown".to_string()),
|
|
unit: None,
|
|
description: Some("Deployed config hash (failed to detect)".to_string()),
|
|
status: Status::Unknown,
|
|
timestamp,
|
|
});
|
|
}
|
|
}
|
|
|
|
// Collect agent hash
|
|
match self.get_agent_hash() {
|
|
Ok(hash) => {
|
|
metrics.push(Metric {
|
|
name: "system_agent_hash".to_string(),
|
|
value: MetricValue::String(hash),
|
|
unit: None,
|
|
description: Some("Agent Nix store hash".to_string()),
|
|
status: Status::Ok,
|
|
timestamp,
|
|
});
|
|
}
|
|
Err(e) => {
|
|
debug!("Failed to get agent hash: {}", e);
|
|
metrics.push(Metric {
|
|
name: "system_agent_hash".to_string(),
|
|
value: MetricValue::String("unknown".to_string()),
|
|
unit: None,
|
|
description: Some("Agent hash (failed to detect)".to_string()),
|
|
status: Status::Unknown,
|
|
timestamp,
|
|
});
|
|
}
|
|
}
|
|
|
|
debug!("Collected {} NixOS metrics", metrics.len());
|
|
Ok(metrics)
|
|
}
|
|
} |