diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index cfc2272a64f..584ff4a002a 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -1426,7 +1426,7 @@ func (t *Translator) processDestination(name string, backendRefContext BackendRe ds = t.processServiceDestinationSetting(name, backendRef.BackendObjectReference, backendNamespace, protocol, resources, envoyProxy) svc := resources.GetService(backendNamespace, string(backendRef.Name)) ds.IPFamily = getServiceIPFamily(svc) - ds.ZoneAwareRouting = processZoneAwareRouting(svc) + ds.PreferLocal = processPreferLocalZone(svc) case egv1a1.KindBackend: ds = t.processBackendDestinationSetting(name, backendRef.BackendObjectReference, backendNamespace, protocol, resources) @@ -1599,12 +1599,12 @@ func (t *Translator) processServiceDestinationSetting( } return &ir.DestinationSetting{ - Name: name, - Protocol: protocol, - Endpoints: endpoints, - AddressType: addrType, - ZoneAwareRouting: processZoneAwareRouting(service), - Metadata: buildResourceMetadata(service, ptr.To(gwapiv1.SectionName(strconv.Itoa(int(*backendRef.Port))))), + Name: name, + Protocol: protocol, + Endpoints: endpoints, + AddressType: addrType, + PreferLocal: processPreferLocalZone(service), + Metadata: buildResourceMetadata(service, ptr.To(gwapiv1.SectionName(strconv.Itoa(int(*backendRef.Port))))), } } @@ -1624,14 +1624,17 @@ func getBackendFilters(routeType gwapiv1.Kind, backendRefContext BackendRefConte return nil } -func processZoneAwareRouting(svc *corev1.Service) *ir.ZoneAwareRouting { +func processPreferLocalZone(svc *corev1.Service) *ir.PreferLocalZone { if svc == nil { return nil } if trafficDist := svc.Spec.TrafficDistribution; trafficDist != nil { - return &ir.ZoneAwareRouting{ - MinSize: 1, + return &ir.PreferLocalZone{ + MinEndpointsThreshold: ptr.To[uint64](1), + Force: &ir.ForceLocalZone{ + MinEndpointsInZoneThreshold: ptr.To[uint32](1), + }, } } @@ -1640,8 +1643,11 @@ func processZoneAwareRouting(svc *corev1.Service) *ir.ZoneAwareRouting { // https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/#enabling-topology-aware-routing // https://github.com/kubernetes/kubernetes/blob/9d9e1afdf78bce0a517cc22557457f942040ca19/staging/src/k8s.io/endpointslice/utils.go#L355-L368 if val, ok := svc.Annotations[corev1.AnnotationTopologyMode]; ok && val == "Auto" || val == "auto" { - return &ir.ZoneAwareRouting{ - MinSize: 3, + return &ir.PreferLocalZone{ + MinEndpointsThreshold: ptr.To[uint64](3), + Force: &ir.ForceLocalZone{ + MinEndpointsInZoneThreshold: ptr.To[uint32](3), + }, } } diff --git a/internal/gatewayapi/testdata/httproute-with-enable-zone-discovery.out.yaml b/internal/gatewayapi/testdata/httproute-with-enable-zone-discovery.out.yaml index 726f5863567..d3cbb6688d0 100644 --- a/internal/gatewayapi/testdata/httproute-with-enable-zone-discovery.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-enable-zone-discovery.out.yaml @@ -157,10 +157,12 @@ xdsIR: namespace: default sectionName: "8080" name: httproute/default/httproute-1/rule/1/backend/0 + preferLocal: + force: + minEndpointsInZoneThreshold: 1 + minEndpointsThreshold: 1 protocol: HTTP weight: 1 - zoneAwareRouting: - minSize: 1 headerMatches: - distinct: false exact: bar @@ -195,10 +197,12 @@ xdsIR: namespace: default sectionName: "8080" name: httproute/default/httproute-1/rule/0/backend/0 + preferLocal: + force: + minEndpointsInZoneThreshold: 1 + minEndpointsThreshold: 1 protocol: HTTP weight: 1 - zoneAwareRouting: - minSize: 1 hostname: '*' isHTTP2: false metadata: diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 1e0ba51dea4..23b88b2eae1 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -832,6 +832,15 @@ func (h *HTTPRoute) GetRetry() *Retry { return nil } +func (h *HTTPRoute) NeedsClusterPerSetting() bool { + if h.Traffic != nil && + h.Traffic.LoadBalancer != nil && + h.Traffic.LoadBalancer.PreferLocal != nil { + return true + } + return h.Destination.NeedsClusterPerSetting() +} + // DNS contains configuration options for DNS resolution. // +k8s:deepcopy-gen=true type DNS struct { @@ -1582,7 +1591,7 @@ func (r *RouteDestination) Validate() error { func (r *RouteDestination) NeedsClusterPerSetting() bool { return r.HasMixedEndpoints() || r.HasFiltersInSettings() || - (len(r.Settings) > 1 && r.HasZoneAwareRouting()) + (len(r.Settings) > 1 && r.HasPreferLocalZone()) } // HasMixedEndpoints returns true if the RouteDestination has endpoints of multiple types @@ -1607,10 +1616,10 @@ func (r *RouteDestination) HasFiltersInSettings() bool { return false } -// HasZoneAwareRouting returns true if any setting in the destination has ZoneAwareRoutingEnabled set -func (r *RouteDestination) HasZoneAwareRouting() bool { +// HasPreferLocalZone returns true if any setting in the destination has PreferLocalZone set +func (r *RouteDestination) HasPreferLocalZone() bool { for _, setting := range r.Settings { - if setting.ZoneAwareRouting != nil { + if setting.PreferLocal != nil { return true } } @@ -1673,11 +1682,9 @@ type DestinationSetting struct { IPFamily *egv1a1.IPFamily `json:"ipFamily,omitempty" yaml:"ipFamily,omitempty"` TLS *TLSUpstreamConfig `json:"tls,omitempty" yaml:"tls,omitempty"` Filters *DestinationFilters `json:"filters,omitempty" yaml:"filters,omitempty"` - // ZoneAwareRouting specifies whether to enable Zone Aware Routing for this destination's endpoints. + // PreferLocal specifies whether to enable Zone Aware Routing for this destination's endpoints. // This is derived from the backend service and depends on having Kubernetes Topology Aware Routing or Traffic Distribution enabled. - // - // +optional - ZoneAwareRouting *ZoneAwareRouting `json:"zoneAwareRouting,omitempty" yaml:"zoneAwareRouting,omitempty"` + PreferLocal *PreferLocalZone `json:"preferLocal,omitempty" yaml:"preferLocal,omitempty"` // Metadata is used to enrich envoy route metadata with user and provider-specific information // The primary metadata for DestinationSettings comes from the Backend resource reference in BackendRef Metadata *ResourceMetadata `json:"metadata,omitempty" yaml:"metadata,omitempty"` @@ -2523,6 +2530,8 @@ type LoadBalancer struct { Random *Random `json:"random,omitempty" yaml:"random,omitempty"` // ConsistentHash load balancer policy ConsistentHash *ConsistentHash `json:"consistentHash,omitempty" yaml:"consistentHash,omitempty"` + // PreferLocal defines the configuration related to the distribution of requests between locality zones. + PreferLocal *PreferLocalZone `json:"preferLocal,omitempty" yaml:"preferLocal,omitempty"` } // Validate the fields within the LoadBalancer structure @@ -3203,8 +3212,21 @@ type RequestBuffer struct { Limit resource.Quantity `json:"limit" yaml:"limit"` } -// ZoneAwareRouting holds the zone aware routing configuration +// PreferLocalZone configures zone-aware routing to prefer sending traffic to the local locality zone. +// +k8s:deepcopy-gen=true +type PreferLocalZone struct { + // ForceLocalZone defines override configuration for forcing all traffic to stay within the local zone instead of the default behavior + // which maintains equal distribution among upstream endpoints while sending as much traffic as possible locally. + Force *ForceLocalZone `json:"force,omitempty" yaml:"force,omitempty"` + // MinEndpointsThreshold is the minimum number of total upstream endpoints across all zones required to enable zone-aware routing. + MinEndpointsThreshold *uint64 `json:"minEndpointsThreshold,omitempty" yaml:"minEndpointsThreshold,omitempty"` +} + +// ForceLocalZone defines override configuration for forcing all traffic to stay within the local zone instead of the default behavior +// which maintains equal distribution among upstream endpoints while sending as much traffic as possible locally. // +k8s:deepcopy-gen=true -type ZoneAwareRouting struct { - MinSize int `json:"minSize" yaml:"minSize"` +type ForceLocalZone struct { + // MinEndpointsInZoneThreshold is the minimum number of upstream endpoints in the local zone required to honor the forceLocalZone + // override. This is useful for protecting zones with fewer endpoints. + MinEndpointsInZoneThreshold *uint32 `json:"minEndpointsInZoneThreshold,omitempty" yaml:"minEndpointsInZoneThreshold,omitempty"` } diff --git a/internal/ir/xds_test.go b/internal/ir/xds_test.go index 9ad48cbcf61..6cebc99dc6c 100644 --- a/internal/ir/xds_test.go +++ b/internal/ir/xds_test.go @@ -1125,8 +1125,10 @@ func TestRouteDestination_NeedsClusterPerSetting(t *testing.T) { Port: 8080, }, }, - AddressType: ptr.To(FQDN), - ZoneAwareRouting: &ZoneAwareRouting{MinSize: 1}, + AddressType: ptr.To(FQDN), + PreferLocal: &PreferLocalZone{ + Force: &ForceLocalZone{MinEndpointsInZoneThreshold: ptr.To[uint32](1)}, + }, }, { Endpoints: []*DestinationEndpoint{ @@ -1153,8 +1155,10 @@ func TestRouteDestination_NeedsClusterPerSetting(t *testing.T) { Port: 8080, }, }, - AddressType: ptr.To(FQDN), - ZoneAwareRouting: &ZoneAwareRouting{MinSize: 1}, + AddressType: ptr.To(FQDN), + PreferLocal: &PreferLocalZone{ + Force: &ForceLocalZone{MinEndpointsInZoneThreshold: ptr.To[uint32](1)}, + }, }, }, }, diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index e1d2c936c5f..9de0acea3df 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -960,10 +960,10 @@ func (in *DestinationSetting) DeepCopyInto(out *DestinationSetting) { *out = new(DestinationFilters) (*in).DeepCopyInto(*out) } - if in.ZoneAwareRouting != nil { - in, out := &in.ZoneAwareRouting, &out.ZoneAwareRouting - *out = new(ZoneAwareRouting) - **out = **in + if in.PreferLocal != nil { + in, out := &in.PreferLocal, &out.PreferLocal + *out = new(PreferLocalZone) + (*in).DeepCopyInto(*out) } if in.Metadata != nil { in, out := &in.Metadata, &out.Metadata @@ -1307,6 +1307,26 @@ func (in *FaultInjectionDelay) DeepCopy() *FaultInjectionDelay { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ForceLocalZone) DeepCopyInto(out *ForceLocalZone) { + *out = *in + if in.MinEndpointsInZoneThreshold != nil { + in, out := &in.MinEndpointsInZoneThreshold, &out.MinEndpointsInZoneThreshold + *out = new(uint32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ForceLocalZone. +func (in *ForceLocalZone) DeepCopy() *ForceLocalZone { + if in == nil { + return nil + } + out := new(ForceLocalZone) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GRPCExtAuthService) DeepCopyInto(out *GRPCExtAuthService) { *out = *in @@ -2295,6 +2315,11 @@ func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { *out = new(ConsistentHash) (*in).DeepCopyInto(*out) } + if in.PreferLocal != nil { + in, out := &in.PreferLocal, &out.PreferLocal + *out = new(PreferLocalZone) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancer. @@ -2650,6 +2675,31 @@ func (in *PerRetryPolicy) DeepCopy() *PerRetryPolicy { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PreferLocalZone) DeepCopyInto(out *PreferLocalZone) { + *out = *in + if in.Force != nil { + in, out := &in.Force, &out.Force + *out = new(ForceLocalZone) + (*in).DeepCopyInto(*out) + } + if in.MinEndpointsThreshold != nil { + in, out := &in.MinEndpointsThreshold, &out.MinEndpointsThreshold + *out = new(uint64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PreferLocalZone. +func (in *PreferLocalZone) DeepCopy() *PreferLocalZone { + if in == nil { + return nil + } + out := new(PreferLocalZone) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Principal) DeepCopyInto(out *Principal) { *out = *in @@ -4261,18 +4311,3 @@ func (in *Xds) DeepCopy() *Xds { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ZoneAwareRouting) DeepCopyInto(out *ZoneAwareRouting) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZoneAwareRouting. -func (in *ZoneAwareRouting) DeepCopy() *ZoneAwareRouting { - if in == nil { - return nil - } - out := new(ZoneAwareRouting) - in.DeepCopyInto(out) - return out -} diff --git a/internal/xds/translator/cluster.go b/internal/xds/translator/cluster.go index 78378ea0893..a17a4b771f8 100644 --- a/internal/xds/translator/cluster.go +++ b/internal/xds/translator/cluster.go @@ -228,25 +228,7 @@ func buildXdsCluster(args *xdsClusterArgs) (*buildClusterResult, error) { cluster.TypedExtensionProtocolOptions = epo } - // Set default localityLbConfig - localityLbConfig := &commonv3.LocalityLbConfig{ - LocalityConfigSpecifier: &commonv3.LocalityLbConfig_LocalityWeightedLbConfig_{ - LocalityWeightedLbConfig: &commonv3.LocalityLbConfig_LocalityWeightedLbConfig{}, - }, - } - - // Override LocalityWeightedLbConfig if zone aware routing is enabled. - // Zone aware enabled backendRefs always have a single DestinationSetting per-cluster. - if len(args.settings) == 1 && args.settings[0].ZoneAwareRouting != nil { - localityLbConfig.LocalityConfigSpecifier = &commonv3.LocalityLbConfig_ZoneAwareLbConfig_{ - ZoneAwareLbConfig: &commonv3.LocalityLbConfig_ZoneAwareLbConfig{ - MinClusterSize: wrapperspb.UInt64(1), - ForceLocalZone: &commonv3.LocalityLbConfig_ZoneAwareLbConfig_ForceLocalZone{ - MinSize: wrapperspb.UInt32(uint32(args.settings[0].ZoneAwareRouting.MinSize)), - }, - }, - } - } + localityLbConfig := buildLocalityLbConfig(args) // Set Load Balancer policy //nolint:gocritic @@ -439,6 +421,48 @@ func buildXdsCluster(args *xdsClusterArgs) (*buildClusterResult, error) { }, nil } +func buildLocalityLbConfig(args *xdsClusterArgs) *commonv3.LocalityLbConfig { + // Default to LocalityWeightedLbConfig + localityLbConfig := &commonv3.LocalityLbConfig{ + LocalityConfigSpecifier: &commonv3.LocalityLbConfig_LocalityWeightedLbConfig_{ + LocalityWeightedLbConfig: &commonv3.LocalityLbConfig_LocalityWeightedLbConfig{}, + }, + } + + // Check for LoadBalancer.PreferLocal configuration or if backendRef enables + // PreferLocal (such as Topology Aware Routing or Traffic Distribution) + if preferLocal := ptr.Deref(args.loadBalancer, ir.LoadBalancer{}).PreferLocal; preferLocal != nil { + if cfg := buildZoneAwareLbConfig(preferLocal); cfg != nil { + localityLbConfig.LocalityConfigSpecifier = cfg + } + // Zone aware enabled backendRefs use weighted clusters and + // always have a single DestinationSetting per-cluster. + } else if len(args.settings) == 1 && args.settings[0].PreferLocal != nil { + if cfg := buildZoneAwareLbConfig(args.settings[0].PreferLocal); cfg != nil { + localityLbConfig.LocalityConfigSpecifier = cfg + } + } + + return localityLbConfig +} + +func buildZoneAwareLbConfig(preferLocal *ir.PreferLocalZone) *commonv3.LocalityLbConfig_ZoneAwareLbConfig_ { + if preferLocal == nil { + return nil + } + lbConfig := &commonv3.LocalityLbConfig_ZoneAwareLbConfig_{ + ZoneAwareLbConfig: &commonv3.LocalityLbConfig_ZoneAwareLbConfig{ + MinClusterSize: wrapperspb.UInt64(ptr.Deref(preferLocal.MinEndpointsThreshold, 6)), + }, + } + if preferLocal.Force != nil { + lbConfig.ZoneAwareLbConfig.ForceLocalZone = &commonv3.LocalityLbConfig_ZoneAwareLbConfig_ForceLocalZone{ + MinSize: wrapperspb.UInt32(ptr.Deref(preferLocal.Force.MinEndpointsInZoneThreshold, 1)), + } + } + return lbConfig +} + func buildXdsHealthCheck(healthcheck *ir.ActiveHealthCheck) []*corev3.HealthCheck { hc := &corev3.HealthCheck{ Timeout: durationpb.New(healthcheck.Timeout.Duration), @@ -650,7 +674,7 @@ func buildXdsClusterLoadAssignment(clusterName string, destSettings []*ir.Destin // if multiple backendRefs exist. This pushes part of the routing logic higher up the stack which can // limit host selection controls during retries and session affinity. // For more details see https://github.com/envoyproxy/gateway/issues/5307#issuecomment-2688767482 - if ds.ZoneAwareRouting != nil { + if ds.PreferLocal != nil { localities = append(localities, buildZonalLocalities(metadata, ds)...) } else { localities = append(localities, buildWeightedLocalities(metadata, ds)) diff --git a/internal/xds/translator/route.go b/internal/xds/translator/route.go index 0a49d44611c..f07f80d8ea0 100644 --- a/internal/xds/translator/route.go +++ b/internal/xds/translator/route.go @@ -83,8 +83,7 @@ func buildXdsRoute(httpRoute *ir.HTTPRoute, httpListener *ir.HTTPListener) (*rou router.Action = &routev3.Route_Route{Route: routeAction} default: - backendWeights := httpRoute.Destination.ToBackendWeights() - routeAction := buildXdsRouteAction(backendWeights, httpRoute.Destination) + routeAction := buildXdsRouteAction(httpRoute) routeAction.IdleTimeout = idleTimeout(httpRoute) if httpRoute.Mirrors != nil { @@ -285,10 +284,11 @@ func buildXdsStringMatcher(irMatch *ir.StringMatch) *matcherv3.StringMatcher { return stringMatcher } -func buildXdsRouteAction(backendWeights *ir.BackendWeights, dest *ir.RouteDestination) *routev3.RouteAction { +func buildXdsRouteAction(route *ir.HTTPRoute) *routev3.RouteAction { + backendWeights := route.Destination.ToBackendWeights() // only use weighted cluster when there are invalid weights - if dest.NeedsClusterPerSetting() || backendWeights.Invalid != 0 { - return buildXdsWeightedRouteAction(backendWeights, dest.Settings) + if route.NeedsClusterPerSetting() || backendWeights.Invalid != 0 { + return buildXdsWeightedRouteAction(backendWeights, route.Destination.Settings) } return &routev3.RouteAction{ diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-lb-routing.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-lb-routing.yaml new file mode 100644 index 00000000000..f26259fc885 --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-lb-routing.yaml @@ -0,0 +1,67 @@ +http: +- name: "first-listener" + address: "::" + port: 10080 + hostnames: + - "*" + routes: + - name: "route-with-settings-preferlocal" + hostname: "*" + destination: + name: "route-with-settings-preferlocal-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 8080 + zone: us-east-1a + - host: "2.3.4.5" + port: 8080 + zone: us-east-1b + name: "route-with-settings-preferlocal/backend/0" + weight: 30 + preferLocal: + minEndpointsThreshold: 1 + force: + minEndpointsInZoneThreshold: 1 + - name: "route-with-lb-preferlocal" + hostname: "*" + destination: + name: "route-with-lb-preferlocal-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 8080 + zone: us-east-1a + - host: "2.3.4.5" + port: 8080 + zone: us-east-1b + name: "route-with-lb-preferlocal-dest/backend/0" + weight: 30 + traffic: + loadBalancer: + leastRequest: {} + preferLocal: + minEndpointsThreshold: 3 + - name: "route-with-lb-and-settings-preferlocal" + hostname: "*" + destination: + name: "route-with-lb-and-settings-preferlocal-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 8080 + zone: us-east-1a + - host: "2.3.4.5" + port: 8080 + zone: us-east-1b + name: "route-with-lb-and-settings-preferlocal-dest/backend/0" + weight: 30 + preferLocal: + minEndpointsThreshold: 1 + force: + minEndpointsInZoneThreshold: 1 + traffic: + loadBalancer: + leastRequest: {} + preferLocal: + minEndpointsThreshold: 3 diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-routing-weighted-clusters.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-routing-weighted-clusters.yaml index fb9c0c6fc1c..666d55f8fe7 100644 --- a/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-routing-weighted-clusters.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-routing-weighted-clusters.yaml @@ -19,8 +19,10 @@ http: zone: us-east-1b name: "first-route-dest/backend/0" weight: 30 - zoneAwareRouting: - minSize: 1 + preferLocal: + force: + minEndpointsInZoneThreshold: 1 + minEndpointsThreshold: 1 - endpoints: - host: "3.4.5.6" port: 9090 diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-routing.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-routing.yaml index 37d103aed20..ffd776b0670 100644 --- a/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-routing.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/http-route-zonal-routing.yaml @@ -19,5 +19,7 @@ http: zone: us-east-1b name: "first-route-dest/backend/0" weight: 30 - zoneAwareRouting: - minSize: 1 + preferLocal: + force: + minEndpointsInZoneThreshold: 1 + minEndpointsThreshold: 1 diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.clusters.yaml new file mode 100644 index 00000000000..50cd448cd20 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.clusters.yaml @@ -0,0 +1,77 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: route-with-settings-preferlocal-dest + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + zoneAwareLbConfig: + forceLocalZone: + minSize: 1 + minClusterSize: "1" + name: route-with-settings-preferlocal-dest + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: route-with-lb-preferlocal-dest/backend/0 + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + zoneAwareLbConfig: + minClusterSize: "3" + name: route-with-lb-preferlocal-dest/backend/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: route-with-lb-and-settings-preferlocal-dest/backend/0 + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + zoneAwareLbConfig: + minClusterSize: "3" + name: route-with-lb-and-settings-preferlocal-dest/backend/0 + perConnectionBufferLimitBytes: 32768 + type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.endpoints.yaml new file mode 100644 index 00000000000..9ad2673fed3 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.endpoints.yaml @@ -0,0 +1,58 @@ +- clusterName: route-with-settings-preferlocal-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 8080 + loadBalancingWeight: 1 + locality: + zone: us-east-1a + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 2.3.4.5 + portValue: 8080 + loadBalancingWeight: 1 + locality: + zone: us-east-1b +- clusterName: route-with-lb-preferlocal-dest/backend/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 8080 + loadBalancingWeight: 1 + - endpoint: + address: + socketAddress: + address: 2.3.4.5 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 30 + locality: + region: route-with-lb-preferlocal-dest/backend/0 +- clusterName: route-with-lb-and-settings-preferlocal-dest/backend/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 8080 + loadBalancingWeight: 1 + locality: + zone: us-east-1a + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 2.3.4.5 + portValue: 8080 + loadBalancingWeight: 1 + locality: + zone: us-east-1b diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.listeners.yaml new file mode 100644 index 00000000000..5c7db41545a --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.listeners.yaml @@ -0,0 +1,33 @@ +- address: + socketAddress: + address: '::' + 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 + suppressEnvoyHeaders: true + normalizePath: true + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: first-listener + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: first-listener + maxConnectionsToAcceptPerSocketEvent: 1 + name: first-listener + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.routes.yaml new file mode 100644 index 00000000000..c6b19600c09 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/http-route-zonal-lb-routing.routes.yaml @@ -0,0 +1,36 @@ +- ignorePortInHostMatching: true + name: first-listener + virtualHosts: + - domains: + - '*' + name: first-listener/* + routes: + - match: + prefix: / + name: route-with-settings-preferlocal + route: + cluster: route-with-settings-preferlocal-dest + upgradeConfigs: + - upgradeType: websocket + - match: + prefix: / + name: route-with-lb-preferlocal + route: + clusterNotFoundResponseCode: INTERNAL_SERVER_ERROR + upgradeConfigs: + - upgradeType: websocket + weightedClusters: + clusters: + - name: route-with-lb-preferlocal-dest/backend/0 + weight: 30 + - match: + prefix: / + name: route-with-lb-and-settings-preferlocal + route: + clusterNotFoundResponseCode: INTERNAL_SERVER_ERROR + upgradeConfigs: + - upgradeType: websocket + weightedClusters: + clusters: + - name: route-with-lb-and-settings-preferlocal-dest/backend/0 + weight: 30 diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go index 27b36397b13..acecd45e567 100644 --- a/internal/xds/translator/translator.go +++ b/internal/xds/translator/translator.go @@ -566,9 +566,10 @@ func (t *Translator) addRouteToRouteConfig( } var err error - // If there are no filters in the destination settings we create - // a regular xds Cluster - if !httpRoute.Destination.NeedsClusterPerSetting() { + // If there are no filters in the destination + // settings and ZoneAware routing isn't + // enabled we create a regular xds Cluster + if !httpRoute.NeedsClusterPerSetting() { err = processXdsCluster( tCtx, httpRoute.Destination.Name,