Skip to content

Commit cfd0ee8

Browse files
author
Kate Osborn
committed
Support cross-namespace routing with TLSRoutes
1 parent a10076e commit cfd0ee8

9 files changed

+649
-136
lines changed

internal/mode/static/state/change_processor_test.go

+429-73
Large diffs are not rendered by default.

internal/mode/static/state/graph/graph.go

+1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ func BuildGraph(
228228
processedGws.GetAllNsNames(),
229229
state.Services,
230230
npCfg,
231+
refGrantResolver,
231232
)
232233

233234
bindRoutesToListeners(routes, l4routes, gw, state.Namespaces)

internal/mode/static/state/graph/reference_grant.go

+8
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ func fromGRPCRoute(namespace string) fromResource {
8181
}
8282
}
8383

84+
func fromTLSRoute(namespace string) fromResource {
85+
return fromResource{
86+
group: v1.GroupName,
87+
kind: kinds.TLSRoute,
88+
namespace: namespace,
89+
}
90+
}
91+
8492
// newReferenceGrantResolver creates a new referenceGrantResolver.
8593
func newReferenceGrantResolver(refGrants map[types.NamespacedName]*v1beta1.ReferenceGrant) *referenceGrantResolver {
8694
allowed := make(map[allowedReference]struct{})

internal/mode/static/state/graph/reference_grant_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -233,17 +233,34 @@ func TestFromGRPCRoute(t *testing.T) {
233233
g.Expect(ref).To(Equal(exp))
234234
}
235235

236+
func TestFromTLSRoute(t *testing.T) {
237+
ref := fromTLSRoute("ns")
238+
239+
exp := fromResource{
240+
group: v1beta1.GroupName,
241+
kind: kinds.TLSRoute,
242+
namespace: "ns",
243+
}
244+
245+
g := NewWithT(t)
246+
g.Expect(ref).To(Equal(exp))
247+
}
248+
236249
func TestRefAllowedFrom(t *testing.T) {
237250
gwNs := "gw-ns"
238251
hrNs := "hr-ns"
239252
grNs := "gr-ns"
253+
trNs := "tr-ns"
240254

241255
allowedHTTPRouteNs := "hr-allowed-ns"
242256
allowedHTTPRouteNsName := types.NamespacedName{Namespace: allowedHTTPRouteNs, Name: "all-allowed-in-ns"}
243257

244258
allowedGRPCRouteNs := "gr-allowed-ns"
245259
allowedGRPCRouteNsName := types.NamespacedName{Namespace: allowedGRPCRouteNs, Name: "all-allowed-in-ns"}
246260

261+
allowedTLSRouteNs := "tr-allowed-ns"
262+
allowedTLSRouteNsName := types.NamespacedName{Namespace: allowedTLSRouteNs, Name: "all-allowed-in-ns"}
263+
247264
allowedGatewayNs := "gw-allowed-ns"
248265
allowedGatewayNsName := types.NamespacedName{Namespace: allowedGatewayNs, Name: "all-allowed-in-ns"}
249266

@@ -298,11 +315,28 @@ func TestRefAllowedFrom(t *testing.T) {
298315
},
299316
},
300317
},
318+
{Namespace: allowedTLSRouteNs, Name: "tr-2-svc"}: {
319+
Spec: v1beta1.ReferenceGrantSpec{
320+
From: []v1beta1.ReferenceGrantFrom{
321+
{
322+
Group: v1beta1.GroupName,
323+
Kind: kinds.TLSRoute,
324+
Namespace: v1beta1.Namespace(trNs),
325+
},
326+
},
327+
To: []v1beta1.ReferenceGrantTo{
328+
{
329+
Kind: "Service",
330+
},
331+
},
332+
},
333+
},
301334
}
302335

