Skip to content

Commit

Permalink
Gateway API BackendRef filters support
Browse files Browse the repository at this point in the history
Fixes: #29080

Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
  • Loading branch information
chaunceyjiang committed Jan 3, 2024
1 parent 980c5dd commit a199ad6
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 6 deletions.
27 changes: 26 additions & 1 deletion operator/pkg/model/ingestion/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package ingestion

import (
"fmt"
"strings"
"time"

Expand Down Expand Up @@ -125,7 +126,7 @@ func toHTTPRoutes(listener gatewayv1.Listener, input []gatewayv1.HTTPRoute, serv
if len(computedHost) == 1 && computedHost[0] == allHosts {
computedHost = nil
}

var backendHTTPFilters []*model.BackendHTTPFilter
for _, rule := range r.Spec.Rules {
bes := make([]model.Backend, 0, len(rule.BackendRefs))
for _, be := range rule.BackendRefs {
Expand All @@ -141,6 +142,28 @@ func toHTTPRoutes(listener gatewayv1.Listener, input []gatewayv1.HTTPRoute, serv
}
if serviceExists(string(be.Name), helpers.NamespaceDerefOr(be.Namespace, r.Namespace), services) {
bes = append(bes, backendToModelBackend(be.BackendRef, r.Namespace))
for _, f := range be.Filters {
switch f.Type {
case gatewayv1.HTTPRouteFilterRequestHeaderModifier:
backendHTTPFilters = append(backendHTTPFilters, &model.BackendHTTPFilter{
Name: fmt.Sprintf("%s:%s:%d", helpers.NamespaceDerefOr(be.Namespace, r.Namespace), be.Name, uint32(*be.Port)),
RequestHeaderFilter: &model.HTTPHeaderFilter{
HeadersToAdd: toHTTPHeaders(f.RequestHeaderModifier.Add),
HeadersToSet: toHTTPHeaders(f.RequestHeaderModifier.Set),
HeadersToRemove: f.RequestHeaderModifier.Remove,
},
})
case gatewayv1.HTTPRouteFilterResponseHeaderModifier:
backendHTTPFilters = append(backendHTTPFilters, &model.BackendHTTPFilter{
Name: fmt.Sprintf("%s:%s:%d", helpers.NamespaceDerefOr(be.Namespace, r.Namespace), be.Name, uint32(*be.Port)),
ResponseHeaderModifier: &model.HTTPHeaderFilter{
HeadersToAdd: toHTTPHeaders(f.ResponseHeaderModifier.Add),
HeadersToSet: toHTTPHeaders(f.ResponseHeaderModifier.Set),
HeadersToRemove: f.ResponseHeaderModifier.Remove,
},
})
}
}
}
}

Expand Down Expand Up @@ -184,6 +207,7 @@ func toHTTPRoutes(listener gatewayv1.Listener, input []gatewayv1.HTTPRoute, serv
httpRoutes = append(httpRoutes, model.HTTPRoute{
Hostnames: computedHost,
Backends: bes,
BackendHTTPFilters: backendHTTPFilters,
DirectResponse: dr,
RequestHeaderFilter: requestHeaderFilter,
ResponseHeaderModifier: responseHeaderFilter,
Expand All @@ -202,6 +226,7 @@ func toHTTPRoutes(listener gatewayv1.Listener, input []gatewayv1.HTTPRoute, serv
QueryParamsMatch: toQueryMatch(match),
Method: (*string)(match.Method),
Backends: bes,
BackendHTTPFilters: backendHTTPFilters,
DirectResponse: dr,
RequestHeaderFilter: requestHeaderFilter,
ResponseHeaderModifier: responseHeaderFilter,
Expand Down
14 changes: 14 additions & 0 deletions operator/pkg/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ type HTTPRoute struct {
Method *string `json:"method,omitempty"`
// Backend is the backend handling the requests
Backends []Backend `json:"backends,omitempty"`
// BackendHTTPFilters can be used to add or remove HTTP
BackendHTTPFilters []*BackendHTTPFilter `json:"backend_http_filters,omitempty"`
// DirectResponse instructs the proxy to respond directly to the client.
DirectResponse *DirectResponse `json:"direct_response,omitempty"`

Expand Down Expand Up @@ -289,6 +291,18 @@ type HTTPRoute struct {
Timeout Timeout `json:"timeout,omitempty"`
}

type BackendHTTPFilter struct {
// Name is the name of the Backend, the name is having the format of "namespace:name:port"
Name string `json:"name"`
// RequestHeaderFilter can be used to add or remove an HTTP
//header from an HTTP request before it is sent to the upstream target.
RequestHeaderFilter *HTTPHeaderFilter `json:"request_header_filter,omitempty"`

// ResponseHeaderModifier can be used to add or remove an HTTP
//header from an HTTP response before it is sent to the client.
ResponseHeaderModifier *HTTPHeaderFilter `json:"response_header_modifier,omitempty"`
}

// Infrastructure holds the labels and annotations configuration,
// which will be propagated to LB service.
type Infrastructure struct {
Expand Down
28 changes: 23 additions & 5 deletions operator/pkg/model/translation/envoy_virtual_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,15 @@ func envoyHTTPRoutes(httpRoutes []model.HTTPRoute, hostnames []string, hostNameS
if hRoutes[0].RequestRedirect != nil {
route.Action = getRouteRedirect(hRoutes[0].RequestRedirect, listenerPort)
} else {
route.Action = getRouteAction(&r, backends, r.Rewrite, r.RequestMirrors)
route.Action = getRouteAction(&r, backends, r.BackendHTTPFilters, r.Rewrite, r.RequestMirrors)
}
if len(backends) == 1 {
for _, fn := range hRoutes[0].BackendHTTPFilters {
route.RequestHeadersToAdd = append(route.RequestHeadersToAdd, getHeadersToAdd(fn.RequestHeaderFilter)...)
route.RequestHeadersToRemove = append(route.RequestHeadersToRemove, getHeadersToRemove(fn.RequestHeaderFilter)...)
route.ResponseHeadersToAdd = append(route.ResponseHeadersToAdd, getHeadersToAdd(fn.ResponseHeaderModifier)...)
route.ResponseHeadersToRemove = append(route.ResponseHeadersToRemove, getHeadersToRemove(fn.ResponseHeaderModifier)...)
}
}
routes = append(routes, &route)
delete(matchBackendMap, r.GetMatchKey())
Expand Down Expand Up @@ -322,7 +330,7 @@ func timeoutMutation(backend *time.Duration, request *time.Duration) routeAction
}
}

func getRouteAction(route *model.HTTPRoute, backends []model.Backend, rewrite *model.HTTPURLRewriteFilter, mirrors []*model.HTTPRequestMirror) *envoy_config_route_v3.Route_Route {
func getRouteAction(route *model.HTTPRoute, backends []model.Backend, backendHTTPFilter []*model.BackendHTTPFilter, rewrite *model.HTTPURLRewriteFilter, mirrors []*model.HTTPRequestMirror) *envoy_config_route_v3.Route_Route {
var routeAction *envoy_config_route_v3.Route_Route

mutators := []routeActionMutation{
Expand All @@ -347,17 +355,27 @@ func getRouteAction(route *model.HTTPRoute, backends []model.Backend, rewrite *m
}
return r
}

backendFilter := make(map[string]*model.BackendHTTPFilter)
for _, f := range backendHTTPFilter {
backendFilter[f.Name] = f
}
weightedClusters := make([]*envoy_config_route_v3.WeightedCluster_ClusterWeight, 0, len(backends))
for _, be := range backends {
var weight int32 = 1
if be.Weight != nil {
weight = *be.Weight
}
weightedClusters = append(weightedClusters, &envoy_config_route_v3.WeightedCluster_ClusterWeight{
clusterWeight := &envoy_config_route_v3.WeightedCluster_ClusterWeight{
Name: getClusterName(be.Namespace, be.Name, be.Port.GetPort()),
Weight: wrapperspb.UInt32(uint32(weight)),
})
}
if fn, ok := backendFilter[getClusterName(be.Namespace, be.Name, be.Port.GetPort())]; ok {
clusterWeight.RequestHeadersToAdd = append(clusterWeight.RequestHeadersToAdd, getHeadersToAdd(fn.RequestHeaderFilter)...)
clusterWeight.RequestHeadersToRemove = append(clusterWeight.RequestHeadersToRemove, getHeadersToRemove(fn.RequestHeaderFilter)...)
clusterWeight.ResponseHeadersToAdd = append(clusterWeight.ResponseHeadersToAdd, getHeadersToAdd(fn.ResponseHeaderModifier)...)
clusterWeight.ResponseHeadersToRemove = append(clusterWeight.ResponseHeadersToRemove, getHeadersToRemove(fn.ResponseHeaderModifier)...)
}
weightedClusters = append(weightedClusters, clusterWeight)
}
routeAction = &envoy_config_route_v3.Route_Route{
Route: &envoy_config_route_v3.RouteAction{
Expand Down

0 comments on commit a199ad6

Please sign in to comment.