package hub import ( "context" "os/exec" "strings" ) // CloudflaredProber reports the cloudflared tunnel service health. It is a // READ-ONLY probe: the agent does NOT manage or restart cloudflared in this slice // (that is the tunnel-management slice — this is the seam for it). Injectable so // tests use a fake and never exec. type CloudflaredProber interface { // Status returns one of: "active" | "inactive" | "failed" | "unknown". Status(ctx context.Context) (string, error) } // SystemctlProber runs `systemctl is-active cloudflared`. This is NOT a Privileged // (root-CLI) op — `is-active` is non-root readable and is not one of the three // proven root exceptions, so it does not go through internal/proxmox.Privileged. type SystemctlProber struct { Unit string // defaults to "cloudflared" } // Status maps `systemctl is-active` output to the report vocabulary. systemctl // exits non-zero for inactive/failed, so the output string is authoritative over // the exit code; any exec error (binary missing, etc.) maps to "unknown". func (p SystemctlProber) Status(ctx context.Context) (string, error) { unit := p.Unit if unit == "" { unit = "cloudflared" } out, _ := exec.CommandContext(ctx, "systemctl", "is-active", unit).Output() switch strings.TrimSpace(string(out)) { case "active": return "active", nil case "failed": return "failed", nil case "inactive", "deactivating", "activating": return "inactive", nil case "": return "unknown", nil // no output → systemctl/exec problem default: return "unknown", nil } }