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.
This commit is contained in:
Christoffer Martinsson 2025-10-20 22:41:21 +02:00
parent eb268922bd
commit 5886426dac

View File

@ -111,19 +111,29 @@ impl SystemdCollector {
/// Auto-discover interesting services to monitor /// Auto-discover interesting services to monitor
fn discover_services(&self) -> Result<Vec<String>> { fn discover_services(&self) -> Result<Vec<String>> {
let output = Command::new("systemctl") // First get all unit files (includes inactive services)
.arg("list-units") let unit_files_output = Command::new("systemctl")
.arg("list-unit-files")
.arg("--type=service") .arg("--type=service")
.arg("--state=running,failed,inactive")
.arg("--no-pager") .arg("--no-pager")
.arg("--plain") .arg("--plain")
.output()?; .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")); 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(); let mut services = Vec::new();
// Skip setup/certificate services that don't need monitoring (from legacy) // 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) // Define patterns for services we want to monitor (from legacy)
let interesting_services = [ let service_name_filters = [
// Web applications // Web applications
"gitea", "gitea",
"immich", "immich",
@ -183,10 +193,29 @@ impl SystemdCollector {
"ark", "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(); let fields: Vec<&str> = line.split_whitespace().collect();
if fields.len() >= 4 && fields[0].ends_with(".service") { if fields.len() >= 4 && fields[0].ends_with(".service") {
let service_name = fields[0].trim_end_matches(".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); debug!("Processing service: '{}'", service_name);
// Skip excluded services first // Skip excluded services first
@ -207,8 +236,8 @@ impl SystemdCollector {
continue; continue;
} }
// Check if this service matches our interesting patterns // Check if this service matches our filter patterns
for pattern in &interesting_services { for pattern in &service_name_filters {
if service_name.contains(pattern) || pattern.contains(service_name) { if service_name.contains(pattern) || pattern.contains(service_name) {
debug!( debug!(
"INCLUDING service '{}' because it matches pattern '{}'", "INCLUDING service '{}' because it matches pattern '{}'",
@ -218,21 +247,8 @@ impl SystemdCollector {
break; 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) Ok(services)
} }