Integrate SnapRAID parity drives into mergerfs pools
All checks were successful
Build and Release / build-and-release (push) Successful in 1m19s
All checks were successful
Build and Release / build-and-release (push) Successful in 1m19s
- Add SnapRAID parity drive detection to mergerfs discovery - Remove Pool Status health line as discussed - Update drive display to always show wear data when available - Include /mnt/parity drives as part of mergerfs pool structure
This commit is contained in:
parent
43fb838c9b
commit
192eea6e0c
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -279,7 +279,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cm-dashboard"
|
name = "cm-dashboard"
|
||||||
version = "0.1.123"
|
version = "0.1.124"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -301,7 +301,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cm-dashboard-agent"
|
name = "cm-dashboard-agent"
|
||||||
version = "0.1.123"
|
version = "0.1.124"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -324,7 +324,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cm-dashboard-shared"
|
name = "cm-dashboard-shared"
|
||||||
version = "0.1.123"
|
version = "0.1.124"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cm-dashboard-agent"
|
name = "cm-dashboard-agent"
|
||||||
version = "0.1.123"
|
version = "0.1.124"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -210,7 +210,7 @@ impl DiskCollector {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Convert numeric references to actual mount points if needed
|
// Convert numeric references to actual mount points if needed
|
||||||
let member_paths = if raw_paths.iter().any(|path| !path.starts_with('/')) {
|
let mut member_paths = if raw_paths.iter().any(|path| !path.starts_with('/')) {
|
||||||
// Handle numeric format like "1:2" by finding corresponding /mnt/disk* paths
|
// Handle numeric format like "1:2" by finding corresponding /mnt/disk* paths
|
||||||
self.resolve_numeric_mergerfs_paths(&raw_paths)?
|
self.resolve_numeric_mergerfs_paths(&raw_paths)?
|
||||||
} else {
|
} else {
|
||||||
@ -218,6 +218,10 @@ impl DiskCollector {
|
|||||||
raw_paths
|
raw_paths
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For SnapRAID setups, also include parity drives as part of the pool
|
||||||
|
let snapraid_parity_paths = self.discover_snapraid_parity_drives()?;
|
||||||
|
member_paths.extend(snapraid_parity_paths);
|
||||||
|
|
||||||
// Categorize as data vs parity drives
|
// Categorize as data vs parity drives
|
||||||
let (data_drives, parity_drives) = match self.categorize_pool_drives(&member_paths) {
|
let (data_drives, parity_drives) = match self.categorize_pool_drives(&member_paths) {
|
||||||
Ok(drives) => drives,
|
Ok(drives) => drives,
|
||||||
@ -240,6 +244,16 @@ impl DiskCollector {
|
|||||||
Ok(pools)
|
Ok(pools)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Discover SnapRAID parity drives
|
||||||
|
fn discover_snapraid_parity_drives(&self) -> Result<Vec<String>> {
|
||||||
|
let mount_devices = self.get_mount_devices()?;
|
||||||
|
let parity_paths: Vec<String> = mount_devices.keys()
|
||||||
|
.filter(|path| path.contains("parity"))
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
Ok(parity_paths)
|
||||||
|
}
|
||||||
|
|
||||||
/// Categorize pool member drives as data vs parity
|
/// Categorize pool member drives as data vs parity
|
||||||
fn categorize_pool_drives(&self, member_paths: &[String]) -> Result<(Vec<DriveInfo>, Vec<DriveInfo>)> {
|
fn categorize_pool_drives(&self, member_paths: &[String]) -> Result<(Vec<DriveInfo>, Vec<DriveInfo>)> {
|
||||||
let mut data_drives = Vec::new();
|
let mut data_drives = Vec::new();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cm-dashboard"
|
name = "cm-dashboard"
|
||||||
version = "0.1.123"
|
version = "0.1.124"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -470,26 +470,7 @@ impl SystemWidget {
|
|||||||
);
|
);
|
||||||
lines.push(Line::from(pool_spans));
|
lines.push(Line::from(pool_spans));
|
||||||
|
|
||||||
// Pool health line (for multi-disk pools)
|
// Skip pool health line as discussed - removed
|
||||||
if pool.pool_type != "single" {
|
|
||||||
if let Some(health) = &pool.pool_health {
|
|
||||||
let health_text = match health.as_str() {
|
|
||||||
"healthy" => format!("Pool Status: {} Healthy",
|
|
||||||
if pool.drives.len() > 1 { format!("({} drives)", pool.drives.len()) } else { String::new() }),
|
|
||||||
"degraded" => "Pool Status: ⚠ Degraded".to_string(),
|
|
||||||
"critical" => "Pool Status: ✗ Critical".to_string(),
|
|
||||||
"rebuilding" => "Pool Status: ⟳ Rebuilding".to_string(),
|
|
||||||
_ => format!("Pool Status: ? {}", health),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut health_spans = vec![
|
|
||||||
Span::raw(" "),
|
|
||||||
Span::styled("├─ ", Typography::tree()),
|
|
||||||
];
|
|
||||||
health_spans.extend(StatusIcons::create_status_spans(pool.health_status.clone(), &health_text));
|
|
||||||
lines.push(Line::from(health_spans));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Total usage line (always show for pools)
|
// Total usage line (always show for pools)
|
||||||
let usage_text = match (pool.usage_percent, pool.used_gb, pool.total_gb) {
|
let usage_text = match (pool.usage_percent, pool.used_gb, pool.total_gb) {
|
||||||
@ -641,10 +622,12 @@ impl SystemWidget {
|
|||||||
if let Some(wear) = drive.wear_percent {
|
if let Some(wear) = drive.wear_percent {
|
||||||
drive_info.push(format!("W: {:.0}%", wear));
|
drive_info.push(format!("W: {:.0}%", wear));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always show drive name with info, or just name if no info available
|
||||||
let drive_text = if drive_info.is_empty() {
|
let drive_text = if drive_info.is_empty() {
|
||||||
drive.name.clone()
|
drive.name.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("{} {}", drive.name, drive_info.join(" • "))
|
format!("{} {}", drive.name, drive_info.join(" "))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut drive_spans = vec![
|
let mut drive_spans = vec![
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cm-dashboard-shared"
|
name = "cm-dashboard-shared"
|
||||||
version = "0.1.123"
|
version = "0.1.124"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user