From 5886426dac9df5eee7e3d1662791ab09c231833e Mon Sep 17 00:00:00 2001 From: Christoffer Martinsson Date: Mon, 20 Oct 2025 22:41:21 +0200 Subject: [PATCH] Fix service discovery to detect all services regardless of state - Use systemctl list-unit-files and list-units --all to find inactive services - Parse both outputs to ensure all services are discovered - Remove special SSH detection logic since sshd is in service filters - Rename interesting_services to service_name_filters for clarity - Now detects services in any state: active, inactive, failed, dead, etc. --- agent/src/collectors/systemd.rs | 60 +++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/agent/src/collectors/systemd.rs b/agent/src/collectors/systemd.rs index ca9e4c1..20430c3 100644 --- a/agent/src/collectors/systemd.rs +++ b/agent/src/collectors/systemd.rs @@ -111,19 +111,29 @@ impl SystemdCollector { /// Auto-discover interesting services to monitor fn discover_services(&self) -> Result> { - let output = Command::new("systemctl") - .arg("list-units") + // First get all unit files (includes inactive services) + let unit_files_output = Command::new("systemctl") + .arg("list-unit-files") .arg("--type=service") - .arg("--state=running,failed,inactive") .arg("--no-pager") .arg("--plain") .output()?; - if !output.status.success() { + // Then get all loaded units (includes running/failed services) + let units_output = Command::new("systemctl") + .arg("list-units") + .arg("--type=service") + .arg("--all") + .arg("--no-pager") + .arg("--plain") + .output()?; + + if !unit_files_output.status.success() || !units_output.status.success() { return Err(anyhow::anyhow!("systemctl command failed")); } - let output_str = String::from_utf8(output.stdout)?; + let unit_files_str = String::from_utf8(unit_files_output.stdout)?; + let units_str = String::from_utf8(units_output.stdout)?; let mut services = Vec::new(); // Skip setup/certificate services that don't need monitoring (from legacy) @@ -142,7 +152,7 @@ impl SystemdCollector { ]; // Define patterns for services we want to monitor (from legacy) - let interesting_services = [ + let service_name_filters = [ // Web applications "gitea", "immich", @@ -183,10 +193,29 @@ impl SystemdCollector { "ark", ]; - for line in output_str.lines() { + // Parse both unit files and loaded units + let mut all_service_names = std::collections::HashSet::new(); + + // Parse unit files (includes inactive services) + for line in unit_files_str.lines() { + let fields: Vec<&str> = line.split_whitespace().collect(); + if fields.len() >= 2 && fields[0].ends_with(".service") { + let service_name = fields[0].trim_end_matches(".service"); + all_service_names.insert(service_name.to_string()); + } + } + + // Parse loaded units (includes running/failed services) + for line in units_str.lines() { let fields: Vec<&str> = line.split_whitespace().collect(); if fields.len() >= 4 && fields[0].ends_with(".service") { let service_name = fields[0].trim_end_matches(".service"); + all_service_names.insert(service_name.to_string()); + } + } + + // Now process all discovered services + for service_name in &all_service_names { debug!("Processing service: '{}'", service_name); // Skip excluded services first @@ -207,8 +236,8 @@ impl SystemdCollector { continue; } - // Check if this service matches our interesting patterns - for pattern in &interesting_services { + // Check if this service matches our filter patterns + for pattern in &service_name_filters { if service_name.contains(pattern) || pattern.contains(service_name) { debug!( "INCLUDING service '{}' because it matches pattern '{}'", @@ -218,21 +247,8 @@ impl SystemdCollector { break; } } - } } - // Always include ssh/sshd if present - if !services.iter().any(|s| s.contains("ssh")) { - for line in output_str.lines() { - let fields: Vec<&str> = line.split_whitespace().collect(); - if fields.len() >= 4 && (fields[0] == "sshd.service" || fields[0] == "ssh.service") - { - let service_name = fields[0].trim_end_matches(".service"); - services.push(service_name.to_string()); - break; - } - } - } Ok(services) }