Implement deterministic service disk usage detection with defined paths

- Prioritize defined service directories over systemctl WorkingDirectory fallbacks
- Add ARK Survival Ascended server mappings to correct NixOS-configured paths
- Remove legacy get_service_disk_usage method to eliminate code duplication
- Ensure deterministic behavior with single-purpose detection logic

Fixes ARK service disk usage reporting on srv02 by using actual data paths
from NixOS configuration instead of systemctl working directory detection.
This commit is contained in:
Christoffer Martinsson 2025-10-20 10:45:30 +02:00
parent a3c9ac3617
commit a1c980ad31

View File

@ -291,112 +291,6 @@ impl SystemdCollector {
None None
} }
/// Get service disk usage by examining service working directory
fn get_service_disk_usage(&self, service: &str) -> Option<f32> {
// Try to get working directory from systemctl
let output = Command::new("systemctl")
.arg("show")
.arg(format!("{}.service", service))
.arg("--property=WorkingDirectory")
.output()
.ok()?;
let output_str = String::from_utf8(output.stdout).ok()?;
for line in output_str.lines() {
if line.starts_with("WorkingDirectory=") && !line.contains("[not set]") {
let dir = line.trim_start_matches("WorkingDirectory=");
if !dir.is_empty() && dir != "/" {
return self.get_directory_size(dir);
}
}
}
// Try comprehensive service directory mapping
let service_dirs = match service {
// Container and virtualization services
s if s.contains("docker") => vec!["/var/lib/docker", "/var/lib/docker/containers"],
// Web services and applications
s if s.contains("gitea") => {
vec!["/var/lib/gitea", "/opt/gitea", "/home/git", "/data/gitea"]
}
s if s.contains("nginx") => vec!["/var/log/nginx", "/var/www", "/usr/share/nginx"],
s if s.contains("apache") || s.contains("httpd") => {
vec!["/var/log/apache2", "/var/www", "/etc/apache2"]
}
s if s.contains("immich") => {
vec!["/var/lib/immich", "/opt/immich", "/usr/src/app/upload"]
}
s if s.contains("nextcloud") => vec!["/var/www/nextcloud", "/var/nextcloud"],
s if s.contains("owncloud") => vec!["/var/www/owncloud", "/var/owncloud"],
s if s.contains("plex") => vec!["/var/lib/plexmediaserver", "/opt/plex"],
s if s.contains("jellyfin") => vec!["/var/lib/jellyfin", "/opt/jellyfin"],
s if s.contains("unifi") => vec!["/var/lib/unifi", "/opt/UniFi"],
s if s.contains("vaultwarden") => vec!["/var/lib/vaultwarden", "/opt/vaultwarden"],
s if s.contains("grafana") => vec!["/var/lib/grafana", "/etc/grafana"],
s if s.contains("prometheus") => vec!["/var/lib/prometheus", "/etc/prometheus"],
// Database services
s if s.contains("postgres") => vec!["/var/lib/postgresql", "/var/lib/postgres"],
s if s.contains("mysql") => vec!["/var/lib/mysql"],
s if s.contains("mariadb") => vec!["/var/lib/mysql", "/var/lib/mariadb"],
s if s.contains("redis") => vec!["/var/lib/redis", "/var/redis"],
s if s.contains("mongodb") || s.contains("mongo") => {
vec!["/var/lib/mongodb", "/var/lib/mongo"]
}
// Message queues and communication
s if s.contains("mosquitto") => vec!["/var/lib/mosquitto", "/etc/mosquitto"],
s if s.contains("postfix") => vec!["/var/spool/postfix", "/var/lib/postfix"],
s if s.contains("ssh") => vec!["/var/log/auth.log", "/etc/ssh"],
// Download and sync services
s if s.contains("transmission") => {
vec!["/var/lib/transmission-daemon", "/var/transmission"]
}
s if s.contains("syncthing") => vec!["/var/lib/syncthing", "/home/syncthing"],
// Game servers (ARK Survival Ascended)
s if s == "ark-island" => vec!["/var/lib/ark-servers/island"],
s if s == "ark-scorched" => vec!["/var/lib/ark-servers/scorched"],
s if s == "ark-center" => vec!["/var/lib/ark-servers/center"],
s if s == "ark-aberration" => vec!["/var/lib/ark-servers/aberration"],
s if s == "ark-extinction" => vec!["/var/lib/ark-servers/extinction"],
s if s == "ark-ragnarok" => vec!["/var/lib/ark-servers/ragnarok"],
s if s == "ark-valguero" => vec!["/var/lib/ark-servers/valguero"],
// System services - check logs and config
s if s.contains("systemd") => vec!["/var/log/journal"],
s if s.contains("cron") => vec!["/var/spool/cron", "/var/log/cron"],
// Default fallbacks for any service
_ => vec![],
};
// Try each service-specific directory first
for dir in service_dirs {
if let Some(size) = self.get_directory_size(dir) {
return Some(size);
}
}
// Try common fallback directories for unmatched services
let fallback_patterns = [
format!("/var/lib/{}", service),
format!("/opt/{}", service),
format!("/usr/share/{}", service),
format!("/var/log/{}", service),
format!("/etc/{}", service),
];
for dir in &fallback_patterns {
if let Some(size) = self.get_directory_size(dir) {
return Some(size);
}
}
None
}
/// Get directory size in GB with permission-aware logging /// Get directory size in GB with permission-aware logging
fn get_directory_size(&self, dir: &str) -> Option<f32> { fn get_directory_size(&self, dir: &str) -> Option<f32> {
@ -456,7 +350,15 @@ impl SystemdCollector {
/// Basic service disk usage detection (existing logic) /// Basic service disk usage detection (existing logic)
fn get_service_disk_usage_basic(&self, service: &str) -> Option<f32> { fn get_service_disk_usage_basic(&self, service: &str) -> Option<f32> {
// Try to get working directory from systemctl // Check defined service paths FIRST (highest priority)
let service_dirs = self.get_service_directories(service);
for dir in service_dirs {
if let Some(size) = self.get_directory_size(dir) {
return Some(size);
}
}
// Only if no defined path, try systemctl WorkingDirectory
let output = Command::new("systemctl") let output = Command::new("systemctl")
.arg("show") .arg("show")
.arg(format!("{}.service", service)) .arg(format!("{}.service", service))
@ -474,16 +376,26 @@ impl SystemdCollector {
} }
} }
// Try service-specific known directories None
let service_dirs = match service { }
/// Get defined service directories (highest priority)
fn get_service_directories(&self, service: &str) -> Vec<&str> {
match service {
// Game servers (ARK Survival Ascended) - HIGHEST PRIORITY
"ark-island" => vec!["/var/lib/ark-servers/island"],
"ark-scorched" => vec!["/var/lib/ark-servers/scorched"],
"ark-center" => vec!["/var/lib/ark-servers/center"],
"ark-aberration" => vec!["/var/lib/ark-servers/aberration"],
"ark-extinction" => vec!["/var/lib/ark-servers/extinction"],
"ark-ragnarok" => vec!["/var/lib/ark-servers/ragnarok"],
"ark-valguero" => vec!["/var/lib/ark-servers/valguero"],
// Other services with defined paths
s if s.contains("docker") => vec!["/var/lib/docker", "/var/lib/docker/containers"], s if s.contains("docker") => vec!["/var/lib/docker", "/var/lib/docker/containers"],
s if s.contains("gitea") => { s if s.contains("gitea") => vec!["/var/lib/gitea", "/opt/gitea", "/home/git", "/data/gitea"],
vec!["/var/lib/gitea", "/opt/gitea", "/home/git", "/data/gitea"]
}
s if s.contains("nginx") => vec!["/var/log/nginx", "/var/www", "/usr/share/nginx"], s if s.contains("nginx") => vec!["/var/log/nginx", "/var/www", "/usr/share/nginx"],
s if s.contains("immich") => { s if s.contains("immich") => vec!["/var/lib/immich", "/opt/immich", "/usr/src/app/upload"],
vec!["/var/lib/immich", "/opt/immich", "/usr/src/app/upload"]
}
s if s.contains("postgres") => vec!["/var/lib/postgresql", "/var/lib/postgres"], s if s.contains("postgres") => vec!["/var/lib/postgresql", "/var/lib/postgres"],
s if s.contains("mysql") => vec!["/var/lib/mysql"], s if s.contains("mysql") => vec!["/var/lib/mysql"],
s if s.contains("redis") => vec!["/var/lib/redis", "/var/redis"], s if s.contains("redis") => vec!["/var/lib/redis", "/var/redis"],
@ -491,16 +403,10 @@ impl SystemdCollector {
s if s.contains("vaultwarden") => vec!["/var/lib/vaultwarden", "/opt/vaultwarden"], s if s.contains("vaultwarden") => vec!["/var/lib/vaultwarden", "/opt/vaultwarden"],
s if s.contains("mosquitto") => vec!["/var/lib/mosquitto", "/etc/mosquitto"], s if s.contains("mosquitto") => vec!["/var/lib/mosquitto", "/etc/mosquitto"],
s if s.contains("postfix") => vec!["/var/spool/postfix", "/var/lib/postfix"], s if s.contains("postfix") => vec!["/var/spool/postfix", "/var/lib/postfix"],
// No defined path - will fall back to systemctl WorkingDirectory
_ => vec![], _ => vec![],
};
for dir in service_dirs {
if let Some(size) = self.get_directory_size(dir) {
return Some(size);
}
} }
None
} }
/// Check service binary and configuration directories /// Check service binary and configuration directories