diff --git a/api/v1alpha1/loadbalancer_types.go b/api/v1alpha1/loadbalancer_types.go index 9bf2d48702d..3bd4d9c4e54 100644 --- a/api/v1alpha1/loadbalancer_types.go +++ b/api/v1alpha1/loadbalancer_types.go @@ -5,10 +5,13 @@ package v1alpha1 +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + // LoadBalancer defines the load balancer policy to be applied. // +union // // +kubebuilder:validation:XValidation:rule="self.type == 'ConsistentHash' ? has(self.consistentHash) : !has(self.consistentHash)",message="If LoadBalancer type is consistentHash, consistentHash field needs to be set." +// +kubebuilder:validation:XValidation:rule="self.type in ['Random', 'ConsistentHash'] ? !has(self.slowStart) : true ",message="Currently SlowStart is only supported for RoundRobin and LeastRequest load balancers." type LoadBalancer struct { // Type decides the type of Load Balancer policy. // Valid LoadBalancerType values are @@ -24,6 +27,13 @@ type LoadBalancer struct { // // +optional ConsistentHash *ConsistentHash `json:"consistentHash,omitempty"` + + // 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 + // + // +optional + SlowStart *SlowStart `json:"slowStart,omitempty"` } // LoadBalancerType specifies the types of LoadBalancer. @@ -55,3 +65,14 @@ const ( // SourceIPConsistentHashType hashes based on the source IP address. SourceIPConsistentHashType ConsistentHashType = "SourceIP" ) + +// SlowStart defines the configuration related to the slow start load balancer policy. +type SlowStart struct { + // Window defines the duration of the warm up period for newly added host. + // During slow start window, traffic sent to the newly added hosts will gradually increase. + // Currently only supports linear growth of traffic. For additional details, + // see https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/cluster.proto#config-cluster-v3-cluster-slowstartconfig + // +kubebuilder:validation:Required + Window *metav1.Duration `json:"window"` + // TODO: Add support for non-linear traffic increases based on user usage. +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index df57bd7512d..88bc53a3ae5 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1571,6 +1571,11 @@ func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { *out = new(ConsistentHash) **out = **in } + if in.SlowStart != nil { + in, out := &in.SlowStart, &out.SlowStart + *out = new(SlowStart) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancer. @@ -2266,6 +2271,26 @@ func (in *SecurityPolicyStatus) DeepCopy() *SecurityPolicyStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SlowStart) DeepCopyInto(out *SlowStart) { + *out = *in + if in.Window != nil { + in, out := &in.Window, &out.Window + *out = new(v1.Duration) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SlowStart. +func (in *SlowStart) DeepCopy() *SlowStart { + if in == nil { + return nil + } + out := new(SlowStart) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SourceMatch) DeepCopyInto(out *SourceMatch) { *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 3becfc6b5b1..6606d2dd859 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -61,6 +61,23 @@ spec: required: - type type: object + slowStart: + description: 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 + properties: + window: + description: Window defines the duration of the warm up period + for newly added host. During slow start window, traffic + sent to the newly added hosts will gradually increase. Currently + only supports linear growth of traffic. For additional details, + see https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/cluster.proto#config-cluster-v3-cluster-slowstartconfig + type: string + required: + - window + type: object type: description: Type decides the type of Load Balancer policy. Valid LoadBalancerType values are "ConsistentHash", "LeastRequest", @@ -79,6 +96,10 @@ spec: field needs to be set. rule: 'self.type == ''ConsistentHash'' ? has(self.consistentHash) : !has(self.consistentHash)' + - message: Currently SlowStart is only supported for RoundRobin and + LeastRequest load balancers. + rule: 'self.type in [''Random'', ''ConsistentHash''] ? !has(self.slowStart) + : true ' proxyProtocol: description: ProxyProtocol enables the Proxy Protocol when communicating with the backend. diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index 3b6e47b5955..fc21e970bab 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -433,8 +433,15 @@ func (t *Translator) buildLoadBalancer(policy *egv1a1.BackendTrafficPolicy) *ir. lb.ConsistentHash.SourceIP = ptr.To(true) } case egv1a1.LeastRequestLoadBalancerType: - lb = &ir.LoadBalancer{ - LeastRequest: &ir.LeastRequest{}, + lb = &ir.LoadBalancer{} + if policy.Spec.LoadBalancer.SlowStart != nil { + if policy.Spec.LoadBalancer.SlowStart.Window != nil { + lb.LeastRequest = &ir.LeastRequest{ + SlowStart: &ir.SlowStart{ + Window: policy.Spec.LoadBalancer.SlowStart.Window, + }, + } + } } case egv1a1.RandomLoadBalancerType: lb = &ir.LoadBalancer{ @@ -442,7 +449,18 @@ func (t *Translator) buildLoadBalancer(policy *egv1a1.BackendTrafficPolicy) *ir. } case egv1a1.RoundRobinLoadBalancerType: lb = &ir.LoadBalancer{ - RoundRobin: &ir.RoundRobin{}, + RoundRobin: &ir.RoundRobin{ + SlowStart: &ir.SlowStart{}, + }, + } + if policy.Spec.LoadBalancer.SlowStart != nil { + if policy.Spec.LoadBalancer.SlowStart.Window != nil { + lb.RoundRobin = &ir.RoundRobin{ + SlowStart: &ir.SlowStart{ + Window: policy.Spec.LoadBalancer.SlowStart.Window, + }, + } + } } } diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml index 00f3895d30a..5f8b1a5f236 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml @@ -62,6 +62,25 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-2 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-2 + sectionName: http + rules: + - matches: + - path: + value: "/test2" + backendRefs: + - name: service-2 + port: 8080 backendTrafficPolicies: - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy @@ -91,3 +110,33 @@ backendTrafficPolicies: type: ConsistentHash consistentHash: type: SourceIP +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: envoy-gateway + name: policy-for-gateway2 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + loadBalancer: + type: RoundRobin + slowStart: + window: 300s +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: policy-for-route2 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-2 + namespace: default + loadBalancer: + type: LeastRequest + slowStart: + window: 300s diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml index b6be965c840..d43e7ad33dd 100755 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml @@ -22,6 +22,29 @@ backendTrafficPolicies: reason: Accepted status: "True" type: Accepted +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: policy-for-route2 + namespace: default + spec: + loadBalancer: + slowStart: + window: 5m0s + type: LeastRequest + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-2 + namespace: default + status: + conditions: + - lastTransitionTime: null + message: BackendTrafficPolicy has been accepted. + reason: Accepted + status: "True" + type: Accepted - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy metadata: @@ -43,6 +66,29 @@ backendTrafficPolicies: reason: Accepted status: "True" type: Accepted +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: policy-for-gateway2 + namespace: envoy-gateway + spec: + loadBalancer: + slowStart: + window: 5m0s + type: RoundRobin + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + status: + conditions: + - lastTransitionTime: null + message: BackendTrafficPolicy has been accepted. + reason: Accepted + status: "True" + type: Accepted gateways: - apiVersion: gateway.networking.k8s.io/v1 kind: Gateway @@ -101,7 +147,7 @@ gateways: protocol: HTTP status: listeners: - - attachedRoutes: 1 + - attachedRoutes: 2 conditions: - lastTransitionTime: null message: Sending translated listener configuration to the data plane @@ -197,6 +243,44 @@ httpRoutes: name: gateway-2 namespace: envoy-gateway sectionName: http +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-2 + 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: /test2 + 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: @@ -266,6 +350,27 @@ xdsIR: name: envoy-gateway/gateway-2/http port: 10080 routes: + - backendWeights: + invalid: 0 + valid: 0 + destination: + name: httproute/default/httproute-2/rule/0 + settings: + - endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + hostname: gateway.envoyproxy.io + loadBalancer: + leastRequest: + slowStart: + window: 5m0s + name: httproute/default/httproute-2/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: /test2 - backendWeights: invalid: 0 valid: 0 diff --git a/internal/ir/xds.go b/internal/ir/xds.go index eece53edab9..a0f8c821fcc 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -1048,11 +1048,19 @@ func (l *LoadBalancer) Validate() error { // RoundRobin load balancer settings // +k8s:deepcopy-gen=true -type RoundRobin struct{} +type RoundRobin struct { + // SlowStart defines the slow start configuration. + // If set, slow start mode is enabled for newly added hosts in the cluster. + SlowStart *SlowStart `json:"slowStart,omitempty" yaml:"slowStart,omitempty"` +} // LeastRequest load balancer settings // +k8s:deepcopy-gen=true -type LeastRequest struct{} +type LeastRequest struct { + // SlowStart defines the slow start configuration. + // If set, slow start mode is enabled for newly added hosts in the cluster. + SlowStart *SlowStart `json:"slowStart,omitempty" yaml:"slowStart,omitempty"` +} // Random load balancer settings // +k8s:deepcopy-gen=true @@ -1080,3 +1088,10 @@ type ProxyProtocol struct { // Version of proxy protocol to use Version ProxyProtocolVersion `json:"version,omitempty" yaml:"version,omitempty"` } + +// SlowStart defines the slow start configuration. +// +k8s:deepcopy-gen=true +type SlowStart struct { + // Window defines the duration of the warm up period for newly added host. + Window *metav1.Duration `json:"window" yaml:"window"` +} diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 4ffefa33d90..d68471b263a 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -615,6 +615,11 @@ func (in *JWT) DeepCopy() *JWT { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LeastRequest) DeepCopyInto(out *LeastRequest) { *out = *in + if in.SlowStart != nil { + in, out := &in.SlowStart, &out.SlowStart + *out = new(SlowStart) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeastRequest. @@ -648,12 +653,12 @@ func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { if in.RoundRobin != nil { in, out := &in.RoundRobin, &out.RoundRobin *out = new(RoundRobin) - **out = **in + (*in).DeepCopyInto(*out) } if in.LeastRequest != nil { in, out := &in.LeastRequest, &out.LeastRequest *out = new(LeastRequest) - **out = **in + (*in).DeepCopyInto(*out) } if in.Random != nil { in, out := &in.Random, &out.Random @@ -953,6 +958,11 @@ func (in *Redirect) DeepCopy() *Redirect { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RoundRobin) DeepCopyInto(out *RoundRobin) { *out = *in + if in.SlowStart != nil { + in, out := &in.SlowStart, &out.SlowStart + *out = new(SlowStart) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoundRobin. @@ -991,6 +1001,26 @@ func (in *RouteDestination) DeepCopy() *RouteDestination { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SlowStart) DeepCopyInto(out *SlowStart) { + *out = *in + if in.Window != nil { + in, out := &in.Window, &out.Window + *out = new(v1.Duration) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SlowStart. +func (in *SlowStart) DeepCopy() *SlowStart { + if in == nil { + return nil + } + out := new(SlowStart) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StringMatch) DeepCopyInto(out *StringMatch) { *out = *in diff --git a/internal/xds/translator/cluster.go b/internal/xds/translator/cluster.go index ea99496dead..d7aa3d21aff 100644 --- a/internal/xds/translator/cluster.go +++ b/internal/xds/translator/cluster.go @@ -100,8 +100,30 @@ func buildXdsCluster(args *xdsClusterArgs) *clusterv3.Cluster { cluster.LbPolicy = clusterv3.Cluster_LEAST_REQUEST } else if args.loadBalancer.LeastRequest != nil { cluster.LbPolicy = clusterv3.Cluster_LEAST_REQUEST + if args.loadBalancer.LeastRequest.SlowStart != nil { + if args.loadBalancer.LeastRequest.SlowStart.Window != nil { + cluster.LbConfig = &clusterv3.Cluster_LeastRequestLbConfig_{ + LeastRequestLbConfig: &clusterv3.Cluster_LeastRequestLbConfig{ + SlowStartConfig: &clusterv3.Cluster_SlowStartConfig{ + SlowStartWindow: durationpb.New(args.loadBalancer.LeastRequest.SlowStart.Window.Duration), + }, + }, + } + } + } } else if args.loadBalancer.RoundRobin != nil { cluster.LbPolicy = clusterv3.Cluster_ROUND_ROBIN + if args.loadBalancer.RoundRobin.SlowStart != nil { + if args.loadBalancer.RoundRobin.SlowStart.Window != nil { + cluster.LbConfig = &clusterv3.Cluster_RoundRobinLbConfig_{ + RoundRobinLbConfig: &clusterv3.Cluster_RoundRobinLbConfig{ + SlowStartConfig: &clusterv3.Cluster_SlowStartConfig{ + SlowStartWindow: durationpb.New(args.loadBalancer.RoundRobin.SlowStart.Window.Duration), + }, + }, + } + } + } } else if args.loadBalancer.Random != nil { cluster.LbPolicy = clusterv3.Cluster_RANDOM } else if args.loadBalancer.ConsistentHash != 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 965ce41425c..91ba5b18971 100644 --- a/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml @@ -46,3 +46,27 @@ http: - endpoints: - host: "1.2.3.4" port: 50000 + - name: "fifth-route" + hostname: "*" + loadBalancer: + leastRequest: + slowStart: + window: 60s + destination: + name: "fifth-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + - name: "sixth-route" + hostname: "*" + loadBalancer: + roundRobin: + slowStart: + window: 300s + destination: + name: "sixth-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 097e0262991..60969f05429 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 @@ -53,3 +53,36 @@ outlierDetection: {} perConnectionBufferLimitBytes: 32768 type: EDS +- commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: fifth-route-dest + lbPolicy: LEAST_REQUEST + leastRequestLbConfig: + slowStartConfig: + slowStartWindow: 60s + name: fifth-route-dest + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS +- commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: sixth-route-dest + name: sixth-route-dest + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + roundRobinLbConfig: + slowStartConfig: + slowStartWindow: 300s + 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 f185af17da7..ee22b49d2b2 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 @@ -46,3 +46,27 @@ loadBalancingWeight: 1 locality: region: fourth-route-dest/backend/0 +- clusterName: fifth-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: fifth-route-dest/backend/0 +- clusterName: sixth-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: sixth-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 214600b6262..d2a33c64849 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 @@ -28,3 +28,13 @@ hashPolicy: - connectionProperties: sourceIp: true + - match: + prefix: / + name: fifth-route + route: + cluster: fifth-route-dest + - match: + prefix: / + name: sixth-route + route: + cluster: sixth-route-dest diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 09b5e0e62e1..0c5519f1b61 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1068,6 +1068,7 @@ _Appears in:_ | --- | --- | | `type` _[LoadBalancerType](#loadbalancertype)_ | Type decides the type of Load Balancer policy. Valid LoadBalancerType values are "ConsistentHash", "LeastRequest", "Random", "RoundRobin", | | `consistentHash` _[ConsistentHash](#consistenthash)_ | ConsistentHash defines the configuration when the load balancer type is set to ConsistentHash | +| `slowStart` _[SlowStart](#slowstart)_ | 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 | #### LoadBalancerType @@ -1671,6 +1672,20 @@ _Appears in:_ +#### SlowStart + + + +SlowStart defines the configuration related to the slow start load balancer policy. + +_Appears in:_ +- [LoadBalancer](#loadbalancer) + +| Field | Description | +| --- | --- | +| `window` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#duration-v1-meta)_ | Window defines the duration of the warm up period for newly added host. During slow start window, traffic sent to the newly added hosts will gradually increase. Currently only supports linear growth of traffic. For additional details, see https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/cluster.proto#config-cluster-v3-cluster-slowstartconfig | + + #### SourceMatch diff --git a/test/cel-validation/backendtrafficpolicy_test.go b/test/cel-validation/backendtrafficpolicy_test.go index 673efd308b8..9ca669caea5 100644 --- a/test/cel-validation/backendtrafficpolicy_test.go +++ b/test/cel-validation/backendtrafficpolicy_test.go @@ -210,6 +210,102 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { }, wantErrors: []string{}, }, + { + desc: "leastRequest with SlowStar is set", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + 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"), + }, + }, + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.LeastRequestLoadBalancerType, + SlowStart: &egv1a1.SlowStart{ + Window: &metav1.Duration{ + Duration: 10000000, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "roundrobin with SlowStart is set", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + 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"), + }, + }, + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.RoundRobinLoadBalancerType, + SlowStart: &egv1a1.SlowStart{ + Window: &metav1.Duration{ + Duration: 10000000, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: " random with SlowStart is set", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + 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"), + }, + }, + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.RandomLoadBalancerType, + SlowStart: &egv1a1.SlowStart{ + Window: &metav1.Duration{ + Duration: 10000000, + }, + }, + }, + } + }, + wantErrors: []string{ + "spec.loadBalancer: Invalid value: \"object\": Currently SlowStart is only supported for RoundRobin and LeastRequest load balancers.", + }, + }, + { + desc: " consistenthash with SlowStart is set", + mutate: func(btp *egv1a1.BackendTrafficPolicy) { + 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"), + }, + }, + LoadBalancer: &egv1a1.LoadBalancer{ + Type: egv1a1.ConsistentHashLoadBalancerType, + SlowStart: &egv1a1.SlowStart{ + Window: &metav1.Duration{ + Duration: 10000000, + }, + }, + }, + } + }, + wantErrors: []string{ + "spec.loadBalancer: Invalid value: \"object\": Currently SlowStart is only supported for RoundRobin and LeastRequest load balancers.", + }, + }, } for _, tc := range cases {