diff --git a/src/backend/hosts/metrics/host-status.test.ts b/src/backend/hosts/metrics/host-status.test.ts index f41c4544..55ab03c8 100644 --- a/src/backend/hosts/metrics/host-status.test.ts +++ b/src/backend/hosts/metrics/host-status.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from "vitest"; import { + needsStatusPollAuthentication, statusAfterAuthentication, statusAfterReachabilityCheck, } from "./host-status.js"; @@ -21,4 +22,11 @@ describe("host availability status", () => { expect(statusAfterAuthentication(false, "online")).toBe("reachable"); expect(statusAfterAuthentication(false, "offline")).toBe("offline"); }); + + it("authenticates in the status probe unless a metrics poll will do it", () => { + expect(needsStatusPollAuthentication(false, false)).toBe(true); + expect(needsStatusPollAuthentication(false, true)).toBe(true); + expect(needsStatusPollAuthentication(true, false)).toBe(true); + expect(needsStatusPollAuthentication(true, true)).toBe(false); + }); }); diff --git a/src/backend/hosts/metrics/host-status.ts b/src/backend/hosts/metrics/host-status.ts index 3c5b3914..7c1a39e5 100644 --- a/src/backend/hosts/metrics/host-status.ts +++ b/src/backend/hosts/metrics/host-status.ts @@ -15,3 +15,18 @@ export function statusAfterAuthentication( if (authenticated) return "online"; return current === "offline" ? "offline" : "reachable"; } + +/** + * Whether the cheap status probe must also authenticate over SSH. + * + * "online" means authenticated, and normally the metrics poll proves that. + * That poll only runs while someone is viewing the host, so an unwatched host + * with metrics enabled would otherwise never leave "reachable" - while a host + * with metrics disabled, whose probe always authenticates, shows online. + */ +export function needsStatusPollAuthentication( + metricsEnabled: boolean, + hasViewers: boolean, +): boolean { + return !metricsEnabled || !hasViewers; +} diff --git a/src/backend/hosts/metrics/index.ts b/src/backend/hosts/metrics/index.ts index 4229be4c..be431cf1 100644 --- a/src/backend/hosts/metrics/index.ts +++ b/src/backend/hosts/metrics/index.ts @@ -71,6 +71,7 @@ import { } from "./helpers.js"; import { type HostStatus, + needsStatusPollAuthentication, statusAfterAuthentication, statusAfterReachabilityCheck, } from "./host-status.js"; @@ -581,7 +582,10 @@ class PollingManager { if ( isOnline && supportsMetrics(refreshedHost) && - !config?.statsConfig.metricsEnabled + needsStatusPollAuthentication( + !!config?.statsConfig.metricsEnabled, + this.activeViewers.has(refreshedHost.id), + ) ) { try { await withSshConnection(refreshedHost, async () => undefined);