Skip to content

Commit c03f3c5

Browse files
puertomonttnfuden
andauthored
initial TLSRoute support (#10601)
Co-authored-by: Nathan Fudenberg <[email protected]> Co-authored-by: changelog-bot <changelog-bot>
1 parent 9c6688e commit c03f3c5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1939
-85
lines changed

.github/workflows/pr-kubernetes-tests.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ jobs:
9595
# 2025-02-13: 26m29s
9696
- cluster-name: 'cluster-seven'
9797
go-test-args: '-v -timeout=25m'
98-
go-test-run-regex: '^TestK8sGateway$$/^CRDCategories$$|^TestK8sGateway$$/^Metrics$$|^TestGloomtlsGatewayEdgeGateway$$|^TestGloomtlsGatewayK8sGateway$$|^TestGlooGatewayEdgeGatewayClearMetrics$$|^TestWatchNamespaceSelector$$'
98+
go-test-run-regex: '^TestK8sGateway$$/^CRDCategories$$|^TestK8sGateway$$/^Metrics$$|^TestGloomtlsGatewayEdgeGateway$$|^TestGloomtlsGatewayK8sGateway$$|^TestGlooGatewayEdgeGatewayClearMetrics$$|^TestWatchNamespaceSelector$$|^TestK8sGateway$$/^TLSRouteServices$$'
9999

100100
# In our PR tests, we run the suite of tests using the upper ends of versions that we claim to support
101101
# The versions should mirror: https://docs.solo.io/gloo-edge/latest/reference/support/

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,7 @@ $(TEST_ASSET_DIR)/conformance/conformance_test.go:
12431243
cat $(shell go list -json -m sigs.k8s.io/gateway-api | jq -r '.Dir')/conformance/conformance_test.go >> $@
12441244
go fmt $@
12451245

1246-
CONFORMANCE_SUPPORTED_FEATURES ?= -supported-features=Gateway,ReferenceGrant,HTTPRoute,HTTPRouteQueryParamMatching,HTTPRouteMethodMatching,HTTPRouteResponseHeaderModification,HTTPRoutePortRedirect,HTTPRouteHostRewrite,HTTPRouteSchemeRedirect,HTTPRoutePathRedirect,HTTPRouteHostRewrite,HTTPRoutePathRewrite,HTTPRouteRequestMirror
1246+
CONFORMANCE_SUPPORTED_FEATURES ?= -supported-features=Gateway,ReferenceGrant,HTTPRoute,HTTPRouteQueryParamMatching,HTTPRouteMethodMatching,HTTPRouteResponseHeaderModification,HTTPRoutePortRedirect,HTTPRouteHostRewrite,HTTPRouteSchemeRedirect,HTTPRoutePathRedirect,HTTPRouteHostRewrite,HTTPRoutePathRewrite,HTTPRouteRequestMirror,TLSRoute
12471247
CONFORMANCE_SUPPORTED_PROFILES ?= -conformance-profiles=GATEWAY-HTTP
12481248
CONFORMANCE_REPORT_ARGS ?= -report-output=$(TEST_ASSET_DIR)/conformance/$(VERSION)-report.yaml -organization=solo.io -project=gloo-gateway -version=$(VERSION) -url=github.com/solo-io/gloo -contact=github.com/solo-io/gloo/issues/new/choose
12491249
CONFORMANCE_ARGS := -gateway-class=gloo-gateway $(CONFORMANCE_SUPPORTED_FEATURES) $(CONFORMANCE_SUPPORTED_PROFILES) $(CONFORMANCE_REPORT_ARGS)
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
changelog:
2+
- type: NEW_FEATURE
3+
issueLink: https://github.com/kgateway-dev/kgateway/issues/10074
4+
resolvesIssue: false
5+
description: >-
6+
"Add support for sig gateway's TLS Routes."

install/helm/gloo/templates/44-rbac.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rules:
1313
- gatewayclasses
1414
- gateways
1515
- tcproutes
16+
- tlsroutes
1617
- httproutes
1718
- referencegrants
1819
verbs: ["get", "list", "watch"]
@@ -50,6 +51,7 @@ rules:
5051
- gateways/status
5152
- httproutes/status
5253
- tcproutes/status
54+
- tlsroutes/status
5355
verbs: ["update", "patch"]
5456
- apiGroups:
5557
- apiextensions.k8s.io

projects/gateway2/controller/controller.go

+31
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func NewBaseGatewayController(ctx context.Context, cfg GatewayConfig) error {
8080
controllerBuilder.watchGw,
8181
controllerBuilder.watchHttpRoute,
8282
controllerBuilder.watchTcpRoute,
83+
controllerBuilder.watchTlsRoute,
8384
controllerBuilder.watchReferenceGrant,
8485
controllerBuilder.watchNamespaces,
8586
controllerBuilder.watchHttpListenerOptions,
@@ -140,6 +141,12 @@ func (c *controllerBuilder) addIndexes(ctx context.Context) error {
140141
}
141142
}
142143

144+
if c.cfg.CRDs.Has(wellknown.TLSRouteCRDName) {
145+
if err := c.cfg.Mgr.GetFieldIndexer().IndexField(ctx, &apiv1a2.TLSRoute{}, query.TlsRouteTargetField, query.IndexerByObjType); err != nil {
146+
errs = append(errs, err)
147+
}
148+
}
149+
143150
return errors.Join(errs...)
144151
}
145152

