feat(api): per-route port overrides on NebariApp routes#121
Draft
viniciusdc wants to merge 1 commit into
Draft
Conversation
7a5ea5b to
71aad60
Compare
de42a7c to
158caae
Compare
71aad60 to
78e47b6
Compare
158caae to
fa905de
Compare
78e47b6 to
bdc887b
Compare
fa905de to
44a9e50
Compare
5 tasks
7e1cc69 to
2d096ea
Compare
Adds an optional Port field on RouteMatch so a single NebariApp can route different path prefixes to different ports on the same backend Service under one hostname. Routes without a per-route Port continue to forward to spec.service.port, so all existing NebariApp manifests behave identically. A NebariApp still targets exactly one Service. Per-route backend Services are intentionally not supported — packs that need to fan out to multiple Services should split into multiple NebariApps. Tightens the same-namespace contract by removing ServiceReference.Namespace. The field was a half-feature: the operator emitted a cross-namespace BackendObjectReference on the HTTPRoute, but never created the Gateway API ReferenceGrant the gateway needs in the target namespace, so traffic would silently fail. The new contract is "the backend Service lives in the NebariApp's own namespace"; workloads that need cross-namespace communication should use in-cluster DNS rather than the public HTTPRoute. Reconciler changes: - buildHTTPRouteRules now emits one HTTPRouteRule per RouteMatch when routes are configured, each with its own resolved port (the route's Port override if set, else spec.service.port). The "no routes" case still emits a single rule with empty matches so Gateway API's "/" default applies (unchanged behavior). - buildPublicHTTPRoute applies the same shape so per-route ports also work on routing.publicRoutes[]. - ValidateService looks up spec.service once and confirms every effective port (spec.service.port plus each route override) is exposed by the Service. Design rationale: docs/design/multi-backend-routes.md. This PR implements only the multi-port + namespace-removal portions of the design; the streaming/BackendTrafficPolicy portion is a follow-up.
44a9e50 to
9f35cf6
Compare
This was referenced May 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the multi-port + namespace-removal portions of the design in #120 (stacked on top of that PR — base will switch to
mainonce #120 merges). The streaming/BackendTrafficPolicyportion of #120 is not in this PR — open question on whether to extend this PR or land separately, see #120's PR body.RouteMatch.Port(*int32) so a single NebariApp can route different path prefixes to different ports on the same backend Service under one hostname.ServiceReference.Namespace. Was a half-feature: the operator rendered cross-namespaceBackendObjectReferencebut never created the Gateway APIReferenceGrantthe gateway needs, so traffic silently failed. New contract: the backend Service lives in the NebariApp's own namespace. nebari-landing depends on this field but has graceful fallback; see docs(design): multi-port routes and streaming for NebariApp #120's Downstream consumer section.HTTPRouteRuleperRouteMatch(with that route's resolved port) instead of one rule with N matches sharing a single port. The "no routes" case still emits a single rule with empty matches, so the Gateway-API "/" default still applies.routing.routes[]androuting.publicRoutes[]support per-route ports.ValidateServicelooks upspec.serviceonce and confirms every effective port (default + each route override) is exposed by it. A route Port that the Service doesn't expose surfaces as a clear error.What this PR does NOT include
routing.streamingfield onRoutingConfig.BackendTrafficPolicyreconciler / newstreaming.go.gateway.envoyproxy.io/backendtrafficpolicies.The design for those is in #120. Whether they land here or as a stacked third PR is the open question called out at the bottom of #120's body.
Iteration history
An earlier iteration exposed per-route
backend: {name, port}overrides for multi-Service fan-out; narrowed after design feedback to ports-only on a single Service. Both PRs have been force-pushed in place (draft, no review activity).Files touched
api/v1/nebariapp_types.go—ServiceReferenceslim-down,RouteMatch.Port, updated docstrings (hostname / single-Service constraints codified).internal/controller/reconcilers/routing/httproute.go—buildHTTPRouteRules,buildPublicHTTPRoute, newrouteToMatch/resolveRoutePorthelpers, slimmedbuildBackendRefs(name, port).internal/controller/reconcilers/core/reconciler.go—ValidateServicenow multi-port aware against a single Service lookup.TestBuildBackendRefsrewritten for the new(string, int32)signature; same-namespace invariant asserted.TestBuildHTTPRouteRules_PerRoutePortandTestBuildHTTPRouteRules_NoRoutescover the new behavior.TestBuildHTTPRoute/TestBuildHTTPRouteRules/TestBuildPublicHTTPRouteupdated for one-rule-per-route shape.config/crd/bases/reconcilers.nebari.dev_nebariapps.yaml,docs/api-reference.md,zz_generated.deepcopy.go.Backwards compatibility
spec.service.namespaceare unaffected.nebari-devpacks deploy via Argo CD into a single per-pack namespace; the only historical users — Keycloak/ArgoCD NebariApps in the kind dev cluster — have moved to NIC's foundational Argo-apps layer).v1; field removal is permitted under the current README contract that flagsv1as unstable during NIC bring-up.Test plan
go build ./...passesgo vet ./...cleanmake lint(golangci-lint) — 0 issuesapi/,internal/controller/reconcilers/{routing,core,tls,auth}— all greenmake generate-devregenerates CRD and deepcopy cleanlymake docsregeneratesapi-reference.mdcleanlyTestControllers(envtest-based) — pre-existing failure onmainforshould successfully reconcile the resource. Reproduces onmainwith no code changes. Not introduced here.Related