From 14a395a92ccf19c73cd6553c3891ccd52fad77ba Mon Sep 17 00:00:00 2001 From: Ronnie-personal <76408835+Ronnie-personal@users.noreply.github.com> Date: Sat, 16 Sep 2023 21:43:02 -0400 Subject: [PATCH] feat: Multiple RequestMirrors Filters per HTTPRoute Rule (#1819) * initial code change draft coding Signed-off-by: Ronnie Personal <76408835+Ronnie-personal@users.noreply.github.com> * update test cases Signed-off-by: Ronnie Personal <76408835+Ronnie-personal@users.noreply.github.com> * update mirror to mirrors Signed-off-by: Ronnie Personal <76408835+Ronnie-personal@users.noreply.github.com> * update test file Signed-off-by: Ronnie Personal <76408835+Ronnie-personal@users.noreply.github.com> * fix conformance test Signed-off-by: Ronnie Personal <76408835+Ronnie-personal@users.noreply.github.com> * update gatewayapi testdata Signed-off-by: Ronnie Personal <76408835+Ronnie-personal@users.noreply.github.com> * address review comments Signed-off-by: Ronnie-personal <76408835+Ronnie-personal@users.noreply.github.com> * update mirror to mirrors Signed-off-by: Ronnie-personal <76408835+Ronnie-personal@users.noreply.github.com> * Mirror to Mirrors Signed-off-by: Ronnie-personal <76408835+Ronnie-personal@users.noreply.github.com> * add conformance test back Signed-off-by: Ronnie-personal <76408835+Ronnie-personal@users.noreply.github.com> --------- Signed-off-by: Ronnie Personal <76408835+Ronnie-personal@users.noreply.github.com> Signed-off-by: Ronnie-personal <76408835+Ronnie-personal@users.noreply.github.com> Co-authored-by: zirain --- internal/gatewayapi/filters.go | 35 +++++------------ internal/gatewayapi/route.go | 6 +-- ...ute-with-mirror-filter-duplicates.out.yaml | 11 ++++-- ...proute-with-mirror-filter-multiple.in.yaml | 12 ++++++ ...route-with-mirror-filter-multiple.out.yaml | 34 ++++++++++++++-- .../httproute-with-mirror-filter.out.yaml | 6 +-- internal/ir/xds.go | 10 +++-- internal/ir/xds_test.go | 2 +- internal/ir/zz_generated.deepcopy.go | 14 +++++-- internal/xds/translator/route.go | 24 ++++++------ .../xds-ir/http-route-multiple-mirrors.yaml | 22 +++++++++++ .../xds-ir/http-route-mirror.clusters.yaml | 13 ------- .../xds-ir/http-route-mirror.endpoints.yaml | 10 ----- .../out/xds-ir/http-route-mirror.routes.yaml | 2 - .../http-route-multiple-mirrors.clusters.yaml | 39 +++++++++++++++++++ ...http-route-multiple-mirrors.endpoints.yaml | 30 ++++++++++++++ ...http-route-multiple-mirrors.listeners.yaml | 33 ++++++++++++++++ .../http-route-multiple-mirrors.routes.yaml | 15 +++++++ internal/xds/translator/translator.go | 20 +++++----- internal/xds/translator/translator_test.go | 3 ++ test/conformance/conformance_test.go | 7 +--- .../experimental_conformance_test.go | 7 +--- 22 files changed, 252 insertions(+), 103 deletions(-) create mode 100644 internal/xds/translator/testdata/in/xds-ir/http-route-multiple-mirrors.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.clusters.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.endpoints.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.listeners.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.routes.yaml diff --git a/internal/gatewayapi/filters.go b/internal/gatewayapi/filters.go index 6d65beb7f5f..4469b356633 100644 --- a/internal/gatewayapi/filters.go +++ b/internal/gatewayapi/filters.go @@ -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) } @@ -56,7 +56,7 @@ type HTTPFilterIR struct { AddResponseHeaders []ir.AddHeader RemoveResponseHeaders []string - Mirror *ir.RouteDestination + Mirrors []*ir.RouteDestination RequestAuthentication *ir.RequestAuthentication RateLimit *ir.RateLimit @@ -76,7 +76,6 @@ func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext, RuleIdx: ruleIdx, HTTPFilterIR: &HTTPFilterIR{}, } - for i := range filters { filter := filters[i] // If an invalid filter type has been configured then skip processing any more filters @@ -98,7 +97,7 @@ 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(i, filter.RequestMirror, httpFiltersContext, resources) case v1beta1.HTTPRouteFilterExtensionRef: t.processExtensionRefHTTPFilter(filter.ExtensionRef, httpFiltersContext, resources) default: @@ -120,7 +119,6 @@ func (t *Translator) ProcessGRPCFilters(parentRef *RouteParentContext, HTTPFilterIR: &HTTPFilterIR{}, } - for i := range filters { filter := filters[i] // If an invalid filter type has been configured then skip processing any more filters @@ -138,7 +136,7 @@ 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(i, filter.RequestMirror, httpFiltersContext, resources) case v1alpha2.GRPCRouteFilterExtensionRef: t.processExtensionRefHTTPFilter(filter.ExtensionRef, httpFiltersContext, resources) default: @@ -808,6 +806,7 @@ func (t *Translator) processExtensionRefHTTPFilter(extFilter *v1beta1.LocalObjec } func (t *Translator) processRequestMirrorFilter( + filterIdx int, mirrorFilter *v1beta1.HTTPRequestMirrorFilter, filterContext *HTTPFiltersContext, resources *Resources) { @@ -836,27 +835,11 @@ func (t *Translator) processRequestMirrorFilter( mirrorEndpoints, _ := t.processDestEndpoints(mirrorBackendRef, filterContext.ParentRef, filterContext.Route, resources) - // Only add missing mirror destinations - for _, mirrorEp := range mirrorEndpoints { - var found bool - if filterContext.Mirror != nil { - for _, mirror := range filterContext.Mirror.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)), - } - } - filterContext.Mirror.Endpoints = append(filterContext.Mirror.Endpoints, mirrorEp) - } + newMirror := &ir.RouteDestination{ + Name: fmt.Sprintf("%s-mirror-%d", irRouteDestinationName(filterContext.Route, filterContext.RuleIdx), filterIdx), + Endpoints: mirrorEndpoints, } + filterContext.Mirrors = append(filterContext.Mirrors, newMirror) } func (t *Translator) processUnresolvedHTTPFilter(errMsg string, filterContext *HTTPFiltersContext) { diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 5e81d210bb3..e239b333cc4 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -286,8 +286,8 @@ func applyHTTPFiltersContextToIRRoute(httpFiltersContext *HTTPFiltersContext, ir if len(httpFiltersContext.RemoveResponseHeaders) > 0 { irRoute.RemoveResponseHeaders = httpFiltersContext.RemoveResponseHeaders } - if httpFiltersContext.Mirror != nil { - irRoute.Mirror = httpFiltersContext.Mirror + if httpFiltersContext.Mirrors != nil { + irRoute.Mirrors = httpFiltersContext.Mirrors } if httpFiltersContext.RequestAuthentication != nil { irRoute.RequestAuthentication = httpFiltersContext.RequestAuthentication @@ -533,7 +533,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route Redirect: routeRoute.Redirect, DirectResponse: routeRoute.DirectResponse, URLRewrite: routeRoute.URLRewrite, - Mirror: routeRoute.Mirror, + Mirrors: routeRoute.Mirrors, RequestAuthentication: routeRoute.RequestAuthentication, RateLimit: routeRoute.RateLimit, ExtensionRefs: routeRoute.ExtensionRefs, diff --git a/internal/gatewayapi/testdata/httproute-with-mirror-filter-duplicates.out.yaml b/internal/gatewayapi/testdata/httproute-with-mirror-filter-duplicates.out.yaml index 31bd037de61..e2196172de5 100644 --- a/internal/gatewayapi/testdata/httproute-with-mirror-filter-duplicates.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-mirror-filter-duplicates.out.yaml @@ -125,12 +125,17 @@ xdsIR: weight: 1 name: httproute/default/httproute-1/rule/0 hostname: gateway.envoyproxy.io - mirror: - endpoints: + mirrors: + - endpoints: + - host: 7.7.7.7 + port: 8080 + weight: 1 + name: httproute/default/httproute-1/rule/0-mirror-0 + - endpoints: - host: 7.7.7.7 port: 8080 weight: 1 - name: httproute/default/httproute-1/rule/0-mirror + name: httproute/default/httproute-1/rule/0-mirror-1 name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io pathMatch: distinct: false diff --git a/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.in.yaml b/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.in.yaml index 77bee0e1ee0..950db156b83 100644 --- a/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.in.yaml +++ b/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.in.yaml @@ -35,6 +35,18 @@ httpRoutes: - name: service-1 port: 8080 filters: + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Header-Set + value: set-overwrites-values + add: + - name: X-Header-Add + value: header-val-1 + - name: X-Header-Add-Append + value: header-val-2 + remove: + - X-Header-Remove - type: RequestMirror requestMirror: backendRef: diff --git a/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.out.yaml b/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.out.yaml index 29cbca920ba..faaf58c047f 100644 --- a/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-mirror-filter-multiple.out.yaml @@ -54,6 +54,18 @@ httpRoutes: - name: service-1 port: 8080 filters: + - requestHeaderModifier: + add: + - name: X-Header-Add + value: header-val-1 + - name: X-Header-Add-Append + value: header-val-2 + remove: + - X-Header-Remove + set: + - name: X-Header-Set + value: set-overwrites-values + type: RequestHeaderModifier - requestMirror: backendRef: kind: Service @@ -115,7 +127,17 @@ xdsIR: name: envoy-gateway/gateway-1/http port: 10080 routes: - - backendWeights: + - addRequestHeaders: + - append: true + name: X-Header-Add + value: header-val-1 + - append: true + name: X-Header-Add-Append + value: header-val-2 + - append: false + name: X-Header-Set + value: set-overwrites-values + backendWeights: invalid: 0 valid: 0 destination: @@ -125,17 +147,21 @@ xdsIR: weight: 1 name: httproute/default/httproute-1/rule/0 hostname: gateway.envoyproxy.io - mirror: - endpoints: + mirrors: + - endpoints: - host: 7.7.7.7 port: 8080 weight: 1 + name: httproute/default/httproute-1/rule/0-mirror-1 + - endpoints: - host: 7.6.5.4 port: 8080 weight: 1 - name: httproute/default/httproute-1/rule/0-mirror + name: httproute/default/httproute-1/rule/0-mirror-2 name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io pathMatch: distinct: false name: "" prefix: / + removeRequestHeaders: + - X-Header-Remove diff --git a/internal/gatewayapi/testdata/httproute-with-mirror-filter.out.yaml b/internal/gatewayapi/testdata/httproute-with-mirror-filter.out.yaml index 899a61902f7..5baa08a521a 100644 --- a/internal/gatewayapi/testdata/httproute-with-mirror-filter.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-mirror-filter.out.yaml @@ -119,12 +119,12 @@ xdsIR: weight: 1 name: httproute/default/httproute-1/rule/0 hostname: gateway.envoyproxy.io - mirror: - endpoints: + mirrors: + - endpoints: - host: 7.7.7.7 port: 8080 weight: 1 - name: httproute/default/httproute-1/rule/0-mirror + name: httproute/default/httproute-1/rule/0-mirror-0 name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io pathMatch: distinct: false diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 394f009bbdc..21333e20072 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -263,7 +263,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"` + Mirrors []*RouteDestination `json:"mirrors,omitempty" yaml:"mirrors,omitempty"` // Destination associated with this matched route. Destination *RouteDestination `json:"destination,omitempty" yaml:"destination,omitempty"` // Rewrite to be changed for this route. @@ -353,9 +353,11 @@ func (h HTTPRoute) Validate() error { errs = multierror.Append(errs, err) } } - if h.Mirror != nil { - if err := h.Mirror.Validate(); err != nil { - errs = multierror.Append(errs, err) + if h.Mirrors != nil { + for _, mirror := range h.Mirrors { + if err := mirror.Validate(); err != nil { + errs = multierror.Append(errs, err) + } } } if len(h.AddRequestHeaders) > 0 { diff --git a/internal/ir/xds_test.go b/internal/ir/xds_test.go index 16713749150..424cea3f59e 100644 --- a/internal/ir/xds_test.go +++ b/internal/ir/xds_test.go @@ -456,7 +456,7 @@ var ( PathMatch: &StringMatch{ Exact: ptrTo("mirrorfilter"), }, - Mirror: &happyRouteDestination, + Mirrors: []*RouteDestination{&happyRouteDestination}, } // RouteDestination diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index d4dd6a95572..3ad7888f181 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -319,10 +319,16 @@ func (in *HTTPRoute) DeepCopyInto(out *HTTPRoute) { *out = new(Redirect) (*in).DeepCopyInto(*out) } - if in.Mirror != nil { - in, out := &in.Mirror, &out.Mirror - *out = new(RouteDestination) - (*in).DeepCopyInto(*out) + if in.Mirrors != nil { + in, out := &in.Mirrors, &out.Mirrors + *out = make([]*RouteDestination, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RouteDestination) + (*in).DeepCopyInto(*out) + } + } } if in.Destination != nil { in, out := &in.Destination, &out.Destination diff --git a/internal/xds/translator/route.go b/internal/xds/translator/route.go index cfafdd9e9f0..bcbe33d7f17 100644 --- a/internal/xds/translator/route.go +++ b/internal/xds/translator/route.go @@ -43,8 +43,8 @@ func buildXdsRoute(httpRoute *ir.HTTPRoute) *routev3.Route { router.Action = &routev3.Route_Redirect{Redirect: buildXdsRedirectAction(httpRoute.Redirect)} case httpRoute.URLRewrite != nil: routeAction := buildXdsURLRewriteAction(httpRoute.Destination.Name, httpRoute.URLRewrite) - if httpRoute.Mirror != nil { - routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirror.Name) + if httpRoute.Mirrors != nil { + routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirrors) } router.Action = &routev3.Route_Route{Route: routeAction} @@ -52,14 +52,14 @@ func buildXdsRoute(httpRoute *ir.HTTPRoute) *routev3.Route { if httpRoute.BackendWeights.Invalid != 0 { // 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) + if httpRoute.Mirrors != nil { + routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirrors) } router.Action = &routev3.Route_Route{Route: routeAction} } else { routeAction := buildXdsRouteAction(httpRoute.Destination.Name) - if httpRoute.Mirror != nil { - routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirror.Name) + if httpRoute.Mirrors != nil { + routeAction.RequestMirrorPolicies = buildXdsRequestMirrorPolicies(httpRoute.Mirrors) } router.Action = &routev3.Route_Route{Route: routeAction} } @@ -292,11 +292,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 diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-multiple-mirrors.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-multiple-mirrors.yaml new file mode 100644 index 00000000000..8c3d0231ddb --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/http-route-multiple-mirrors.yaml @@ -0,0 +1,22 @@ +name: "http-route" +http: +- name: "first-listener" + address: "0.0.0.0" + port: 10080 + hostnames: + - "*" + routes: + - name: "mirror-route" + hostname: "*" + destination: + name: "route-dest" + endpoints: + - host: "1.2.3.4" + port: 50000 + mirrors: + - name: "mirror-route-dest" + endpoints: + - host: "2.3.4.5" + - name: "mirror-route-dest1" + endpoints: + - host: "3.4.5.6" diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.clusters.yaml index 4a16af1a2a0..dac161f28ea 100644 --- a/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.clusters.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.clusters.yaml @@ -11,16 +11,3 @@ outlierDetection: {} perConnectionBufferLimitBytes: 32768 type: EDS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: mirror-route-dest - name: mirror-route-dest - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.endpoints.yaml index a996ef4e46c..11974943f46 100644 --- a/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.endpoints.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.endpoints.yaml @@ -8,13 +8,3 @@ portValue: 50000 loadBalancingWeight: 1 locality: {} -- clusterName: mirror-route-dest - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 2.3.4.5 - portValue: 0 - loadBalancingWeight: 1 - locality: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.routes.yaml index 6beaecd65c5..c5f6e70b254 100644 --- a/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-mirror.routes.yaml @@ -10,5 +10,3 @@ name: mirror-route route: cluster: route-dest - requestMirrorPolicies: - - cluster: mirror-route-dest diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.clusters.yaml new file mode 100644 index 00000000000..a5b6e0b7641 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.clusters.yaml @@ -0,0 +1,39 @@ +- commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: route-dest + name: route-dest + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS +- commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: mirror-route-dest + name: mirror-route-dest + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS +- commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: mirror-route-dest1 + name: mirror-route-dest1 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.endpoints.yaml new file mode 100644 index 00000000000..ea28283b656 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.endpoints.yaml @@ -0,0 +1,30 @@ +- clusterName: route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + locality: {} +- clusterName: mirror-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 2.3.4.5 + portValue: 0 + loadBalancingWeight: 1 + locality: {} +- clusterName: mirror-route-dest1 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 3.4.5.6 + portValue: 0 + loadBalancingWeight: 1 + locality: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.listeners.yaml new file mode 100644 index 00000000000..73ee1b42ef6 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.listeners.yaml @@ -0,0 +1,33 @@ +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10080 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: first-listener + statPrefix: http + upgradeConfigs: + - upgradeType: websocket + useRemoteAddress: true + name: first-listener + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.routes.yaml new file mode 100644 index 00000000000..1429b4da64e --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-multiple-mirrors.routes.yaml @@ -0,0 +1,15 @@ +- ignorePortInHostMatching: true + name: first-listener + virtualHosts: + - domains: + - '*' + name: first-listener/* + routes: + - match: + prefix: / + name: mirror-route + route: + cluster: route-dest + requestMirrorPolicies: + - cluster: mirror-route-dest + - cluster: mirror-route-dest1 diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go index 38a546bf66c..3f2811ee4fd 100644 --- a/internal/xds/translator/translator.go +++ b/internal/xds/translator/translator.go @@ -222,15 +222,17 @@ 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 + if httpRoute.Mirrors != nil { + for _, mirrorDest := range httpRoute.Mirrors { + 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 + } } } } diff --git a/internal/xds/translator/translator_test.go b/internal/xds/translator/translator_test.go index 286b04dede5..219db64e628 100644 --- a/internal/xds/translator/translator_test.go +++ b/internal/xds/translator/translator_test.go @@ -62,6 +62,9 @@ func TestTranslateXds(t *testing.T) { { name: "http-route-mirror", }, + { + name: "http-route-multiple-mirrors", + }, { name: "http-route-multiple-matches", }, diff --git a/test/conformance/conformance_test.go b/test/conformance/conformance_test.go index f7f195a55e7..a46d251a8c5 100644 --- a/test/conformance/conformance_test.go +++ b/test/conformance/conformance_test.go @@ -45,11 +45,8 @@ func TestGatewayAPIConformance(t *testing.T) { Clientset: clientset, CleanupBaseResources: *flags.CleanupBaseResources, SupportedFeatures: suite.AllFeatures, - SkipTests: []string{ - // TODO: Remove once https://github.com/envoyproxy/gateway/issues/1811 is fixed - tests.HTTPRouteRequestMultipleMirrors.ShortName, - }, - ExemptFeatures: suite.MeshCoreFeatures, + SkipTests: []string{}, + ExemptFeatures: suite.MeshCoreFeatures, }) cSuite.Setup(t) cSuite.Run(t, tests.ConformanceTests) diff --git a/test/conformance/experimental_conformance_test.go b/test/conformance/experimental_conformance_test.go index ca5abffc2bd..ee6f061944a 100644 --- a/test/conformance/experimental_conformance_test.go +++ b/test/conformance/experimental_conformance_test.go @@ -92,11 +92,8 @@ func experimentalConformance(t *testing.T) { GatewayClassName: *flags.GatewayClassName, Debug: *flags.ShowDebug, CleanupBaseResources: *flags.CleanupBaseResources, - SkipTests: []string{ - // TODO: Remove once https://github.com/envoyproxy/gateway/issues/1811 is fixed - tests.HTTPRouteRequestMultipleMirrors.ShortName, - }, - SupportedFeatures: sets.Set[suite.SupportedFeature]{}.Insert(suite.HTTPRouteExtendedFeatures.UnsortedList()...), + SkipTests: []string{}, + SupportedFeatures: sets.Set[suite.SupportedFeature]{}.Insert(suite.HTTPRouteExtendedFeatures.UnsortedList()...), }, Implementation: *implementation, ConformanceProfiles: conformanceProfiles,