Skip to content

Commit

Permalink
add BackendRefContext
Browse files Browse the repository at this point in the history
Signed-off-by: Karol Szwaj <karol.szwaj@gmail.com>
  • Loading branch information
cnvergence committed Feb 23, 2024
1 parent e46a2c3 commit 6a64316
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 30 deletions.
38 changes: 38 additions & 0 deletions internal/gatewayapi/contexts.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,41 @@ func (r *RouteParentContext) HasCondition(route RouteContext, condType gwapiv1.R
}
return false
}

// BackendRefContext represents a generic BackendRef object that can reference Gateway objects.
type BackendRefContext struct {
HTTPBackendRef *gwapiv1.HTTPBackendRef
GRPCBackendRef *v1alpha2.GRPCBackendRef
BackendRef *gwapiv1.BackendRef
}

// GetBackendRef returns the BackendRef object from BackendRefContext matching route Kind.
func (b *BackendRefContext) GetBackendRef(routeKind gwapiv1.Kind) *gwapiv1.BackendRef {
switch routeKind {
case KindHTTPRoute:
if b.HTTPBackendRef != nil {
return &b.HTTPBackendRef.BackendRef
}
case KindGRPCRoute:
if b.GRPCBackendRef != nil {
return &b.GRPCBackendRef.BackendRef
}
default:
return b.BackendRef
}
return nil

Check warning on line 442 in internal/gatewayapi/contexts.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/contexts.go#L442

Added line #L442 was not covered by tests
}

func (b *BackendRefContext) GetHTTPFilters() []gwapiv1.HTTPRouteFilter {
if b.HTTPBackendRef != nil {
return b.HTTPBackendRef.Filters
}
return nil

Check warning on line 449 in internal/gatewayapi/contexts.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/contexts.go#L449

Added line #L449 was not covered by tests
}

func (b *BackendRefContext) GetGRPCFilters() []v1alpha2.GRPCRouteFilter {
if b.GRPCBackendRef != nil {
return b.GRPCBackendRef.Filters
}
return nil

Check warning on line 456 in internal/gatewayapi/contexts.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/contexts.go#L456

Added line #L456 was not covered by tests
}
9 changes: 7 additions & 2 deletions internal/gatewayapi/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -709,15 +709,20 @@ func (t *Translator) processRequestMirrorFilter(
Weight: &weight,
}

