diff --git a/agent/src/collectors/service.rs b/agent/src/collectors/service.rs index 8374a31..947ebfb 100644 --- a/agent/src/collectors/service.rs +++ b/agent/src/collectors/service.rs @@ -81,8 +81,9 @@ impl ServiceCollector { // Check if service is sandboxed (needed for status determination) let is_sandboxed = self.check_service_sandbox(service).await.unwrap_or(false); + let is_sandbox_excluded = self.is_sandbox_excluded(service); - let status = self.determine_service_status(&active_state, &sub_state, is_sandboxed); + let status = self.determine_service_status(&active_state, &sub_state, is_sandboxed, service); // Get resource usage if service is running let (memory_used_mb, cpu_percent) = if let Some(pid) = main_pid { @@ -125,21 +126,36 @@ impl ServiceCollector { disk_used_gb, disk_quota_gb, is_sandboxed, + is_sandbox_excluded, description, sub_service: None, }) } + fn is_sandbox_excluded(&self, service: &str) -> bool { + // Services that don't need sandboxing due to their nature + matches!(service, + "sshd" | "ssh" | // SSH needs system access for auth/shell + "docker" | // Docker needs broad system access + "systemd-logind" | // System service + "systemd-resolved" | // System service + "dbus" | // System service + "NetworkManager" | // Network management + "wpa_supplicant" // WiFi management + ) + } + fn determine_service_status( &self, active_state: &Option, sub_state: &Option, is_sandboxed: bool, + service_name: &str, ) -> ServiceStatus { match (active_state.as_deref(), sub_state.as_deref()) { (Some("active"), Some("running")) => { - // Running services should be degraded if not sandboxed - if is_sandboxed { + // Check if service is excluded from sandbox requirements + if self.is_sandbox_excluded(service_name) || is_sandboxed { ServiceStatus::Running } else { ServiceStatus::Degraded // Warning status for unsandboxed running services @@ -147,7 +163,7 @@ impl ServiceCollector { }, (Some("active"), Some("exited")) => { // One-shot services should also be degraded if not sandboxed - if is_sandboxed { + if self.is_sandbox_excluded(service_name) || is_sandboxed { ServiceStatus::Running } else { ServiceStatus::Degraded @@ -1314,6 +1330,7 @@ impl Collector for ServiceCollector { disk_used_gb: 0.0, disk_quota_gb: 0.0, is_sandboxed: false, // Sub-services inherit parent sandbox status + is_sandbox_excluded: false, description: None, sub_service: Some("nginx".to_string()), }); @@ -1341,6 +1358,7 @@ impl Collector for ServiceCollector { disk_used_gb: 0.0, disk_quota_gb: 0.0, is_sandboxed: true, // Docker containers are inherently sandboxed + is_sandbox_excluded: false, description: None, sub_service: Some("docker".to_string()), }); @@ -1364,6 +1382,7 @@ impl Collector for ServiceCollector { disk_used_gb: 0.0, disk_quota_gb: 0.0, is_sandboxed: false, // Unknown for failed services + is_sandbox_excluded: false, description: None, sub_service: None, }); @@ -1425,6 +1444,7 @@ struct ServiceData { disk_used_gb: f32, disk_quota_gb: f32, is_sandboxed: bool, + is_sandbox_excluded: bool, #[serde(skip_serializing_if = "Option::is_none")] description: Option>, #[serde(default)] diff --git a/dashboard/src/data/metrics.rs b/dashboard/src/data/metrics.rs index decc624..110bbbd 100644 --- a/dashboard/src/data/metrics.rs +++ b/dashboard/src/data/metrics.rs @@ -121,6 +121,8 @@ pub struct ServiceInfo { #[serde(default)] pub is_sandboxed: bool, #[serde(default)] + pub is_sandbox_excluded: bool, + #[serde(default)] pub description: Option>, #[serde(default)] pub sub_service: Option, diff --git a/dashboard/src/ui/services.rs b/dashboard/src/ui/services.rs index 406d1d0..50aaf43 100644 --- a/dashboard/src/ui/services.rs +++ b/dashboard/src/ui/services.rs @@ -129,7 +129,7 @@ fn render_metrics( format_memory_value(svc.memory_used_mb, svc.memory_quota_mb), format_cpu_value(svc.cpu_percent), format_disk_value(svc.disk_used_gb, svc.disk_quota_gb), - format_sandbox_value(svc.is_sandboxed), + format_sandbox_value(svc.is_sandboxed, svc.is_sandbox_excluded), ], ); } @@ -171,11 +171,13 @@ fn format_disk_value(used: f32, quota: f32) -> String { } } -fn format_sandbox_value(is_sandboxed: bool) -> String { +fn format_sandbox_value(is_sandboxed: bool, is_excluded: bool) -> String { if is_sandboxed { "yes".to_string() + } else if is_excluded { + "no(ok)".to_string() // Excluded services don't need sandboxing } else { - "no".to_string() + "no".to_string() // Services that should be sandboxed but aren't } }