From b90f81c09fe865bcac7e42f2349fa530b85482cc Mon Sep 17 00:00:00 2001 From: Harry Turton Date: Thu, 9 May 2024 09:23:58 +1000 Subject: [PATCH] feat(api): Add support for the header hash policy (#3342) * Make API changes Signed-off-by: Harry Turton * Add tests Signed-off-by: Harry Turton * Fixups Signed-off-by: Harry Turton * Fixup test compilation issues Signed-off-by: Harry Turton * Make ConsistentHash a union Signed-off-by: Harry Turton * Remove redundant TargetRef from tests Signed-off-by: Harry Turton * Revert test change Signed-off-by: Harry Turton * Add target ref back Signed-off-by: Harry Turton * Code review and fix tests Signed-off-by: Harry Turton * Regen charts Signed-off-by: Harry Turton * Propagate HeaderName to Header change to the json field Signed-off-by: Harry Turton * Generate code Signed-off-by: Harry Turton * Regen manifests Signed-off-by: Harry Turton * Add +notImplementedHide on Header Signed-off-by: Harry Turton --- api/v1alpha1/loadbalancer_types.go | 27 +++++++++-- api/v1alpha1/zz_generated.deepcopy.go | 22 ++++++++- ....envoyproxy.io_backendtrafficpolicies.yaml | 20 ++++++-- site/content/en/latest/api/extension_types.md | 22 +++++++-- .../backendtrafficpolicy_test.go | 47 +++++++++++++++++++ 5 files changed, 128 insertions(+), 10 deletions(-) diff --git a/api/v1alpha1/loadbalancer_types.go b/api/v1alpha1/loadbalancer_types.go index 3bd4d9c4e54..2a0fb21e515 100644 --- a/api/v1alpha1/loadbalancer_types.go +++ b/api/v1alpha1/loadbalancer_types.go @@ -18,7 +18,7 @@ type LoadBalancer struct { // "ConsistentHash", // "LeastRequest", // "Random", - // "RoundRobin", + // "RoundRobin". // // +unionDiscriminator Type LoadBalancerType `json:"type"` @@ -52,18 +52,39 @@ const ( ) // ConsistentHash defines the configuration related to the consistent hash -// load balancer policy +// load balancer policy. +// +union +// +// +kubebuilder:validation:XValidation:rule="self.type == 'Header' ? has(self.header) : !has(self.header)",message="If consistent hash type is header, the header field must be set." type ConsistentHash struct { + // Valid Type values are "SourceIP". + // + // +unionDiscriminator Type ConsistentHashType `json:"type"` + + // Header configures the header hash policy when the consistent hash type is set to Header. + // + // +optional + // +notImplementedHide + Header *Header `json:"header,omitempty"` +} + +// Header defines the header hashing configuration for consistent hash based +// load balancing. +type Header struct { + // Name of the header to hash. + Name string `json:"name"` } // ConsistentHashType defines the type of input to hash on. -// +kubebuilder:validation:Enum=SourceIP +// +kubebuilder:validation:Enum=SourceIP;Header type ConsistentHashType string const ( // SourceIPConsistentHashType hashes based on the source IP address. SourceIPConsistentHashType ConsistentHashType = "SourceIP" + // HeaderConsistentHashType hashes based on a request header. + HeaderConsistentHashType ConsistentHashType = "Header" ) // SlowStart defines the configuration related to the slow start load balancer policy. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 8ebd4453c5c..71f09022f35 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -751,6 +751,11 @@ func (in *ConnectionLimit) DeepCopy() *ConnectionLimit { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ConsistentHash) DeepCopyInto(out *ConsistentHash) { *out = *in + if in.Header != nil { + in, out := &in.Header, &out.Header + *out = new(Header) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConsistentHash. @@ -2225,6 +2230,21 @@ func (in *HTTPWasmCodeSource) DeepCopy() *HTTPWasmCodeSource { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Header) DeepCopyInto(out *Header) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Header. +func (in *Header) DeepCopy() *Header { + if in == nil { + return nil + } + out := new(Header) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HeaderMatch) DeepCopyInto(out *HeaderMatch) { *out = *in @@ -2865,7 +2885,7 @@ func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { if in.ConsistentHash != nil { in, out := &in.ConsistentHash, &out.ConsistentHash *out = new(ConsistentHash) - **out = **in + (*in).DeepCopyInto(*out) } if in.SlowStart != nil { in, out := &in.SlowStart, &out.SlowStart diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index eb8457a116b..ba195c65408 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -412,15 +412,29 @@ spec: ConsistentHash defines the configuration when the load balancer type is set to ConsistentHash properties: + header: + description: Header configures the header hash policy when + the consistent hash type is set to Header. + properties: + name: + description: Name of the header to hash. + type: string + required: + - name + type: object type: - description: ConsistentHashType defines the type of input - to hash on. + description: Valid Type values are "SourceIP". enum: - SourceIP + - Header type: string required: - type type: object + x-kubernetes-validations: + - message: If consistent hash type is header, the header field + must be set. + rule: 'self.type == ''Header'' ? has(self.header) : !has(self.header)' slowStart: description: |- SlowStart defines the configuration related to the slow start load balancer policy. @@ -444,7 +458,7 @@ spec: "ConsistentHash", "LeastRequest", "Random", - "RoundRobin", + "RoundRobin". enum: - ConsistentHash - LeastRequest diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index c00e9d8a915..cb74c44f487 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -555,14 +555,14 @@ _Appears in:_ ConsistentHash defines the configuration related to the consistent hash -load balancer policy +load balancer policy. _Appears in:_ - [LoadBalancer](#loadbalancer) | Field | Type | Required | Description | | --- | --- | --- | --- | -| `type` | _[ConsistentHashType](#consistenthashtype)_ | true | | +| `type` | _[ConsistentHashType](#consistenthashtype)_ | true | Valid Type values are "SourceIP". | #### ConsistentHashType @@ -577,6 +577,7 @@ _Appears in:_ | Value | Description | | ----- | ----------- | | `SourceIP` | SourceIPConsistentHashType hashes based on the source IP address.
| +| `Header` | HeaderConsistentHashType hashes based on a request header.
| #### CustomHeaderExtensionSettings @@ -1624,6 +1625,21 @@ _Appears in:_ | `url` | _string_ | true | URL is the URL containing the wasm code. | +#### Header + + + +Header defines the header hashing configuration for consistent hash based +load balancing. + +_Appears in:_ +- [ConsistentHash](#consistenthash) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `name` | _string_ | true | Name of the header to hash. | + + #### HeaderMatchType @@ -2018,7 +2034,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | -| `type` | _[LoadBalancerType](#loadbalancertype)_ | true | Type decides the type of Load Balancer policy.
Valid LoadBalancerType values are
"ConsistentHash",
"LeastRequest",
"Random",
"RoundRobin", | +| `type` | _[LoadBalancerType](#loadbalancertype)_ | true | Type decides the type of Load Balancer policy.
Valid LoadBalancerType values are
"ConsistentHash",
"LeastRequest",
"Random",
"RoundRobin". | | `consistentHash` | _[ConsistentHash](#consistenthash)_ | false | ConsistentHash defines the configuration when the load balancer type is
set to ConsistentHash | | `slowStart` | _[SlowStart](#slowstart)_ | false | SlowStart defines the configuration related to the slow start load balancer policy.
If set, during slow start window, traffic sent to the newly added hosts will gradually increase.
Currently this is only supported for RoundRobin and LeastRequest load balancers | diff --git a/test/cel-validation/backendtrafficpolicy_test.go b/test/cel-validation/backendtrafficpolicy_test.go index a1dd7ac7eb7..187fae39929 100644 --- a/test/cel-validation/backendtrafficpolicy_test.go +++ b/test/cel-validation/backendtrafficpolicy_test.go @@ -194,6 +194,53 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { "spec.loadBalancer: Invalid value: \"object\": If LoadBalancer type is consistentHash, consistentHash field needs to be set", }, }, + { + desc: "consistentHash header field not nil when consistentHashType is header", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.LocalPolicyTargetReferenceWithSectionName{ + LocalPolicyTargetReference: gwapiv1a2.LocalPolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.ConsistentHashLoadBalancerType, + ConsistentHash: &egv1a1.ConsistentHash{ + Type: "Header", + Header: &egv1a1.Header{ + Name: "name", + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "consistentHash header field nil when consistentHashType is header", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.LocalPolicyTargetReferenceWithSectionName{ + LocalPolicyTargetReference: gwapiv1a2.LocalPolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.ConsistentHashLoadBalancerType, + ConsistentHash: &egv1a1.ConsistentHash{ + Type: "Header", + }, + }, + } + }, + wantErrors: []string{ + "spec.loadBalancer.consistentHash: Invalid value: \"object\": If consistent hash type is header, the header field must be set", + }, + }, { desc: "leastRequest with ConsistentHash nil", mutate: func(btp *egv1a1.BackendTrafficPolicy) {