backendRefContext := BackendRefContext{
HTTPBackendRef: &gwapiv1.HTTPBackendRef{
BackendRef: mirrorBackendRef,
},
}
// This sets the status on the HTTPRoute, should the usage be changed so that the status message reflects that the backendRef is from the filter?
filterNs := filterContext.Route.GetNamespace()
serviceNamespace := NamespaceDerefOr(mirrorBackend.Namespace, filterNs)
if !t.validateBackendRef(&mirrorBackendRef, filterContext.ParentRef, filterContext.Route,
if !t.validateBackendRef(backendRefContext, filterContext.ParentRef, filterContext.Route,
resources, serviceNamespace, KindHTTPRoute) {
return
}

ds, _ := t.processDestination(mirrorBackendRef, filterContext.ParentRef, filterContext.Route, resources)
ds, _ := t.processDestination(backendRefContext, filterContext.ParentRef, filterContext.Route, resources)

newMirror := &ir.RouteDestination{
Name: fmt.Sprintf("%s-mirror-%d", irRouteDestinationName(filterContext.Route, filterContext.RuleIdx), filterIdx),
Expand Down
49 changes: 23 additions & 26 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,17 +173,11 @@ func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRe
dstAddrTypeMap := make(map[ir.DestinationAddressType]int)

for _, backendRef := range rule.BackendRefs {
if len(backendRef.Filters) > 0 {
parentRef.SetCondition(httpRoute,
gwapiv1.RouteConditionResolvedRefs,
metav1.ConditionFalse,
"UnsupportedRefValue",
"The filters field within BackendRef is not supported",
)
continue
backendRefContext := BackendRefContext{
HTTPBackendRef: &backendRef,

Check failure on line 177 in internal/gatewayapi/route.go

View workflow job for this annotation

GitHub Actions / lint

G601: Implicit memory aliasing in for loop. (gosec)
}

ds, backendWeight := t.processDestination(backendRef.BackendRef, parentRef, httpRoute, resources)
ds, backendWeight := t.processDestination(backendRefContext, parentRef, httpRoute, resources)
if !t.EndpointRoutingDisabled && ds != nil && len(ds.Endpoints) > 0 && ds.AddressType != nil {
dstAddrTypeMap[*ds.AddressType]++
}
Expand Down Expand Up @@ -477,16 +471,11 @@ func (t *Translator) processGRPCRouteRules(grpcRoute *GRPCRouteContext, parentRe
}

for _, backendRef := range rule.BackendRefs {
if len(backendRef.Filters) > 0 {
parentRef.SetCondition(grpcRoute,
gwapiv1.RouteConditionResolvedRefs,
metav1.ConditionFalse,
"UnsupportedRefValue",
"The filters field within BackendRef is not supported",
)
continue
backendRefContext := BackendRefContext{
GRPCBackendRef: &backendRef,

Check failure on line 475 in internal/gatewayapi/route.go

View workflow job for this annotation

GitHub Actions / lint

G601: Implicit memory aliasing in for loop. (gosec)
}
ds, backendWeight := t.processDestination(backendRef.BackendRef, parentRef, grpcRoute, resources)

ds, backendWeight := t.processDestination(backendRefContext, parentRef, grpcRoute, resources)
for _, route := range ruleRoutes {
// If the route already has a direct response or redirect configured, then it was from a filter so skip
// processing any destinations for this route.
Expand Down Expand Up @@ -738,7 +727,10 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour
for _, rule := range tlsRoute.Spec.Rules {
for _, backendRef := range rule.BackendRefs {
backendRef := backendRef
ds, _ := t.processDestination(backendRef, parentRef, tlsRoute, resources)
backendRefContext := BackendRefContext{
BackendRef: &backendRef,
}
ds, _ := t.processDestination(backendRefContext, parentRef, tlsRoute, resources)
if ds != nil {
destSettings = append(destSettings, ds)
}
Expand Down Expand Up @@ -876,7 +868,10 @@ func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resour
}

backendRef := udpRoute.Spec.Rules[0].BackendRefs[0]
ds, _ := t.processDestination(backendRef, parentRef, udpRoute, resources)
backendRefContext := BackendRefContext{
BackendRef: &backendRef,
}
ds, _ := t.processDestination(backendRefContext, parentRef, udpRoute, resources)
// Skip further processing if route destination is not valid
if ds == nil || len(ds.Endpoints) == 0 {
continue
Expand Down Expand Up @@ -1008,7 +1003,10 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour
}

backendRef := tcpRoute.Spec.Rules[0].BackendRefs[0]
ds, _ := t.processDestination(backendRef, parentRef, tcpRoute, resources)
backendRefContext := BackendRefContext{
BackendRef: &backendRef,
}
ds, _ := t.processDestination(backendRefContext, parentRef, tcpRoute, resources)
// Skip further processing if route destination is not valid
if ds == nil || len(ds.Endpoints) == 0 {
continue
Expand Down Expand Up @@ -1084,20 +1082,19 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour
// processDestination takes a backendRef and translates it into destination setting or sets error statuses and
// returns the weight for the backend so that 500 error responses can be returned for invalid backends in
// the same proportion as the backend would have otherwise received
func (t *Translator) processDestination(backendRef gwapiv1.BackendRef,
func (t *Translator) processDestination(backendRefContext BackendRefContext,
parentRef *RouteParentContext,
route RouteContext,
resources *Resources) (ds *ir.DestinationSetting, backendWeight uint32) {

routeType := GetRouteType(route)
weight := uint32(1)
backendRef := backendRefContext.GetBackendRef(routeType)
if backendRef.Weight != nil {
weight = uint32(*backendRef.Weight)
}

backendNamespace := NamespaceDerefOr(backendRef.Namespace, route.GetNamespace())

routeType := GetRouteType(route)
if !t.validateBackendRef(&backendRef, parentRef, route, resources, backendNamespace, routeType) {
if !t.validateBackendRef(backendRefContext, parentRef, route, resources, backendNamespace, routeType) {
return nil, weight
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,10 @@ xdsIR:
port: 10080
routes:
- backendWeights:
invalid: 0
invalid: 1
valid: 0
directResponse:
statusCode: 500
hostname: '*'
name: httproute/default/httproute-1/rule/0/match/0/*
pathMatch:
Expand Down
31 changes: 30 additions & 1 deletion internal/gatewayapi/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ import (
egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
)

func (t *Translator) validateBackendRef(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext,
func (t *Translator) validateBackendRef(backendRefContext BackendRefContext, parentRef *RouteParentContext, route RouteContext,
resources *Resources, backendNamespace string, routeKind gwapiv1.Kind) bool {
if !t.validateBackendRefFilters(backendRefContext, parentRef, route, routeKind) {
return false
}
backendRef := backendRefContext.GetBackendRef(routeKind)

if !t.validateBackendRefGroup(backendRef, parentRef, route) {
return false
}
Expand Down Expand Up @@ -80,6 +85,30 @@ func (t *Translator) validateBackendRefKind(backendRef *gwapiv1a2.BackendRef, pa
return true
}

func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, parentRef *RouteParentContext, route RouteContext, routeKind gwapiv1.Kind) bool {
var filtersLen int
switch routeKind {
case KindHTTPRoute:
filtersLen = len(backendRef.GetHTTPFilters())
case KindGRPCRoute:
filtersLen = len(backendRef.GetGRPCFilters())
default:
return true
}

if filtersLen > 0 {
parentRef.SetCondition(route,
gwapiv1.RouteConditionResolvedRefs,
metav1.ConditionFalse,
"UnsupportedRefValue",
"The filters field within BackendRef is not supported",
)
return false
}

return true
}

func (t *Translator) validateBackendNamespace(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext,
resources *Resources, routeKind gwapiv1.Kind) bool {
if backendRef.Namespace != nil && string(*backendRef.Namespace) != "" && string(*backendRef.Namespace) != route.GetNamespace() {
Expand Down

0 comments on commit 6a64316

Please sign in to comment.