Fix disk collector to use dynamic device detection

- Remove underlying_devices field from FilesystemConfig
- Add device detection at startup using findmnt command
- Store detected devices in HashMap for reuse during collection
- Keep all existing functionality (StoragePool, DriveInfo, SMART data)
- Detect devices only once at initialization, not every collection cycle
- Fixes agent startup failure due to missing underlying_devices config
This commit is contained in:
Christoffer Martinsson 2025-10-23 18:50:40 +02:00
parent 7f5949b818
commit 5134c5320a
2 changed files with 36 additions and 3 deletions

View File

@ -36,6 +36,7 @@ struct DriveInfo {
pub struct DiskCollector { pub struct DiskCollector {
config: DiskConfig, config: DiskConfig,
temperature_thresholds: HysteresisThresholds, temperature_thresholds: HysteresisThresholds,
detected_devices: std::collections::HashMap<String, Vec<String>>, // mount_point -> devices
} }
impl DiskCollector { impl DiskCollector {
@ -48,9 +49,20 @@ impl DiskCollector {
5.0, // 5°C gap for recovery 5.0, // 5°C gap for recovery
); );
// Detect devices for all configured filesystems at startup
let mut detected_devices = std::collections::HashMap::new();
for fs_config in &config.filesystems {
if fs_config.monitor {
if let Ok(devices) = Self::detect_device_for_mount_point_static(&fs_config.mount_point) {
detected_devices.insert(fs_config.mount_point.clone(), devices);
}
}
}
Self { Self {
config, config,
temperature_thresholds, temperature_thresholds,
detected_devices,
} }
} }
@ -84,8 +96,9 @@ impl DiskCollector {
let used = self.bytes_to_human_readable(used_bytes); let used = self.bytes_to_human_readable(used_bytes);
let available = self.bytes_to_human_readable(available_bytes); let available = self.bytes_to_human_readable(available_bytes);
// Get individual drive information // Get individual drive information using pre-detected devices
let underlying_drives = self.get_drive_info_for_devices(&fs_config.underlying_devices)?; let device_names = self.detected_devices.get(&fs_config.mount_point).cloned().unwrap_or_default();
let underlying_drives = self.get_drive_info_for_devices(&device_names)?;
storage_pools.push(StoragePool { storage_pools.push(StoragePool {
name: fs_config.name.clone(), name: fs_config.name.clone(),
@ -249,6 +262,27 @@ impl DiskCollector {
} }
} }
/// Detect device backing a mount point using findmnt (static version for startup)
fn detect_device_for_mount_point_static(mount_point: &str) -> Result<Vec<String>> {
let output = Command::new("findmnt")
.args(&["-n", "-o", "SOURCE", mount_point])
.output()?;
if !output.status.success() {
return Ok(Vec::new());
}
let output_str = String::from_utf8_lossy(&output.stdout);
let device_path = output_str.trim();
// Extract device name from path (e.g., /dev/nvme0n1 -> nvme0n1)
if let Some(device_name) = device_path.strip_prefix("/dev/") {
Ok(vec![device_name.to_string()])
} else {
Ok(Vec::new())
}
}
/// Get directory size using du command (efficient for single directory) /// Get directory size using du command (efficient for single directory)
fn get_directory_size(&self, path: &str) -> Result<u64> { fn get_directory_size(&self, path: &str) -> Result<u64> {
let output = Command::new("du") let output = Command::new("du")

View File

@ -86,7 +86,6 @@ pub struct FilesystemConfig {
pub fs_type: String, // "ext4", "zfs", "xfs", "mergerfs", "btrfs" pub fs_type: String, // "ext4", "zfs", "xfs", "mergerfs", "btrfs"
pub monitor: bool, pub monitor: bool,
pub storage_type: String, // "single", "raid", "mirror", "mergerfs", "zfs" pub storage_type: String, // "single", "raid", "mirror", "mergerfs", "zfs"
pub underlying_devices: Vec<String>, // ["sda", "sdb", "sdc"] or ["nvme0n1"]
} }