@@ -361,6 +368,19 @@ func (c *controllerBuilder) watchTcpRoute(ctx context.Context) error {
361368
Complete(reconcile.Func(c.reconciler.ReconcileTcpRoutes))
362369
}
363370

371+
func (c *controllerBuilder) watchTlsRoute(ctx context.Context) error {
372+
if !c.cfg.CRDs.Has(wellknown.TLSRouteCRDName) {
373+
log.FromContext(ctx).Info("TLSRoute type not registered in scheme; skipping TLSRoute controller setup")
374+
return nil
375+
}
376+
377+
// Proceed to set up the controller for TLSRoute
378+
return ctrl.NewControllerManagedBy(c.cfg.Mgr).
379+
WithEventFilter(predicate.GenerationChangedPredicate{}).
380+
For(&apiv1a2.TLSRoute{}).
381+
Complete(reconcile.Func(c.reconciler.ReconcileTlsRoutes))
382+
}
383+
364384
func (c *controllerBuilder) watchReferenceGrant(_ context.Context) error {
365385
return ctrl.NewControllerManagedBy(c.cfg.Mgr).
366386
WithEventFilter(predicate.GenerationChangedPredicate{}).
@@ -551,6 +571,17 @@ func (r *controllerReconciler) ReconcileTcpRoutes(ctx context.Context, req ctrl.
551571
return ctrl.Result{}, nil
552572
}
553573

574+
func (r *controllerReconciler) ReconcileTlsRoutes(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
575+
// TODO: consider finding impacted gateways and queue them
576+
// TODO: consider enabling this
577+
// // reconcile this specific route:
578+
// queries := query.NewData(r.cli, r.scheme)
579+
// httproute.TranslateGatewayHTTPRouteRules(queries, hr, nil)
580+
581+
r.kick(ctx)
582+
return ctrl.Result{}, nil
583+
}
584+
554585
func (r *controllerReconciler) ReconcileReferenceGrants(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
555586
// reconcile all things?! https://github.com/solo-io/gloo/issues/9997
556587
r.kick(ctx)

projects/gateway2/controller/start.go

+9
Original file line numberDiff line numberDiff line change
@@ -290,5 +290,14 @@ func getGatewayCRDs(restConfig *rest.Config) (sets.Set[string], error) {
290290
crds.Insert(wellknown.TCPRouteCRDName)
291291
}
292292

293+
tlsRouteExists, err := glooschemes.CRDExists(restConfig, gwv1a2.GroupVersion.Group, gwv1a2.GroupVersion.Version, wellknown.TLSRouteKind)
294+
if err != nil {
295+
return nil, err
296+
}
297+
298+
if tlsRouteExists {
299+
crds.Insert(wellknown.TLSRouteCRDName)
300+
}
301+
293302
return crds, nil
294303
}

projects/gateway2/proxy_syncer/proxy_syncer.go

+35
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ func (p glooProxy) Equals(in glooProxy) bool {
247247
if !maps.Equal(p.reportMap.TCPRoutes, in.reportMap.TCPRoutes) {
248248
return false
249249
}
250+
if !maps.Equal(p.reportMap.TLSRoutes, in.reportMap.TLSRoutes) {
251+
return false
252+
}
250253
return true
251254
}
252255

@@ -273,6 +276,9 @@ func (r report) Equals(in report) bool {
273276
if !maps.Equal(r.ReportMap.TCPRoutes, in.ReportMap.TCPRoutes) {
274277
return false
275278
}
279+
if !maps.Equal(r.ReportMap.TLSRoutes, in.ReportMap.TLSRoutes) {
280+
return false
281+
}
276282
return true
277283
}
278284

@@ -491,6 +497,19 @@ func (s *ProxySyncer) Init(ctx context.Context, dbg *krt.DebugHandler) error {
491497
// obsGen will stay as-is...
492498
maps.Copy(p.reportMap.TCPRoutes[rnn].Parents, rr.Parents)
493499
}
500+
501+
// 4. merge tlsroute parentRefs into RouteReports
502+
for rnn, rr := range p.reportMap.TLSRoutes {
503+
// if we haven't encountered this route, just copy it over completely
504+
old := merged.TLSRoutes[rnn]
505+
if old == nil {
506+
merged.TLSRoutes[rnn] = rr
507+
continue
508+
}
509+
// else, let's merge our parentRefs into the existing map
510+
// obsGen will stay as-is...
511+
maps.Copy(p.reportMap.TLSRoutes[rnn].Parents, rr.Parents)
512+
}
494513
}
495514
return &report{merged}
496515
})
@@ -902,6 +921,12 @@ func (s *ProxySyncer) syncRouteStatus(ctx context.Context, rm reports.ReportMap)
902921
return nil
903922
}
904923
r.Status.RouteStatus = *status
924+
case *gwv1a2.TLSRoute:
925+
status = rm.BuildRouteStatus(ctx, r, s.controllerName)
926+
if status == nil || isRouteStatusEqual(&r.Status.RouteStatus, status) {
927+
return nil
928+
}
929+
r.Status.RouteStatus = *status
905930
default:
906931
logger.Warnw(fmt.Sprintf("unsupported route type for %s", routeType), "route", route)
907932
return nil
@@ -930,6 +955,16 @@ func (s *ProxySyncer) syncRouteStatus(ctx context.Context, rm reports.ReportMap)
930955
logger.Errorw("all attempts failed at updating TCPRoute status", "error", err, "route", rnn)
931956
}
932957
}
958+
959+
// Sync TLSRoute statuses
960+
for rnn := range rm.TLSRoutes {
961+
err := syncStatusWithRetry(wellknown.TLSRouteKind, rnn, func() client.Object { return new(gwv1a2.TLSRoute) }, func(route client.Object) error {
962+
return buildAndUpdateStatus(route, wellknown.TLSRouteKind)
963+
})
964+
if err != nil {
965+
logger.Errorw("all attempts failed at updating TLSRoute status", "error", err, "route", rnn)
966+
}
967+
}
933968
}
934969

