Repository navigation
Open the exact object behind EndpointSlice, Knative and Crossplane reference links - #1996
Conversation
PR Summary by QodoPreserve EndpointSlice target identity and link endpoint Nodes
AI Description
Diagram
High-Level Assessment
Files changed (4)
|
Code Review by Qodoð Bugs (0) ð Rule violations (0) ð Requirement gaps (0)
Great, no issues found!Qodo reviewed your code and found no material issues that require reviewTip of the dayðĄ Did you know, you can turn these tips off under Display > Comment parts |
âĶry (#1997) The Service drawer now lists the EndpointSlices that publish the Service's endpoints, for every Service except ExternalName ones. On `main` it lists them only for Services **without** a selector, which hides them in the case where they explain the most: a Service whose selector matches no Pods, or whose endpoints aren't ready. ## How it works EndpointSlices aren't held in Radar's informer cache, so every read is a direct API call. On `main`, each open drawer for a selector-less Service polls a LIST of every EndpointSlice in the namespace every 30 seconds and filters in the browser. That cost grows with the namespace, not the Service. This PR asks the server for exactly one Service's slices: - `GET /api/services/{namespace}/{name}/endpointslices` returns `{items, truncated}`. - It's one LIST selected by the `kubernetes.io/service-name=<name>` label. kube-proxy and the EndpointSlice controller use the same label, so it's the contract for "this slice serves this Service". - Capped at 500 slices. When more exist, `truncated` is set and the drawer says so. - The selector is validated, so a name like `web,app=x` returns 400. - **Access matches the existing list route.** It is gated like `GET /api/resources/endpointslices?namespace=<ns>`: the same namespace clamp, `--namespace-scope`, and per-user RBAC intersection. A namespace the user can't read returns 403, not an empty list, so the drawer never says "no EndpointSlices" to someone who simply can't see them. - **Association is by label only.** A slice owned by the Service but labelled for another Service is listed under the Service its label names, because that's where kube-proxy sends its traffic. - **Older Radars.** A new `serviceEndpointSlices` capability flag gates the hook (`radarFeatures.ts`). Against a Radar without the endpoint (Radar Hub with an older cluster), the drawer keeps `main`'s behaviour. - `pkg/k8score` gains `ListDirectSelected` (additive). `ListDirect` is unchanged. - The EndpointSlice drawer's Service link carries the core API group explicitly. ## Result on a live cluster   | Service | `main` | this PR | |---|---|---| | `kube-system/kube-dns` (selector) | no section | 1 slice, 2/2 ready | | selector matching no Pods | no section | both labelled slices | | no selector, 2 slices | 2 slices | same 2 slices | | no slices at all | "No EndpointSlices found" | same | Direct API checks: an unknown Service returns `[]`, and an injected selector returns 400. ## Testing - Handler tests cover: - label selection, namespace and limit, checked on the actual LIST call; - truncation, and an empty result as `[]`; - a selector-injection name returning 400; - in auth mode, a namespace outside the user's access returning 403. - `k8score` tests cover the selector, limit, continue token and field stripping. - Renderer tests cover selector and selector-less Services; the loading, error, empty and truncated states; ExternalName; and the older-Radar fallback. - `make tsc`, `go test ./internal/server/... ./internal/k8s/...`, `pkg/k8score`, and the shared UI and web suites pass. - Live: the comparisons above, on a kind cluster. ## Notes This and #1996 both add `EndpointSliceRenderer.test.tsx`. Whichever merges second needs a one-file rebase. ðĪ Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Keep resource navigation faithful to the declared API identity so colliding Kinds cannot route operators to a different object.
The EndpointSlice controller writes Pod targets without apiVersion, so the strict identity rule turned every controller-managed target link into plain text. An omitted apiVersion now means the core group only for a built-in core Kind; custom kinds without apiVersion still stay unlinked. Tests are rewritten in the renderer-test style.
Kind-only navigation used whichever API group discovery listed last, so a CRD that declares Kind Node under another plural could take over core Node and Pod links. Core resources now keep their plural for kind-only lookups, matching the existing first-wins rule for plurals. Collisions between CRDs keep the previous behavior.
The server forwards partial discovery, so core protection seeded only from discovered entries vanished when the core group was missing. Seed it from the built-in core table first.
A CRD may register a core Kind's lowercase word (node) as its own plural, which the already-plural shortcut accepted for core Node links. An exact PascalCase core Kind now resolves to its built-in plural first; lowercase plural slugs and non-core special cases such as PodGroup keep their behavior.
Keep resource navigation faithful to the declared API identity so colliding Kinds cannot route operators to a different object.
âĶdpoints targets Core Kinds now keep their core plural in group-blind lookups, so Crossplane references, which can reuse any core Kind, pluralize within their own group. An Endpoints target without apiVersion is core, like Pod and Node.
âĶt apiVersion Knative sinks, subscribers, replies and channels link within their reference's API group, so a Knative Service sink no longer opens the core Service. An ObjectReference without apiVersion is core only for an exact core Kind; a resource name such as Services is not one.
A DomainMapping to a Knative Service no longer opens the core Service.
Knative references can identify a group without a version. Resolve those references through the shared exact-reference component, leaving incomplete identities as text instead of routing to a core object. Endpoint labels use the normalized target scope so they describe the object their link opens.
b0da042 to
9373bf5
Compare
|
/review |
|
Code review by qodo was updated up to the latest commit 9373bf5 |
âĶes (#2009) An HPA can scale a Deployment using an Object metric from an Ingress, but Radar's metric card currently gives no route to that source. KEDA ScaledObjects targeting StatefulSets also lose their topology edge because targets are resolved before StatefulSet nodes exist. ## Design - Show each HPA Object source inside its existing metric card, separately from the workload being scaled. Carry the source's API group, selector and scope, and pair observations by structured metric identity. - Preserve declared target API identity for HPA, VPA and KEDA links using the shared reference converter. VPA keeps one Target link and ordinary versionless built-in navigation. - Apply KEDA's documented apps/v1 Deployment defaults consistently in the UI, topology, missing-reference detection and compact context. Resolve target edges after supported workload nodes exist, retaining uses edges and scaleTarget/scaledBy projections. No endpoint, read privilege or custom scale-subresource graph support is added. Merge after #1996, which supplies exact-reference navigation. ## Testing TypeScript, the complete Go pkg suite, both focused topology regressions and all 19 autoscaler renderer tests pass. Component regressions exercise an Ingress Object source, exact declared groups and versionless VPA links; builder regressions exercise KEDA StatefulSet edges and both relationship projections. The documented KEDA setup fails against main and passes with this change in a synthetic builder experiment. Merge verification remains blocked: full frontend runs reported failures in unchanged tests under severe host contention, including the known kind-view flake, which also failed in isolation. Root Go build/internal tests, full application build and lint did not complete; rerun those checks before merging. Assertions and timeouts were not weakened. The supplied clusters have ten Resource CPU HPAs and no KEDA or VPA CRDs. Historical live HPA fixtures validated API admission and source navigation. No custom-metrics adapter or KEDA controller reconciled them; source links do not establish working metrics or successful scaling.  
EndpointSlice, Knative and Crossplane references can name a custom resource whose Kind collides with a core resource. Preserve the declared API group and discovered scope so clicking a reference opens the intended object rather than a same-named object in another API.
Changes
Validation
Go build, pkg and internal tests, TypeScript checks and the complete shared UI suite pass (4,534 tests, one existing skip). Full frontend/embed/backend build passes. Web tests passed except one existing timer under concurrent load; all seven tests in that file passed on an isolated rerun.
Compared main and this change against the EKS nonprod and management test clusters using owned fixtures, REST, read-only MCP calls and headless Chromium. EndpointSlice and Knative links open the custom object rather than the core decoy. Crossplane custom Node status uses its discovered workerhosts plural and succeeds; its custom Endpoints alias already resolves on main and remains correct. Controller-shaped Pod and core Node clicks remain functional. Browser runs recorded no page errors.
The Knative fixture was not Ready, and Crossplane fixtures were manually created composite/managed-resource shapes; the evidence establishes identity and navigation, not successful controller reconciliation. Group-only Knative references are component-tested because the installed PingSource schema rejects that experimental field.
Notes
#2009 builds on this reference converter. The overlapping #2047 should follow this stack and retain these shared Knative helpers, collision protections and tests alongside its additional brokerRef changes. No endpoint or authorization behavior changes.