diff --git a/api/v1alpha1/loadbalancer_types.go b/api/v1alpha1/loadbalancer_types.go index 9fdaf26d5b4..3fd144bdfa1 100644 --- a/api/v1alpha1/loadbalancer_types.go +++ b/api/v1alpha1/loadbalancer_types.go @@ -71,7 +71,6 @@ type ConsistentHash struct { // Cookie configures the cookie hash policy when the consistent hash type is set to Cookie. // // +optional - // +notImplementedHide Cookie *Cookie `json:"cookie,omitempty"` // The table size for consistent hashing, must be prime number limited to 5000011. @@ -103,12 +102,10 @@ type Cookie struct { // Max-Age attribute value. // // +optional - // +notImplementedHide TTL *metav1.Duration `json:"ttl,omitempty"` // Additional Attributes to set for the generated cookie. // // +optional - // +notImplementedHide Attributes map[string]string `json:"attributes,omitempty"` } diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index bcc6a5507c2..9c9982e832c 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -864,6 +864,8 @@ func (t *Translator) buildConsistentHashLoadBalancer(policy *egv1a1.BackendTraff consistentHash.Header = &ir.Header{ Name: policy.Spec.LoadBalancer.ConsistentHash.Header.Name, } + case egv1a1.CookieConsistentHashType: + consistentHash.Cookie = policy.Spec.LoadBalancer.ConsistentHash.Cookie } return consistentHash, nil diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml index f8bb9de05eb..9da4a34e664 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml @@ -81,6 +81,25 @@ httpRoutes: backendRefs: - name: service-2 port: 8080 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-3 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-2 + sectionName: http + rules: + - matches: + - path: + value: "/test3" + backendRefs: + - name: service-2 + port: 8080 backendTrafficPolicies: - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy @@ -137,3 +156,19 @@ backendTrafficPolicies: type: LeastRequest slowStart: window: 300s +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: policy-for-route3 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-3 + loadBalancer: + type: ConsistentHash + consistentHash: + type: Cookie + cookie: + name: "test" diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml index d1891d88371..b2378edf754 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml @@ -60,6 +60,38 @@ backendTrafficPolicies: status: "True" type: Accepted controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: policy-for-route3 + namespace: default + spec: + loadBalancer: + consistentHash: + cookie: + name: test + type: Cookie + type: ConsistentHash + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-3 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy metadata: @@ -117,7 +149,7 @@ backendTrafficPolicies: type: Accepted - lastTransitionTime: null message: 'This policy is being overridden by other backendTrafficPolicies - for these routes: [default/httproute-1 default/httproute-2]' + for these routes: [default/httproute-1 default/httproute-2 default/httproute-3]' reason: Overridden status: "True" type: Overridden @@ -180,7 +212,7 @@ gateways: protocol: HTTP status: listeners: - - attachedRoutes: 2 + - attachedRoutes: 3 conditions: - lastTransitionTime: null message: Sending translated listener configuration to the data plane @@ -314,6 +346,44 @@ httpRoutes: name: gateway-2 namespace: envoy-gateway sectionName: http +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-3 + namespace: default + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-2 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-2 + port: 8080 + matches: + - path: + value: /test3 + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-2 + namespace: envoy-gateway + sectionName: http infraIR: envoy-gateway/gateway-1: proxy: @@ -430,6 +500,31 @@ xdsIR: leastRequest: slowStart: window: 5m0s + - destination: + name: httproute/default/httproute-3/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-3 + namespace: default + name: httproute/default/httproute-3/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: /test3 + traffic: + loadBalancer: + consistentHash: + cookie: + name: test - destination: name: httproute/default/httproute-1/rule/0 settings: diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 42704cffe75..8dc95e783cf 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -1795,9 +1795,10 @@ type Random struct{} // +k8s:deepcopy-gen=true type ConsistentHash struct { // Hash based on the Source IP Address - SourceIP *bool `json:"sourceIP,omitempty" yaml:"sourceIP,omitempty"` - Header *Header `json:"header,omitempty" yaml:"header,omitempty"` - TableSize *uint64 `json:"tableSize,omitempty" yaml:"tableSize,omitempty"` + SourceIP *bool `json:"sourceIP,omitempty" yaml:"sourceIP,omitempty"` + Header *Header `json:"header,omitempty" yaml:"header,omitempty"` + Cookie *egv1a1.Cookie `json:"cookie,omitempty" yaml:"cookie,omitempty"` + TableSize *uint64 `json:"tableSize,omitempty" yaml:"tableSize,omitempty"` } // Header consistent hash type settings diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 171c2c28d40..d76ea363c28 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -509,6 +509,11 @@ func (in *ConsistentHash) DeepCopyInto(out *ConsistentHash) { *out = new(Header) **out = **in } + if in.Cookie != nil { + in, out := &in.Cookie, &out.Cookie + *out = new(v1alpha1.Cookie) + (*in).DeepCopyInto(*out) + } if in.TableSize != nil { in, out := &in.TableSize, &out.TableSize *out = new(uint64) diff --git a/internal/xds/translator/route.go b/internal/xds/translator/route.go index ba1baa6c227..139b359a15a 100644 --- a/internal/xds/translator/route.go +++ b/internal/xds/translator/route.go @@ -493,6 +493,28 @@ func buildHashPolicy(httpRoute *ir.HTTPRoute) []*routev3.RouteAction_HashPolicy }, } return []*routev3.RouteAction_HashPolicy{hashPolicy} + case ch.Cookie != nil: + hashPolicy := &routev3.RouteAction_HashPolicy{ + PolicySpecifier: &routev3.RouteAction_HashPolicy_Cookie_{ + Cookie: &routev3.RouteAction_HashPolicy_Cookie{ + Name: ch.Cookie.Name, + }, + }, + } + if ch.Cookie.TTL != nil { + hashPolicy.GetCookie().Ttl = durationpb.New(ch.Cookie.TTL.Duration) + } + if ch.Cookie.Attributes != nil { + attributes := make([]*routev3.RouteAction_HashPolicy_CookieAttribute, len(ch.Cookie.Attributes)) + i := 0 + for name, value := range ch.Cookie.Attributes { + attributes[i].Name = name + attributes[i].Value = value + i++ + } + hashPolicy.GetCookie().Attributes = attributes + } + return []*routev3.RouteAction_HashPolicy{hashPolicy} case ch.SourceIP != nil: if !*ch.SourceIP { return nil diff --git a/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml b/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml index 3886f0cfd7d..998318fdb1d 100644 --- a/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml @@ -104,3 +104,16 @@ http: - endpoints: - host: "1.2.3.4" port: 50000 + - name: "ninth-route" + hostname: "*" + traffic: + loadBalancer: + consistentHash: + cookie: + name: "test" + destination: + name: "ninth-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 diff --git a/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml index 204667fb0b5..cc88feed937 100644 --- a/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml @@ -140,3 +140,20 @@ outlierDetection: {} perConnectionBufferLimitBytes: 32768 type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: ninth-route-dest + lbPolicy: MAGLEV + name: ninth-route-dest + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml index e262710c4f9..31d55310540 100644 --- a/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml @@ -94,3 +94,15 @@ loadBalancingWeight: 1 locality: region: eighth-route-dest/backend/0 +- clusterName: ninth-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: ninth-route-dest/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml index bb34436d3e1..8fcdb470f81 100644 --- a/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml @@ -67,3 +67,13 @@ cluster: eighth-route-dest upgradeConfigs: - upgradeType: websocket + - match: + prefix: / + name: ninth-route + route: + cluster: ninth-route-dest + hashPolicy: + - cookie: + name: test + upgradeConfigs: + - upgradeType: websocket diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 37a76398121..80f548228f9 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -755,6 +755,7 @@ _Appears in:_ | --- | --- | --- | --- | | `type` | _[ConsistentHashType](#consistenthashtype)_ | true | ConsistentHashType defines the type of input to hash on. Valid Type values are "SourceIP" or "Header". | | `header` | _[Header](#header)_ | false | Header configures the header hash policy when the consistent hash type is set to Header. | +| `cookie` | _[Cookie](#cookie)_ | false | Cookie configures the cookie hash policy when the consistent hash type is set to Cookie. | | `tableSize` | _integer_ | false | The table size for consistent hashing, must be prime number limited to 5000011. | @@ -787,6 +788,8 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | _string_ | true | Name of the cookie to hash.
If this cookie does not exist in the request, Envoy will generate a cookie and set
the TTL on the response back to the client based on Layer 4
attributes of the backend endpoint, to ensure that these future requests
go to the same backend endpoint. Make sure to set the TTL field for this case. | +| `ttl` | _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | false | TTL of the generated cookie if the cookie is not present. This value sets the
Max-Age attribute value. | +| `attributes` | _object (keys:string, values:string)_ | false | Additional Attributes to set for the generated cookie. | #### CustomHeaderExtensionSettings diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index 37a76398121..80f548228f9 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -755,6 +755,7 @@ _Appears in:_ | --- | --- | --- | --- | | `type` | _[ConsistentHashType](#consistenthashtype)_ | true | ConsistentHashType defines the type of input to hash on. Valid Type values are "SourceIP" or "Header". | | `header` | _[Header](#header)_ | false | Header configures the header hash policy when the consistent hash type is set to Header. | +| `cookie` | _[Cookie](#cookie)_ | false | Cookie configures the cookie hash policy when the consistent hash type is set to Cookie. | | `tableSize` | _integer_ | false | The table size for consistent hashing, must be prime number limited to 5000011. | @@ -787,6 +788,8 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | _string_ | true | Name of the cookie to hash.
If this cookie does not exist in the request, Envoy will generate a cookie and set
the TTL on the response back to the client based on Layer 4
attributes of the backend endpoint, to ensure that these future requests
go to the same backend endpoint. Make sure to set the TTL field for this case. | +| `ttl` | _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | false | TTL of the generated cookie if the cookie is not present. This value sets the
Max-Age attribute value. | +| `attributes` | _object (keys:string, values:string)_ | false | Additional Attributes to set for the generated cookie. | #### CustomHeaderExtensionSettings