935970
// syncGatewayStatus will build and update status for all Gateways in a reportMap

projects/gateway2/query/httproute.go

+43-3
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ func (r *gatewayQueries) GetRouteChain(
128128
case *gwv1a2.TCPRoute:
129129
backends = r.resolveRouteBackends(ctx, typedRoute)
130130
// TODO (danehans): Should TCPRoute delegation support be added in the future?
131+
case *gwv1a2.TLSRoute:
132+
backends = r.resolveRouteBackends(ctx, typedRoute)
131133
default:
132134
return nil
133135
}
@@ -151,7 +153,7 @@ func (r *gatewayQueries) allowedRoutes(gw *gwv1.Gateway, l *gwv1.Listener) (func
151153
case gwv1.HTTPProtocolType:
152154
allowedKinds = []metav1.GroupKind{{Kind: wellknown.HTTPRouteKind, Group: gwv1.GroupName}}
153155
case gwv1.TLSProtocolType:
154-
fallthrough
156+
allowedKinds = []metav1.GroupKind{{Kind: wellknown.TLSRouteKind, Group: gwv1a2.GroupName}}
155157
case gwv1.TCPProtocolType:
156158
allowedKinds = []metav1.GroupKind{{Kind: wellknown.TCPRouteKind, Group: gwv1a2.GroupName}}
157159
case gwv1.UDPProtocolType:
@@ -228,6 +230,14 @@ func (r *gatewayQueries) resolveRouteBackends(ctx context.Context, obj client.Ob
228230
}
229231
processBackendRefs(refs)
230232
}
233+
case *gwv1a2.TLSRoute:
234+
for _, rule := range rt.Spec.Rules {
235+
var refs []gwv1.BackendObjectReference
236+
for _, ref := range rule.BackendRefs {
237+
refs = append(refs, ref.BackendObjectReference)
238+
}
239+
processBackendRefs(refs)
240+
}
231241
default:
232242
return out
233243
}
@@ -365,6 +375,16 @@ func (r *gatewayQueries) GetRoutesForGateway(ctx context.Context, gw *gwv1.Gatew
365375
routeListTypes = append(routeListTypes, &gwv1a2.TCPRouteList{})
366376
}
367377

