The unified /api/connections aggregator emits IDs as {type}:{name}
(e.g. "pve:delly"), but the PUT/DELETE/refresh-cluster/test endpoints
only parsed the legacy {type}-{index} array-position form. That left
the new Connection surface unable to drive any mutation against the
entries it lists.
HandleUpdateNode, HandleDeleteNode, HandleRefreshClusterNodes, and
HandleTestNode now route the incoming ID through a shared
resolveNodeID helper: colon-form resolves by Name (404 on miss),
dash-form keeps the existing index semantics. Frontend connection
client gains setEnabled/remove that dispatch to the right per-type
endpoint by ID prefix.
/api2/json/version requires authentication, and PVE/PBS deliberately delay
401 responses by ~3s as a timing-attack mitigation. Our 3s probe budget
fired right as the 401 arrived — every probe returned zero candidates
against real targets.
Switch the PVE/PBS/PMG fingerprint path to the web-UI root (/), which
serves the login page in <100ms and carries the same identifying Server
banner (PVE/PMG) or an unambiguous HTML title (PBS, which omits the
Server header on /). Drop versionHintsFromProxmoxBody — /version was the
only caller, and we can surface version after authentication instead.
Verified end-to-end against a live PVE (delly:8006, 41ms) and live PBS
(100.106.60.119:8007, 70ms); fan-out on a bare hostname returns the
correct product.
Adds positive MonitorDatasets/Pools/Replication booleans to TrueNASInstance
and MonitorVMs/Hosts/Datastores to VMwareVCenterInstance, matching the
PVE/PBS/PMG scope pattern. NewInstance defaults all surfaces to true;
ApplyDefaults migrates legacy all-false records to all-true so existing
truenas.json / vmware.json on disk continue monitoring after upgrade.
The unified connections aggregator now reads those booleans into the
Scope map and flips SupportsScope to true for both types, so the Scope
UI in the ConnectionEditor is a straight wire-through to the native
config fields — no new storage or adapter layer. Per-type API clients,
form state, and the TrueNAS and VMware credential slots render the same
three-checkbox "Collection scope" panel used by PVE/PBS/PMG, replacing
the old per-type Stop-this-surface dialog end-to-end from the editor's
side.
Contracts updated: agent-lifecycle, api-contracts, storage-recovery.
Tests: truenas.test.ts and vmware.test.ts round-trip the new monitor*
flags through list + update payloads; config tests cover the legacy
all-false ApplyDefaults migration; aggregator test asserts the scope map
and SupportsScope: true for both types.
Provider Refresh paths still fetch everything in one trip; honoring
Monitor* inside VMware and TrueNAS pollers is deferred to a follow-up.
Introduces GET /api/connections and POST /api/connections/probe as the
backend half of the one-ledger / one-editor connection redesign.
- GET /api/connections aggregates PVE/PBS/PMG/VMware/TrueNAS/agent rows
into a unified Connection shape with derived state (active, paused,
unauthorized, unreachable, stale, pending) computed from in-memory
scheduler health plus agent Host.LastSeen. No new persisted state.
- POST /api/connections/probe fingerprints a host across the five
supported products in parallel (2s dial + 1s read, 3s total, max 5
concurrent). Admin-gated (RequireAdmin + ScopeSettingsWrite) to block
unauthenticated SSRF against internal hosts.
- Disabled bool on PVEInstance/PBSInstance/PMGInstance (zero-value =
enabled, preserves existing nodes.json); pollers skip disabled
instances at client init, reconnect, and per-node iteration.
- NodeConfigRequest/Response gain Enabled; write path translates
*bool -> Disabled so omitted field leaves state untouched.
- ConnectionsAPI frontend client (list/probe) typed off the Go shape.
Contracts updated: api-contracts, monitoring, agent-lifecycle,
performance-and-scalability, storage-recovery. Proofs added:
contract_test.go JSON snapshot for Connection and ProbeResponse,
monitoring guardrails for the Disabled-skip behavior, and a vitest
mock-client test for ConnectionsAPI.
Frontend editor / drawer / table rewrite lands in a separate block.
Summary cards now show degraded/alerting/failing counts rather than raw
online/offline splits, giving operators an at-a-glance health posture without
drilling into the full resource list.
- InfrastructureSummary/infrastructureSummaryModel: adds degraded and alerting
counts derived from resource statuses and active alerts
- StorageSummary/StoragePageSummary/useStoragePageSummary: adds poolsDegraded
and disksFailing indicators, shows "all healthy" when zero degradation
- WorkloadsSummary/useDashboardWorkloadDerivedState: adds alerting guest count
from activeAlerts accessor, included in summary header counts
- RecoverySummary: adds aggregate health-state summary row
- useDashboardState: threads alertsEnabled through workload derived state
- Fix monitored-system cap test helper to use TierEnterprise so limits are
honored (self-hosted tiers are now uncapped per the v6 product model)
- Update registry and governance test snapshots to include
useStoragePageSummary.test.ts in the storage-product-surface proof set
Two test regressions introduced when agent-report tokens were allowed as
fallback auth for /api/auto-register:
1. Org mismatch was not checked: a token belonging to org-a could authenticate
a request whose context carried org-b. Add an explicit org consistency check
before setting authenticated=true in the fallback path.
2. The security regression test assumed only setup tokens could authenticate
auto-register. That contract has intentionally changed: agent-report tokens
can now authenticate but are restricted to updating existing nodes (403 for
new-node attempts). Update the test to assert the actual security boundary.
The isKnownDisconnected helper was building the key as
instanceType+"-"+instanceName ("pve-delly"), but the PVE
PollProvider's connectionKey function returns the bare instance
name ("delly"). PBS uses "pbs-"+name. The mismatch meant the
disconnected-node check always missed, rendering the server-side
stale-token detection inert.
Fix: use type-specific key construction matching the PollProvider
connectionKey implementations.
Two gaps in the existing flow allowed a disconnected PVE node to stay
broken indefinitely even after the agent restarted:
1. Server-side: autoRegisteredNodeExists checked only that a PVE/PBS
instance existed in the config, not whether its connection was
healthy. A node with a stale token would return registered=true on
every check, causing the agent to skip re-registration forever.
Fixed: also consult GetConnectionStatuses(); return registered=false
when the monitor has a definitive disconnected entry so the agent can
rotate and re-register.
2. Agent-side: the type-specific registration marker was cleared only on
success. If rotation succeeded but the Pulse update failed (e.g.
transient network error), the old marker from a previous successful
registration persisted, leaving next-startup to skip setup again.
Fixed: clear the marker before entering the token setup/rotation
phase so any failure leaves the system in a retriable state.
Together these two fixes make the stale-token scenario self-healing:
the monitor detects the broken connection, the next agent startup sees
registered=false, clears its marker, rotates the token, and updates
Pulse — without manual intervention.