303336
resolver := newReferenceGrantResolver(refGrants)
304337
refAllowedFromGRPCRoute := resolver.refAllowedFrom(fromGRPCRoute(grNs))
305338
refAllowedFromHTTPRoute := resolver.refAllowedFrom(fromHTTPRoute(hrNs))
339+
refAllowedFromTLSRoute := resolver.refAllowedFrom(fromTLSRoute(trNs))
306340
refAllowedFromGateway := resolver.refAllowedFrom(fromGateway(gwNs))
307341

308342
tests := []struct {
@@ -347,6 +381,18 @@ func TestRefAllowedFrom(t *testing.T) {
347381
toResource: toService(notAllowedNsName),
348382
expAllowed: false,
349383
},
384+
{
385+
name: "ref allowed from tlsroute to service",
386+
refAllowedFrom: refAllowedFromTLSRoute,
387+
toResource: toService(allowedTLSRouteNsName),
388+
expAllowed: true,
389+
},
390+
{
391+
name: "ref not allowed from tlsroute to service",
392+
refAllowedFrom: refAllowedFromTLSRoute,
393+
toResource: toService(notAllowedNsName),
394+
expAllowed: false,
395+
},
350396
}
351397

352398
for _, test := range tests {

internal/mode/static/state/graph/route_common.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,21 @@ func buildL4RoutesForGateways(
178178
gatewayNsNames []types.NamespacedName,
179179
services map[types.NamespacedName]*apiv1.Service,
180180
npCfg *NginxProxy,
181+
resolver *referenceGrantResolver,
181182
) map[L4RouteKey]*L4Route {
182183
if len(gatewayNsNames) == 0 {
183184
return nil
184185
}
185186

186187
routes := make(map[L4RouteKey]*L4Route)
187188
for _, route := range tlsRoutes {
188-
r := buildTLSRoute(route, gatewayNsNames, services, npCfg)
189+
r := buildTLSRoute(
190+
route,
191+
gatewayNsNames,
192+
services,
193+
npCfg,
194+
resolver.refAllowedFrom(fromTLSRoute(route.Namespace)),
195+
)
189196
if r != nil {
190197
routes[CreateRouteKeyL4(route)] = r
191198
}

internal/mode/static/state/graph/route_common_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -2436,11 +2436,14 @@ func TestBuildL4RoutesForGateways_NoGateways(t *testing.T) {
24362436
},
24372437
}
24382438

2439+
refGrantResolver := newReferenceGrantResolver(nil)
2440+
24392441
g.Expect(buildL4RoutesForGateways(
24402442
tlsRoutes,
24412443
nil,
24422444
services,
24432445
nil,
2446+
refGrantResolver,
24442447
)).To(BeNil())
24452448
}
24462449

internal/mode/static/state/graph/tlsroute.go

+31-35
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ func buildTLSRoute(
1616
gatewayNsNames []types.NamespacedName,
1717
services map[types.NamespacedName]*apiv1.Service,
1818
npCfg *NginxProxy,
19+
refGrantResolver func(resource toResource) bool,
1920
) *L4Route {
2021
r := &L4Route{
2122
Source: gtr,
@@ -53,15 +54,14 @@ func buildTLSRoute(
5354
return r
5455
}
5556

56-
cond, br := validateBackendRefTLSRoute(gtr, services, npCfg)
57+
br, cond := validateBackendRefTLSRoute(gtr, services, npCfg, refGrantResolver)
5758

5859
r.Spec.BackendRef = br
5960
r.Valid = true
6061
r.Attachable = true
6162

6263
if cond != nil {
6364
r.Conditions = append(r.Conditions, *cond)
64-
r.Valid = false
6565
}
6666

6767
return r
@@ -70,12 +70,26 @@ func buildTLSRoute(
7070
func validateBackendRefTLSRoute(gtr *v1alpha2.TLSRoute,
7171
services map[types.NamespacedName]*apiv1.Service,
7272
npCfg *NginxProxy,
73-
) (*conditions.Condition, BackendRef) {
73+
refGrantResolver func(resource toResource) bool,
74+
) (BackendRef, *conditions.Condition) {
7475
// Length of BackendRefs and Rules is guaranteed to be one due to earlier check in buildTLSRoute
7576
refPath := field.NewPath("spec").Child("rules").Index(0).Child("backendRefs").Index(0)
7677

7778
ref := gtr.Spec.Rules[0].BackendRefs[0]
7879

80+
if valid, cond := validateBackendRef(
81+
ref,
82+
gtr.Namespace,
83+
refGrantResolver,
84+
refPath,
85+
); !valid {
86+
backendRef := BackendRef{
87+
Valid: false,
88+
}
89+
90+
return backendRef, &cond
91+
}
92+
7993
ns := gtr.Namespace
8094
if ref.Namespace != nil {
8195
ns = string(*ref.Namespace)
@@ -86,48 +100,30 @@ func validateBackendRefTLSRoute(gtr *v1alpha2.TLSRoute,
86100
Name: string(gtr.Spec.Rules[0].BackendRefs[0].Name),
87101
}
88102

89-
backendRef := BackendRef{
90-
Valid: true,
91-
}
92-
var cond *conditions.Condition
93-
94-
if ref.Port == nil {
95-
valErr := field.Required(refPath.Child("port"), "port cannot be nil")
96-
backendRef.Valid = false
97-
cond = helpers.GetPointer(staticConds.NewRouteBackendRefUnsupportedValue(valErr.Error()))
98-
99-
return cond, backendRef
100-
}
101-
102103
svcIPFamily, svcPort, err := getIPFamilyAndPortFromRef(
103104
ref,
104105
svcNsName,
105106
services,
106107
refPath,
107108
)
108109

109-
backendRef.ServicePort = svcPort
110-
backendRef.SvcNsName = svcNsName
110+
backendRef := BackendRef{
111+
SvcNsName: svcNsName,
112+
ServicePort: svcPort,
113+
Valid: true,
114+
}
111115

112116
if err != nil {
113117
backendRef.Valid = false
114-
cond = helpers.GetPointer(staticConds.NewRouteBackendRefRefBackendNotFound(err.Error()))
115-
} else if err := verifyIPFamily(npCfg, svcIPFamily); err != nil {
116-
backendRef.Valid = false
117-
cond = helpers.GetPointer(staticConds.NewRouteInvalidIPFamily(err.Error()))
118-
} else if ref.Group != nil && !(*ref.Group == "core" || *ref.Group == "") {
119-
valErr := field.NotSupported(refPath.Child("group"), *ref.Group, []string{"core", ""})
120-
backendRef.Valid = false
121-
cond = helpers.GetPointer(staticConds.NewRouteBackendRefInvalidKind(valErr.Error()))
122-
} else if ref.Kind != nil && *ref.Kind != "Service" {
123-
valErr := field.NotSupported(refPath.Child("kind"), *ref.Kind, []string{"Service"})
124-
backendRef.Valid = false
125-
cond = helpers.GetPointer(staticConds.NewRouteBackendRefInvalidKind(valErr.Error()))
126-
} else if ref.Namespace != nil && string(*ref.Namespace) != gtr.Namespace {
127-
msg := "Cross-namespace routing is not supported"
118+
119+
return backendRef, helpers.GetPointer(staticConds.NewRouteBackendRefRefBackendNotFound(err.Error()))
120+
}
121+
122+
if err := verifyIPFamily(npCfg, svcIPFamily); err != nil {
128123
backendRef.Valid = false
129-
cond = helpers.GetPointer(staticConds.NewRouteBackendRefUnsupportedValue(msg))
124+
125+
return backendRef, helpers.GetPointer(staticConds.NewRouteInvalidIPFamily(err.Error()))
130126
}
131-
// FIXME(sarthyparty): Add check for invalid weights, we removed checks to pass the conformance test
132-
return cond, backendRef
127+
128+
return backendRef, nil
133129
}

0 commit comments

Comments
 (0)