378+
// Conditionally include TLSRouteList
379+
tlsRouteGVK := schema.GroupVersionKind{
380+
Group: gwv1a2.GroupVersion.Group,
381+
Version: gwv1a2.GroupVersion.Version,
382+
Kind: wellknown.TLSRouteKind,
383+
}
384+
if r.scheme.Recognizes(tlsRouteGVK) {
385+
routeListTypes = append(routeListTypes, &gwv1a2.TLSRouteList{})
386+
}
387+
368388
var routes []client.Object
369389
for _, routeList := range routeListTypes {
370390
if err := fetchRoutes(ctx, r, routeList, nns, &routes); err != nil {
@@ -406,6 +426,10 @@ func fetchRoutes(ctx context.Context, r *gatewayQueries, routeList client.Object
406426
if err := listAndAppendRoutes(list, TcpRouteTargetField); err != nil {
407427
return fmt.Errorf("failed to list TCPRoutes: %w", err)
408428
}
429+
case *gwv1a2.TLSRouteList:
430+
if err := listAndAppendRoutes(list, TlsRouteTargetField); err != nil {
431+
return fmt.Errorf("failed to list TLSRoutes: %w", err)
432+
}
409433
default:
410434
return fmt.Errorf("unsupported route list type: %T", list)
411435
}
@@ -452,12 +476,22 @@ func (r *gatewayQueries) processRoute(ctx context.Context, gw *gwv1.Gateway, rou
452476
}
453477
anyListenerMatched = true
454478

455-
// If the route is an HTTPRoute, check the hostname intersection
479+
// If the route is an HTTPRoute or TLSRoute, check the hostname intersection
456480
var hostnames []string
457481
if routeKind == wellknown.HTTPRouteKind {
458482
if hr, ok := route.(*gwv1.HTTPRoute); ok {
459483
var ok bool
460-
ok, hostnames = hostnameIntersect(&l, hr)
484+
ok, hostnames = hostnameIntersect(&l, hr.Spec.Hostnames)
485+
if !ok {
486+
continue
487+
}
488+
anyHostsMatch = true
489+
}
490+
}
491+
if routeKind == wellknown.TLSRouteKind {
492+
if tr, ok := route.(*gwv1a2.TLSRoute); ok {
493+
var ok bool
494+
ok, hostnames = hostnameIntersect(&l, tr.Spec.Hostnames)
461495
if !ok {
462496
continue
463497
}
@@ -532,6 +566,12 @@ func getRouteItems(list client.ObjectList) ([]client.Object, error) {
532566
objs = append(objs, &routes.Items[i])
533567
}
534568
return objs, nil
569+
case *gwv1a2.TLSRouteList:
570+
var objs []client.Object
571+
for i := range routes.Items {
572+
objs = append(objs, &routes.Items[i])
573+
}
574+
return objs, nil
535575
default:
536576
return nil, fmt.Errorf("unsupported route type %T", list)
537577
}

projects/gateway2/query/indexers.go

+21
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const (
1616
HttpRouteTargetField = "http-route-target"
1717
HttpRouteDelegatedLabelSelector = "http-route-delegated-label-selector"
1818
TcpRouteTargetField = "tcp-route-target"
19+
TlsRouteTargetField = "tls-route-target"
1920
ReferenceGrantFromField = "ref-grant-from"
2021
)
2122

@@ -25,6 +26,7 @@ func IterateIndices(f func(client.Object, string, client.IndexerFunc) error) err
2526
f(&gwv1.HTTPRoute{}, HttpRouteTargetField, IndexerByObjType),
2627
f(&gwv1.HTTPRoute{}, HttpRouteDelegatedLabelSelector, IndexByHTTPRouteDelegationLabelSelector),
2728
f(&gwv1a2.TCPRoute{}, TcpRouteTargetField, IndexerByObjType),
29+
f(&gwv1a2.TLSRoute{}, TlsRouteTargetField, IndexerByObjType),
2830
f(&gwv1b1.ReferenceGrant{}, ReferenceGrantFromField, IndexerByObjType),
2931
)
3032
}
@@ -33,6 +35,7 @@ func IterateIndices(f func(client.Object, string, client.IndexerFunc) error) err
3335
//
3436
// - HTTPRoute
3537
// - TCPRoute
38+
// - TLSRoute
3639
// - ReferenceGrant
3740
func IndexerByObjType(obj client.Object) []string {
3841
var results []string
@@ -74,6 +77,24 @@ func IndexerByObjType(obj client.Object) []string {
7477
}
7578
results = append(results, nns.String())
7679
}
80+
case *gwv1a2.TLSRoute:
81+
for _, pRef := range resource.Spec.ParentRefs {
82+
if pRef.Group != nil && *pRef.Group != gwv1a2.GroupName {
83+
continue
84+
}
85+
if pRef.Kind != nil && *pRef.Kind != wellknown.GatewayKind {
86+
continue
87+
}
88+
ns := resolveNs(pRef.Namespace)
89+
if ns == "" {
90+
ns = resource.Namespace
91+
}
92+
nns := types.NamespacedName{
93+
Namespace: ns,
94+
Name: string(pRef.Name),
95+
}
96+
results = append(results, nns.String())
97+
}
7798
case *gwv1b1.ReferenceGrant:
7899
for _, from := range resource.Spec.From {
79100
if from.Namespace != "" {

0 commit comments

Comments
 (0)