Prefer monitor connection state in diagnostics

This commit is contained in:
rcourtman 2026-03-26 22:58:57 +00:00
parent 65092bea4e
commit d310c257a1
2 changed files with 70 additions and 6 deletions

View file

@ -281,6 +281,29 @@ type PBSDetails struct {
Version string `json:"version,omitempty"`
}
func diagnosticsMonitorConnectionStatus(m *monitoring.Monitor, key string) (bool, bool) {
if m == nil || strings.TrimSpace(key) == "" {
return false, false
}
statuses := m.GetConnectionStatuses()
connected, ok := statuses[key]
return connected, ok
}
func mergeDiagnosticsConnection(probeConnected bool, probeError string, monitorConnected bool, hasMonitorStatus bool) (bool, string) {
if probeConnected {
return true, probeError
}
if !hasMonitorStatus || !monitorConnected {
return false, probeError
}
if strings.TrimSpace(probeError) == "" {
return true, ""
}
return true, "Live diagnostics probe failed, but the monitor still reports this instance connected: " + probeError
}
// SystemDiagnostic contains system-level diagnostic info
type SystemDiagnostic struct {
OS string `json:"os"`
@ -462,6 +485,7 @@ func (r *Router) computeDiagnostics(ctx context.Context) DiagnosticsInfo {
Host: node.Host,
Type: "pve",
}
monitorConnected, hasMonitorStatus := diagnosticsMonitorConnectionStatus(r.monitor, node.Name)
// Determine auth method (sanitized - don't expose actual values)
if node.TokenName != "" && node.TokenValue != "" {
@ -475,24 +499,26 @@ func (r *Router) computeDiagnostics(ctx context.Context) DiagnosticsInfo {
// Test connection
testCfg := proxmox.ClientConfig{
Host: node.Host,
User: node.User,
Password: node.Password,
TokenName: node.TokenName,
TokenValue: node.TokenValue,
Host: node.Host,
User: node.User,
Password: node.Password,
TokenName: node.TokenName,
TokenValue: node.TokenValue,
Fingerprint: node.Fingerprint,
VerifySSL: node.VerifySSL,
VerifySSL: node.VerifySSL,
}
client, err := proxmox.NewClient(testCfg)
if err != nil {
nodeDiag.Connected = false
nodeDiag.Error = err.Error()
nodeDiag.Connected, nodeDiag.Error = mergeDiagnosticsConnection(nodeDiag.Connected, nodeDiag.Error, monitorConnected, hasMonitorStatus)
} else {
nodes, err := client.GetNodes(ctx)
if err != nil {
nodeDiag.Connected = false
nodeDiag.Error = "Failed to connect to Proxmox API: " + err.Error()
nodeDiag.Connected, nodeDiag.Error = mergeDiagnosticsConnection(nodeDiag.Connected, nodeDiag.Error, monitorConnected, hasMonitorStatus)
} else {
nodeDiag.Connected = true
@ -530,6 +556,7 @@ func (r *Router) computeDiagnostics(ctx context.Context) DiagnosticsInfo {
Name: pbsNode.Name,
Host: pbsNode.Host,
}
monitorConnected, hasMonitorStatus := diagnosticsMonitorConnectionStatus(r.monitor, "pbs-"+pbsNode.Name)
testCfg := pbs.ClientConfig{
Host: pbsNode.Host,
@ -545,10 +572,12 @@ func (r *Router) computeDiagnostics(ctx context.Context) DiagnosticsInfo {
if err != nil {
pbsDiag.Connected = false
pbsDiag.Error = err.Error()
pbsDiag.Connected, pbsDiag.Error = mergeDiagnosticsConnection(pbsDiag.Connected, pbsDiag.Error, monitorConnected, hasMonitorStatus)
} else {
if version, err := client.GetVersion(ctx); err != nil {
pbsDiag.Connected = false
pbsDiag.Error = "Connection established but version check failed: " + err.Error()
pbsDiag.Connected, pbsDiag.Error = mergeDiagnosticsConnection(pbsDiag.Connected, pbsDiag.Error, monitorConnected, hasMonitorStatus)
} else {
pbsDiag.Connected = true
pbsDiag.Details = &PBSDetails{Version: version.Version}

View file

@ -210,6 +210,41 @@ func TestComputeDiagnostics_PVEUsesFingerprint(t *testing.T) {
}
}
func TestMergeDiagnosticsConnection(t *testing.T) {
t.Run("keeps successful probe", func(t *testing.T) {
connected, errMsg := mergeDiagnosticsConnection(true, "", false, false)
if !connected {
t.Fatalf("expected successful probe to stay connected")
}
if errMsg != "" {
t.Fatalf("expected no error, got %q", errMsg)
}
})
t.Run("keeps probe failure when monitor also disagrees", func(t *testing.T) {
connected, errMsg := mergeDiagnosticsConnection(false, "probe failed", false, true)
if connected {
t.Fatalf("expected connection to remain false")
}
if errMsg != "probe failed" {
t.Fatalf("expected original error, got %q", errMsg)
}
})
t.Run("prefers monitor connected state over transient probe failure", func(t *testing.T) {
connected, errMsg := mergeDiagnosticsConnection(false, "probe failed", true, true)
if !connected {
t.Fatalf("expected monitor-connected instance to stay connected")
}
if !strings.Contains(errMsg, "monitor still reports this instance connected") {
t.Fatalf("expected merged warning, got %q", errMsg)
}
if !strings.Contains(errMsg, "probe failed") {
t.Fatalf("expected original probe error to be preserved, got %q", errMsg)
}
})
}
func TestBuildAPITokenDiagnostic_WithDockerUsage(t *testing.T) {
now := time.Now()
lastUsed := now.Add(-time.Hour)