Repository navigation
Stop three topology nodes reporting health nothing checked - #1668
Conversation
PR Summary by QodoCorrect topology health for routes, HPAs, and referenced Secrets
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
1. New autoscalers appear healthy
|
20d8575 to
dab49fa
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit dab49fa. Configure here.
A node's status is not only a dot in the graph: MCP builds its get_topology problem list from degraded and unhealthy nodes, and GitOps derives managed-resource health from it. A green node is Radar answering "nothing is wrong". Gateway API routes were judged on Accepted alone. A gateway accepting a route says nothing about whether the backends it forwards to exist, so a route whose backendRef named a Service that was gone reported healthy — the failure an operator opens the graph to find. Route health now reads ResolvedRefs alongside Accepted, and ignores conditions a controller observed against an earlier generation. HorizontalPodAutoscalers were hardcoded healthy while the builder read their replica counts three lines below. pkg/hpadiag already diagnoses them for the drawer, so the node now uses it. An HPA that cannot reach its metrics reports unhealthy instead of green. The mapping only ever downgrades on negative evidence: routine scaling stays healthy, because degraded nodes become reported problems and normal autoscaling is not one. Four Secret nodes are stubs synthesised from a reference — a TLS or CA name mentioned by a Traefik or HTTPProxy resource that the Secret listing never produced. They were built green, so a misspelled certificate reference rendered as a healthy Secret. They report unknown: nothing confirmed the Secret exists.
dab49fa to
edf6a40
Compare

A topology node's status is not just a dot in the graph. MCP builds its
get_topologyproblem list from degraded and unhealthy nodes (internal/mcp/tools.go:1645), and GitOps derives managed-resource health from it (pkg/gitops/tree/graph.go:21). A green node is Radar answering "nothing is wrong" — to an operator scanning the graph, and to an AI asked whether the cluster is healthy.Three places were answering that without checking. This continues #1645/#1649/#1659, which fixed the TypeScript accessors;
pkg/topologycomputes health independently in Go and had drifted from them.What changed
Gateway API routes were judged on
Acceptedalone. A gateway accepting a route says nothing about whether the backends it forwards to exist — so an HTTPRoute whosebackendRefnamed a deleted Service reported healthy. That is precisely the failure an operator opens the graph to find, and it is the same defect #1645 fixed on the TS side.getRouteHealthnow readsResolvedRefsalongsideAccepted.A route reads healthy only when every parent reports both
Accepted=TrueandResolvedRefs=True. A parent that reports nothing — no conditions, or only ones observed against an earliergeneration— is counted as unassessed and blocks both the healthy and the unhealthy verdict, so neither a green node nor a total failure is claimed while a gateway is still silent.Two deliberate differences from the TS accessor, since this is otherwise meant to match it: the
observedGenerationstaleness check is an addition (speaksToCurrentSpecinresource-utils.ts:1953only tests whether the relevant conditions exist), and a route whose parents all report nothing readsunknownhere where TS readsPending/degraded — claiming a fault we have not established seemed the wrong direction for this change. Both are candidates for reconciling in TS rather than divergences to keep.HorizontalPodAutoscalers were hardcoded healthy while the builder read
hpa.Status.CurrentReplicasthree lines below.pkg/hpadiagalready diagnoses HPAs for the detail drawer, so the node now uses it and the graph stops disagreeing with the drawer.An autoscaler the controller has not written a condition for reads unknown rather than healthy:
hpadiag.Analyzereportsokfor a conditionless HPA, so absence of evidence would otherwise arrive as health. States the vocabulary calls intentionally idle — scaled to zero, disabled, pinned, stabilised, at minimum — map to neutral, matching the shipped TS mapping.Otherwise the mapping only ever downgrades on negative evidence — unreachable metrics and inability to scale become unhealthy, capped/incomplete metrics degraded, everything else stays healthy. Notably
scaling_up/scaling_downremain healthy: an HPA doing its job is not a problem, and since degraded nodes become MCP-reported problems, promoting routine autoscaling would manufacture false ones. This differs fromhpaStateLevelinresource-utils-hpa.ts:68, which calls both scaling directions degraded — worth reconciling, but in both places deliberately rather than by divergence here.Four Secret nodes are stubs synthesised from a reference — a TLS or CA secret named by a Traefik or HTTPProxy resource that the Secret listing never produced, either because it does not exist or because it was not listable. They were built green, so a misspelled
certificateRefrendered as a healthy Secret. They now report unknown.Verification
The HPA fix is verified end to end against a real controller failure rather than a hand-written fixture: a
kindcluster has no metrics-server, so an HPA there genuinely getsScalingActive=False / FailedGetResourceMetricfrom the HPA controller. With that in the cluster, the topology API returnsstatus: "unhealthy"for the node, andget_topologyover MCP returns the same — where both previously said healthy.Route health is pinned by table-driven tests covering unresolved backendRefs, full acceptance, partial and total rejection, absent reports, a stale
observedGeneration, and the mixed cases where one parent is current and healthy while another is stale or silent. I confirmed these actually fail against the previous algorithm rather than passing either way: for a route withAccepted=True, ResolvedRefs=Falsethe old code returnshealthyand the new code returnsdegraded.go buildandgo test ./...clean in both the root andpkgmodules.Scope
Deliberately narrow. A survey found 22 hardcoded
Status: StatusHealthynode constructions, but most are not defects worth changing:StatusNeutralmeans intentionally idle and paints a sky-blue outline (K8sResourceNode.tsx:275), so it would add emphasis to the least interesting nodes rather than remove a claim. That needs a deliberate "health not applicable" presentation instead.loadBalancerand Service endpoints would be new health signals rather than removing a false one. Given that a wrong status propagates into MCP problems and GitOps degraded counts, a false alarm costs more than a missing one here, and Service semantics already live ininternal/k8s/detect.go:1151.Known and not addressed:
TraefikServiceis marked unhealthy on zero backends in the resources view (builder.go:2274) but always healthy in the traffic view (:6472); Cilium and ClusterNetworkPolicy expose conditions the builder ignores; VPA conditions are readable andConfigUnsupportedcurrently renders green; and the generic condition helper (builder.go:7951) returns on the first Ready/Available/Succeeded it sees.🤖 Generated with Claude Code
Note
Medium Risk
Changes how topology health is computed for routes, HPAs, and secrets, which can alter MCP-reported problems and GitOps degraded counts; logic is conservative but user-visible status may shift.
Overview
Topology nodes were marking healthy without checking real status, which flows into MCP problem lists and GitOps health. This PR tightens three cases in
pkg/topology/builder.go.Gateway API routes —
getRouteHealthno longer treatsAccepted=Trueas fully healthy. It also requires currentResolvedRefs(and ignores conditions on staleobservedGeneration), counts silent parents as unassessed, and only returns healthy when every reporting parent accepts and resolves refs.HPAs — HPA graph nodes call new
hpaNodeHealth, which mapshpadiag.Analyzeresults into graph status (unhealthy/degraded for scale/metrics failures, neutral for intentional idle states, unknown when unreconciled). Routine scaling stays non-problematic so MCP does not get false alarms.Referenced Secret stubs (Traefik/Contour TLS/CA refs not in the Secret list) switch from healthy to unknown so missing secrets are not shown as OK.
Adds
node_health_test.gotable tests for route and HPA health behavior.Reviewed by Cursor Bugbot for commit edf6a40. Bugbot is set up for automated code reviews on this repo. Configure here.