From 64d7152cb78383b7e06d9f38848847c4bad16547 Mon Sep 17 00:00:00 2001 From: Guy Daich Date: Tue, 19 Dec 2023 17:19:13 -0600 Subject: [PATCH] API: Support Circuit Breakers in BackendTrafficPolicy (#2284) * API: Support Circuit Breakers in BackendTrafficPolicy Signed-off-by: Guy Daich * reivew fixes Signed-off-by: Guy Daich * Implement API changes Signed-off-by: Guy Daich --------- Signed-off-by: Guy Daich Co-authored-by: zirain --- api/v1alpha1/backendtrafficpolicy_types.go | 6 +++ api/v1alpha1/circuitbreaker_types.go | 33 ++++++++++++ api/v1alpha1/zz_generated.deepcopy.go | 35 +++++++++++++ ....envoyproxy.io_backendtrafficpolicies.yaml | 33 ++++++++++++ site/content/en/latest/api/extension_types.md | 17 ++++++ .../backendtrafficpolicy_test.go | 52 ++++++++++++++++++- 6 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 api/v1alpha1/circuitbreaker_types.go diff --git a/api/v1alpha1/backendtrafficpolicy_types.go b/api/v1alpha1/backendtrafficpolicy_types.go index 33830ef86ae..b62be050e87 100644 --- a/api/v1alpha1/backendtrafficpolicy_types.go +++ b/api/v1alpha1/backendtrafficpolicy_types.go @@ -65,6 +65,12 @@ type BackendTrafficPolicySpec struct { // // +optional TCPKeepalive *TCPKeepalive `json:"tcpKeepalive,omitempty"` + + // Circuit Breaker settings for the upstream connections and requests. + // If not set, circuit breakers will be enabled with the default thresholds + // + // +optional + CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty"` } // BackendTrafficPolicyStatus defines the state of BackendTrafficPolicy diff --git a/api/v1alpha1/circuitbreaker_types.go b/api/v1alpha1/circuitbreaker_types.go new file mode 100644 index 00000000000..d045ae09517 --- /dev/null +++ b/api/v1alpha1/circuitbreaker_types.go @@ -0,0 +1,33 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +package v1alpha1 + +// CircuitBreaker defines the Circuit Breaker configuration. +type CircuitBreaker struct { + // The maximum number of connections that Envoy will establish to the referenced backend defined within a xRoute rule. + // + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=4294967295 + // +kubebuilder:default=1024 + // +optional + MaxConnections *int64 `json:"maxConnections,omitempty"` + + // The maximum number of pending requests that Envoy will queue to the referenced backend defined within a xRoute rule. + // + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=4294967295 + // +kubebuilder:default=1024 + // +optional + MaxPendingRequests *int64 `json:"maxPendingRequests,omitempty"` + + // The maximum number of parallel requests that Envoy will make to the referenced backend defined within a xRoute rule. + // + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=4294967295 + // +kubebuilder:default=1024 + // +optional + MaxParallelRequests *int64 `json:"maxParallelRequests,omitempty"` +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 78360fa1282..931de235ab8 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -101,6 +101,11 @@ func (in *BackendTrafficPolicySpec) DeepCopyInto(out *BackendTrafficPolicySpec) *out = new(TCPKeepalive) (*in).DeepCopyInto(*out) } + if in.CircuitBreaker != nil { + in, out := &in.CircuitBreaker, &out.CircuitBreaker + *out = new(CircuitBreaker) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendTrafficPolicySpec. @@ -198,6 +203,36 @@ func (in *CORS) DeepCopy() *CORS { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CircuitBreaker) DeepCopyInto(out *CircuitBreaker) { + *out = *in + if in.MaxConnections != nil { + in, out := &in.MaxConnections, &out.MaxConnections + *out = new(int64) + **out = **in + } + if in.MaxPendingRequests != nil { + in, out := &in.MaxPendingRequests, &out.MaxPendingRequests + *out = new(int64) + **out = **in + } + if in.MaxParallelRequests != nil { + in, out := &in.MaxParallelRequests, &out.MaxParallelRequests + *out = new(int64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CircuitBreaker. +func (in *CircuitBreaker) DeepCopy() *CircuitBreaker { + if in == nil { + return nil + } + out := new(CircuitBreaker) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClaimToHeader) DeepCopyInto(out *ClaimToHeader) { *out = *in 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 6606d2dd859..7bbb0d10612 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -44,6 +44,39 @@ spec: spec: description: spec defines the desired state of BackendTrafficPolicy. properties: + circuitBreaker: + description: Circuit Breaker settings for the upstream connections + and requests. If not set, circuit breakers will be enabled with + the default thresholds + properties: + maxConnections: + default: 1024 + description: The maximum number of connections that Envoy will + establish to the referenced backend defined within a xRoute + rule. + format: int64 + maximum: 4294967295 + minimum: 0 + type: integer + maxParallelRequests: + default: 1024 + description: The maximum number of parallel requests that Envoy + will make to the referenced backend defined within a xRoute + rule. + format: int64 + maximum: 4294967295 + minimum: 0 + type: integer + maxPendingRequests: + default: 1024 + description: The maximum number of pending requests that Envoy + will queue to the referenced backend defined within a xRoute + rule. + format: int64 + maximum: 4294967295 + minimum: 0 + type: integer + type: object loadBalancer: description: LoadBalancer policy to apply when routing traffic from the gateway to the backend endpoints diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index dc11cd57a0c..d86290614eb 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -76,6 +76,7 @@ _Appears in:_ | `loadBalancer` _[LoadBalancer](#loadbalancer)_ | LoadBalancer policy to apply when routing traffic from the gateway to the backend endpoints | | `proxyProtocol` _[ProxyProtocol](#proxyprotocol)_ | ProxyProtocol enables the Proxy Protocol when communicating with the backend. | | `tcpKeepalive` _[TCPKeepalive](#tcpkeepalive)_ | TcpKeepalive settings associated with the upstream client connection. Disabled by default. | +| `circuitBreaker` _[CircuitBreaker](#circuitbreaker)_ | Circuit Breaker settings for the upstream connections and requests. If not set, circuit breakers will be enabled with the default thresholds | @@ -126,6 +127,22 @@ _Appears in:_ | `allowCredentials` _boolean_ | AllowCredentials indicates whether a request can include user credentials like cookies, authentication headers, or TLS client certificates. | +#### CircuitBreaker + + + +CircuitBreaker defines the Circuit Breaker configuration. + +_Appears in:_ +- [BackendTrafficPolicySpec](#backendtrafficpolicyspec) + +| Field | Description | +| --- | --- | +| `maxConnections` _integer_ | The maximum number of connections that Envoy will establish to the referenced backend defined within a xRoute rule. | +| `maxPendingRequests` _integer_ | The maximum number of pending requests that Envoy will queue to the referenced backend defined within a xRoute rule. | +| `maxParallelRequests` _integer_ | The maximum number of parallel requests that Envoy will make to the referenced backend defined within a xRoute rule. | + + #### ClaimToHeader diff --git a/test/cel-validation/backendtrafficpolicy_test.go b/test/cel-validation/backendtrafficpolicy_test.go index 9ca669caea5..d32198a69a9 100644 --- a/test/cel-validation/backendtrafficpolicy_test.go +++ b/test/cel-validation/backendtrafficpolicy_test.go @@ -11,12 +11,12 @@ package celvalidation import ( "context" "fmt" + egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" + "k8s.io/utils/pointer" "strings" "testing" "time" - egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" ) @@ -306,6 +306,54 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { "spec.loadBalancer: Invalid value: \"object\": Currently SlowStart is only supported for RoundRobin and LeastRequest load balancers.", }, }, + { + desc: " valid config: min, max, nil", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + valMax := pointer.Int64(4294967295) + valMin := pointer.Int64(0) + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + CircuitBreaker: &egv1a1.CircuitBreaker{ + MaxConnections: valMax, + MaxPendingRequests: valMin, + MaxParallelRequests: nil, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: " invalid config: min and max valyues", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + valOverMax := pointer.Int64(4294967296) + valUnderMin := pointer.Int64(-1) + btp.Spec = egv1a1.BackendTrafficPolicySpec{ + TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{ + PolicyTargetReference: gwapiv1a2.PolicyTargetReference{ + Group: gwapiv1a2.Group("gateway.networking.k8s.io"), + Kind: gwapiv1a2.Kind("Gateway"), + Name: gwapiv1a2.ObjectName("eg"), + }, + }, + CircuitBreaker: &egv1a1.CircuitBreaker{ + MaxConnections: valOverMax, + MaxPendingRequests: valUnderMin, + MaxParallelRequests: valOverMax, + }, + } + }, + wantErrors: []string{ + "spec.circuitBreaker.maxParallelRequests: Invalid value: 4294967296: spec.circuitBreaker.maxParallelRequests in body should be less than or equal to 4294967295", + "spec.circuitBreaker.maxPendingRequests: Invalid value: -1: spec.circuitBreaker.maxPendingRequests in body should be greater than or equal to 0", + "spec.circuitBreaker.maxConnections: Invalid value: 4294967296: spec.circuitBreaker.maxConnections in body should be less than or equal to 4294967295", + }, + }, } for _, tc := range cases {