Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Multiple RequestMirrors Filters per HTTPRoute Rule #1819

Merged
merged 15 commits into from
Sep 17, 2023
Merged
31 changes: 19 additions & 12 deletions internal/gatewayapi/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type HTTPFiltersTranslator interface {
processRedirectFilter(redirect *v1beta1.HTTPRequestRedirectFilter, filterContext *HTTPFiltersContext)
processRequestHeaderModifierFilter(headerModifier *v1beta1.HTTPHeaderFilter, filterContext *HTTPFiltersContext)
processResponseHeaderModifierFilter(headerModifier *v1beta1.HTTPHeaderFilter, filterContext *HTTPFiltersContext)
processRequestMirrorFilter(mirror *v1beta1.HTTPRequestMirrorFilter, filterContext *HTTPFiltersContext, resources *Resources)
processRequestMirrorFilter(filterIdx int, mirror *v1beta1.HTTPRequestMirrorFilter, filterContext *HTTPFiltersContext, resources *Resources)
processExtensionRefHTTPFilter(extRef *v1beta1.LocalObjectReference, filterContext *HTTPFiltersContext, resources *Resources)
processUnsupportedHTTPFilter(filterType string, filterContext *HTTPFiltersContext)
}
Expand All @@ -56,7 +56,7 @@ type HTTPFilterIR struct {
AddResponseHeaders []ir.AddHeader
RemoveResponseHeaders []string

Mirror *ir.RouteDestination
Mirror []*ir.RouteDestination

RequestAuthentication *ir.RequestAuthentication
RateLimit *ir.RateLimit
Expand All @@ -76,7 +76,7 @@ func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext,
RuleIdx: ruleIdx,
HTTPFilterIR: &HTTPFilterIR{},
}

