Replace device names with serial numbers in MergerFS pool display
All checks were successful
Build and Release / build-and-release (push) Successful in 1m19s

Updates disk collector and dashboard to show drive serial numbers
instead of device names (sdX) for MergerFS data/parity drives.
Agent extracts serial numbers from SMART data and dashboard
displays them when available, falling back to device names.
This commit is contained in:
Christoffer Martinsson 2025-11-25 10:30:37 +01:00
parent 8f80015273
commit c9d12793ef
7 changed files with 26 additions and 8 deletions

6
Cargo.lock generated
View File

@ -279,7 +279,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "cm-dashboard"
version = "0.1.153"
version = "0.1.154"
dependencies = [
"anyhow",
"chrono",
@ -301,7 +301,7 @@ dependencies = [
[[package]]
name = "cm-dashboard-agent"
version = "0.1.153"
version = "0.1.154"
dependencies = [
"anyhow",
"async-trait",
@ -324,7 +324,7 @@ dependencies = [
[[package]]
name = "cm-dashboard-shared"
version = "0.1.153"
version = "0.1.154"
dependencies = [
"chrono",
"serde",

View File

@ -1,6 +1,6 @@
[package]
name = "cm-dashboard-agent"
version = "0.1.153"
version = "0.1.154"
edition = "2021"
[dependencies]

View File

@ -437,12 +437,14 @@ impl DiskCollector {
// Return unknown data rather than failing completely
return Ok(SmartData {
health: "UNKNOWN".to_string(),
serial_number: None,
temperature_celsius: None,
wear_percent: None,
});
}
let mut health = "UNKNOWN".to_string();
let mut serial_number = None;
let mut temperature = None;
let mut wear_percent = None;
@ -455,6 +457,15 @@ impl DiskCollector {
}
}
// Serial number parsing
if line.starts_with("Serial Number:") {
if let Some(serial_part) = line.split("Serial Number:").nth(1) {
if let Some(serial_str) = serial_part.split_whitespace().next() {
serial_number = Some(serial_str.to_string());
}
}
}
// Temperature parsing for different drive types
if line.contains("Temperature_Celsius") || line.contains("Airflow_Temperature_Cel") {
// Traditional SATA drives: attribute table format
@ -497,6 +508,7 @@ impl DiskCollector {
Ok(SmartData {
health,
serial_number,
temperature_celsius: temperature,
wear_percent,
})
@ -587,6 +599,7 @@ impl DiskCollector {
cm_dashboard_shared::PoolDriveData {
name: d.name.clone(),
serial_number: smart.and_then(|s| s.serial_number.clone()),
temperature_celsius: temperature,
health,
wear_percent: smart.and_then(|s| s.wear_percent),
@ -611,6 +624,7 @@ impl DiskCollector {
cm_dashboard_shared::PoolDriveData {
name: d.name.clone(),
serial_number: smart.and_then(|s| s.serial_number.clone()),
temperature_celsius: temperature,
health,
wear_percent: smart.and_then(|s| s.wear_percent),
@ -808,6 +822,7 @@ impl Collector for DiskCollector {
#[derive(Debug, Clone)]
struct SmartData {
health: String,
serial_number: Option<String>,
temperature_celsius: Option<f32>,
wear_percent: Option<f32>,
}

View File

@ -1,6 +1,6 @@
[package]
name = "cm-dashboard"
version = "0.1.153"
version = "0.1.154"
edition = "2021"
[dependencies]

View File

@ -311,8 +311,9 @@ impl SystemWidget {
Status::Unknown
};
let display_name = drive.serial_number.clone().unwrap_or(drive.name.clone());
let storage_drive = StorageDrive {
name: drive.name.clone(),
name: display_name,
temperature: drive.temperature_celsius,
wear_percent: drive.wear_percent,
status: drive_status,
@ -333,8 +334,9 @@ impl SystemWidget {
Status::Unknown
};
let display_name = drive.serial_number.clone().unwrap_or(drive.name.clone());
let storage_drive = StorageDrive {
name: drive.name.clone(),
name: display_name,
temperature: drive.temperature_celsius,
wear_percent: drive.wear_percent,
status: drive_status,

View File

@ -1,6 +1,6 @@
[package]
name = "cm-dashboard-shared"
version = "0.1.153"
version = "0.1.154"
edition = "2021"
[dependencies]

View File

@ -104,6 +104,7 @@ pub struct PoolData {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PoolDriveData {
pub name: String,
pub serial_number: Option<String>,
pub temperature_celsius: Option<f32>,
pub wear_percent: Option<f32>,
pub health: String,