filterIdx := 0
for i := range filters {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just use i

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just use i

Yes, I can use 'i' if I don't need to match the value with the index of Mirror list.

filter := filters[i]
// If an invalid filter type has been configured then skip processing any more filters
Expand All @@ -98,7 +98,8 @@ func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext,
case v1beta1.HTTPRouteFilterResponseHeaderModifier:
t.processResponseHeaderModifierFilter(filter.ResponseHeaderModifier, httpFiltersContext)
case v1beta1.HTTPRouteFilterRequestMirror:
t.processRequestMirrorFilter(filter.RequestMirror, httpFiltersContext, resources)
t.processRequestMirrorFilter(filterIdx, filter.RequestMirror, httpFiltersContext, resources)
filterIdx++
case v1beta1.HTTPRouteFilterExtensionRef:
t.processExtensionRefHTTPFilter(filter.ExtensionRef, httpFiltersContext, resources)
default:
Expand All @@ -120,7 +121,7 @@ func (t *Translator) ProcessGRPCFilters(parentRef *RouteParentContext,

HTTPFilterIR: &HTTPFilterIR{},
}

filterIdx := 0
for i := range filters {
filter := filters[i]
// If an invalid filter type has been configured then skip processing any more filters
Expand All @@ -138,7 +139,8 @@ func (t *Translator) ProcessGRPCFilters(parentRef *RouteParentContext,
case v1alpha2.GRPCRouteFilterResponseHeaderModifier:
t.processResponseHeaderModifierFilter(filter.ResponseHeaderModifier, httpFiltersContext)
case v1alpha2.GRPCRouteFilterRequestMirror:
t.processRequestMirrorFilter(filter.RequestMirror, httpFiltersContext, resources)
t.processRequestMirrorFilter(filterIdx, filter.RequestMirror, httpFiltersContext, resources)
filterIdx++
case v1alpha2.GRPCRouteFilterExtensionRef:
t.processExtensionRefHTTPFilter(filter.ExtensionRef, httpFiltersContext, resources)
default:
Expand Down Expand Up @@ -808,6 +810,7 @@ func (t *Translator) processExtensionRefHTTPFilter(extFilter *v1beta1.LocalObjec
}

func (t *Translator) processRequestMirrorFilter(
filterIdx int,
mirrorFilter *v1beta1.HTTPRequestMirrorFilter,
filterContext *HTTPFiltersContext,
resources *Resources) {
Expand Down Expand Up @@ -839,22 +842,26 @@ func (t *Translator) processRequestMirrorFilter(
// Only add missing mirror destinations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo this entire logic of adding missing mirror destinations can be removed, and so you can simplify this logic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo this entire logic of adding missing mirror destinations can be removed, and so you can simplify this logic

Are we building filterContext.Mirror from scratch and there is no duplicate Endpoints?
I definitely can refactor the code based on your assessment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes we dont need to consider the duplicate case, please go ahead and refactor

for _, mirrorEp := range mirrorEndpoints {
var found bool
if filterContext.Mirror != nil {
for _, mirror := range filterContext.Mirror.Endpoints {
if filterContext.Mirror != nil && filterIdx < len(filterContext.Mirror) {
for _, mirror := range filterContext.Mirror[filterIdx].Endpoints {
if mirror != nil {
if mirror.Host == mirrorEp.Host && mirror.Port == mirrorEp.Port {
found = true
}
}
}
}

if !found {
if filterContext.Mirror == nil {
filterContext.Mirror = &ir.RouteDestination{
Name: fmt.Sprintf("%s-mirror", irRouteDestinationName(filterContext.Route, filterContext.RuleIdx)),
if filterContext.Mirror == nil || filterIdx >= len(filterContext.Mirror) {
newMirror := &ir.RouteDestination{
Name: fmt.Sprintf("%s-mirror-%d", irRouteDestinationName(filterContext.Route, filterContext.RuleIdx), filterIdx),
}
newMirror.Endpoints = append(newMirror.Endpoints, mirrorEp)
filterContext.Mirror = append(filterContext.Mirror, newMirror)
} else {
filterContext.Mirror[filterIdx].Endpoints = append(filterContext.Mirror[filterIdx].Endpoints, mirrorEp)
}
filterContext.Mirror.Endpoints = append(filterContext.Mirror.Endpoints, mirrorEp)
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions internal/ir/xds.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ type HTTPRoute struct {
// Redirections to be returned for this route. Takes precedence over Destinations.
Redirect *Redirect `json:"redirect,omitempty" yaml:"redirect,omitempty"`
// Destination that requests to this HTTPRoute will be mirrored to
Mirror *RouteDestination `json:"mirror,omitempty" yaml:"mirror,omitempty"`
Mirror []*RouteDestination `json:"mirror,omitempty" yaml:"mirror,omitempty"`
zirain marked this conversation as resolved.
Show resolved Hide resolved
// Destination associated with this matched route.
Destination *RouteDestination `json:"destination,omitempty" yaml:"destination,omitempty"`
// Rewrite to be changed for this route.
Expand Down Expand Up @@ -352,8 +352,10 @@ func (h HTTPRoute) Validate() error {
}
}
if h.Mirror != nil {
if err := h.Mirror.Validate(); err != nil {
errs = multierror.Append(errs, err)
for _, mirror := range h.Mirror {
if err := mirror.Validate(); err != nil {
errs = multierror.Append(errs, err)
}
}
}
if len(h.AddRequestHeaders) > 0 {
Expand Down
10 changes: 8 additions & 2 deletions internal/ir/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 10 additions & 8 deletions internal/xds/translator/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func buildXdsRoute(httpRoute *ir.HTTPRoute, listener *listenerv3.Listener) *rout
case httpRoute.URLRewrite != nil:
routeAction := buildXdsURLRewriteAction(httpRoute.Destination.Name, httpRoute.URLRewrite)
if httpRoute.Mirror != nil {
routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirror.Name)
routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirror)
}

router.Action = &routev3.Route_Route{Route: routeAction}
Expand All @@ -54,13 +54,13 @@ func buildXdsRoute(httpRoute *ir.HTTPRoute, listener *listenerv3.Listener) *rout
// If there are invalid backends then a weighted cluster is required for the route
routeAction := buildXdsWeightedRouteAction(httpRoute)
if httpRoute.Mirror != nil {
routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirror.Name)
routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirror)
}
router.Action = &routev3.Route_Route{Route: routeAction}
} else {
routeAction := buildXdsRouteAction(httpRoute.Destination.Name)
if httpRoute.Mirror != nil {
routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirror.Name)
routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirror)
}
router.Action = &routev3.Route_Route{Route: routeAction}
}
Expand Down Expand Up @@ -293,11 +293,13 @@ func buildXdsDirectResponseAction(res *ir.DirectResponse) *routev3.DirectRespons
return routeAction
}

func buildXdsRequestMirrorPolicies(destName string) []*routev3.RouteAction_RequestMirrorPolicy {
mirrorPolicies := []*routev3.RouteAction_RequestMirrorPolicy{
{
Cluster: destName,
},
func buildXdsRequestMirrorPolicies(mirrorDestinations []*ir.RouteDestination) []*routev3.RouteAction_RequestMirrorPolicy {
var mirrorPolicies []*routev3.RouteAction_RequestMirrorPolicy

for _, mirrorDest := range mirrorDestinations {
mirrorPolicies = append(mirrorPolicies, &routev3.RouteAction_RequestMirrorPolicy{
Cluster: mirrorDest.Name,
})
}

return mirrorPolicies
Expand Down
18 changes: 10 additions & 8 deletions internal/xds/translator/translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,16 @@ func (t *Translator) processHTTPListenerXdsTranslation(tCtx *types.ResourceVersi
}

if httpRoute.Mirror != nil {
if err := addXdsCluster(tCtx, addXdsClusterArgs{
name: httpRoute.Mirror.Name,
endpoints: httpRoute.Mirror.Endpoints,
tSocket: nil,
protocol: protocol,
endpointType: Static,
}); err != nil && !errors.Is(err, ErrXdsClusterExists) {
return err
for _, mirrorDest := range httpRoute.Mirror {
if err := addXdsCluster(tCtx, addXdsClusterArgs{
name: mirrorDest.Name,
endpoints: mirrorDest.Endpoints,
tSocket: nil,
protocol: protocol,
endpointType: Static,
}); err != nil && !errors.Is(err, ErrXdsClusterExists) {
return err
}
}
}
}
Expand Down