diff --git a/charts/consul/templates/crd-servicedefaults.yaml b/charts/consul/templates/crd-servicedefaults.yaml index 5c6ecc7476..28196f693c 100644 --- a/charts/consul/templates/crd-servicedefaults.yaml +++ b/charts/consul/templates/crd-servicedefaults.yaml @@ -274,6 +274,12 @@ spec: upstream proxy instances will be monitored for removal from the load balancing pool. properties: + baseEjectionTime: + description: The base time that a host is ejected for. The + real time is equal to the base time multiplied by the number + of times the host has been ejected and is capped by + max_ejection_time (Default 300s). Defaults to 30s. + type: string enforcing_consecutive_5xx: description: EnforcingConsecutive5xx is the % chance that a host will be actually ejected when an outlier status @@ -285,6 +291,12 @@ spec: description: Interval between health check analysis sweeps. Each sweep may remove hosts or return hosts to the pool. type: string + maxEjectionPercent: + description: The maximum % of an upstream cluster that + can be ejected due to outlier detection. Defaults to + 10% but will eject at least one host regardless of the value. + format: int32 + type: integer maxFailures: description: MaxFailures is the count of consecutive failures that results in a host being removed from the pool. diff --git a/control-plane/api/v1alpha1/servicedefaults_types.go b/control-plane/api/v1alpha1/servicedefaults_types.go index 06da8b1d2c..46334bf64c 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types.go +++ b/control-plane/api/v1alpha1/servicedefaults_types.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "strings" + "time" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" @@ -181,6 +182,13 @@ type PassiveHealthCheck struct { // when an outlier status is detected through consecutive 5xx. // This setting can be used to disable ejection or to ramp it up slowly. EnforcingConsecutive5xx *uint32 `json:"enforcing_consecutive_5xx,omitempty"` + // The maximum % of an upstream cluster that can be ejected due to outlier detection. + // Defaults to 10% but will eject at least one host regardless of the value. + MaxEjectionPercent *uint32 `json:",omitempty" alias:"max_ejection_percent"` + // The base time that a host is ejected for. The real time is equal to the base time + // multiplied by the number of times the host has been ejected and is capped by + // max_ejection_time (Default 300s). Defaults to 30000ms or 30s. + BaseEjectionTime *time.Duration `json:",omitempty" alias:"base_ejection_time"` } type ServiceDefaultsDestination struct { @@ -445,6 +453,8 @@ func (in *PassiveHealthCheck) toConsul() *capi.PassiveHealthCheck { Interval: in.Interval.Duration, MaxFailures: in.MaxFailures, EnforcingConsecutive5xx: in.EnforcingConsecutive5xx, + MaxEjectionPercent: in.MaxEjectionPercent, + BaseEjectionTime: in.BaseEjectionTime, } } diff --git a/control-plane/api/v1alpha1/servicedefaults_types_test.go b/control-plane/api/v1alpha1/servicedefaults_types_test.go index 33ec6d2f40..e31be00e72 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types_test.go +++ b/control-plane/api/v1alpha1/servicedefaults_types_test.go @@ -87,6 +87,8 @@ func TestServiceDefaults_ToConsul(t *testing.T) { }, MaxFailures: uint32(20), EnforcingConsecutive5xx: pointer.Uint32(100), + MaxEjectionPercent: pointer.Uint32(10), + BaseEjectionTime: pointer.Duration(10 * time.Second), }, MeshGateway: MeshGateway{ Mode: "local", @@ -112,6 +114,8 @@ func TestServiceDefaults_ToConsul(t *testing.T) { }, MaxFailures: uint32(10), EnforcingConsecutive5xx: pointer.Uint32(60), + MaxEjectionPercent: pointer.Uint32(20), + BaseEjectionTime: pointer.Duration(20 * time.Second), }, MeshGateway: MeshGateway{ Mode: "remote", @@ -136,6 +140,8 @@ func TestServiceDefaults_ToConsul(t *testing.T) { }, MaxFailures: uint32(10), EnforcingConsecutive5xx: pointer.Uint32(60), + MaxEjectionPercent: pointer.Uint32(30), + BaseEjectionTime: pointer.Duration(30 * time.Second), }, MeshGateway: MeshGateway{ Mode: "remote", @@ -212,6 +218,8 @@ func TestServiceDefaults_ToConsul(t *testing.T) { Interval: 2 * time.Second, MaxFailures: uint32(20), EnforcingConsecutive5xx: pointer.Uint32(100), + MaxEjectionPercent: pointer.Uint32(10), + BaseEjectionTime: pointer.Duration(10 * time.Second), }, MeshGateway: capi.MeshGatewayConfig{ Mode: "local", @@ -235,6 +243,8 @@ func TestServiceDefaults_ToConsul(t *testing.T) { Interval: 2 * time.Second, MaxFailures: uint32(10), EnforcingConsecutive5xx: pointer.Uint32(60), + MaxEjectionPercent: pointer.Uint32(20), + BaseEjectionTime: pointer.Duration(20 * time.Second), }, MeshGateway: capi.MeshGatewayConfig{ Mode: "remote", @@ -257,6 +267,8 @@ func TestServiceDefaults_ToConsul(t *testing.T) { Interval: 2 * time.Second, MaxFailures: uint32(10), EnforcingConsecutive5xx: pointer.Uint32(60), + MaxEjectionPercent: pointer.Uint32(30), + BaseEjectionTime: pointer.Duration(30 * time.Second), }, MeshGateway: capi.MeshGatewayConfig{ Mode: "remote", @@ -383,6 +395,8 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { }, MaxFailures: uint32(20), EnforcingConsecutive5xx: pointer.Uint32(100), + MaxEjectionPercent: pointer.Uint32(10), + BaseEjectionTime: pointer.Duration(10 * time.Second), }, MeshGateway: MeshGateway{ Mode: "local", @@ -407,6 +421,8 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { }, MaxFailures: uint32(10), EnforcingConsecutive5xx: pointer.Uint32(60), + MaxEjectionPercent: pointer.Uint32(20), + BaseEjectionTime: pointer.Duration(20 * time.Second), }, MeshGateway: MeshGateway{ Mode: "remote", @@ -430,6 +446,8 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { }, MaxFailures: uint32(10), EnforcingConsecutive5xx: pointer.Uint32(60), + MaxEjectionPercent: pointer.Uint32(30), + BaseEjectionTime: pointer.Duration(30 * time.Second), }, MeshGateway: MeshGateway{ Mode: "remote", @@ -501,6 +519,8 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { Interval: 2 * time.Second, MaxFailures: uint32(20), EnforcingConsecutive5xx: pointer.Uint32(100), + MaxEjectionPercent: pointer.Uint32(10), + BaseEjectionTime: pointer.Duration(10 * time.Second), }, MeshGateway: capi.MeshGatewayConfig{ Mode: "local", @@ -523,6 +543,8 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { Interval: 2 * time.Second, MaxFailures: uint32(10), EnforcingConsecutive5xx: pointer.Uint32(60), + MaxEjectionPercent: pointer.Uint32(20), + BaseEjectionTime: pointer.Duration(20 * time.Second), }, MeshGateway: capi.MeshGatewayConfig{ Mode: "remote", @@ -544,6 +566,8 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { Interval: 2 * time.Second, MaxFailures: uint32(10), EnforcingConsecutive5xx: pointer.Uint32(60), + MaxEjectionPercent: pointer.Uint32(30), + BaseEjectionTime: pointer.Duration(30 * time.Second), }, MeshGateway: capi.MeshGatewayConfig{ Mode: "remote", diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index d12db29d14..3cd585fdb7 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -8,6 +8,7 @@ package v1alpha1 import ( "encoding/json" runtime "k8s.io/apimachinery/pkg/runtime" + timex "time" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -904,6 +905,16 @@ func (in *PassiveHealthCheck) DeepCopyInto(out *PassiveHealthCheck) { *out = new(uint32) **out = **in } + if in.MaxEjectionPercent != nil { + in, out := &in.MaxEjectionPercent, &out.MaxEjectionPercent + *out = new(uint32) + **out = **in + } + if in.BaseEjectionTime != nil { + in, out := &in.BaseEjectionTime, &out.BaseEjectionTime + *out = new(timex.Duration) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PassiveHealthCheck. diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml index 4f335a923d..dd6c7569af 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml @@ -267,6 +267,12 @@ spec: upstream proxy instances will be monitored for removal from the load balancing pool. properties: + baseEjectionTime: + description: The base time that a host is ejected for. The + real time is equal to the base time multiplied by the number + of times the host has been ejected and is capped by + max_ejection_time (Default 300s). Defaults to 30s. + type: string enforcing_consecutive_5xx: description: EnforcingConsecutive5xx is the % chance that a host will be actually ejected when an outlier status @@ -278,6 +284,12 @@ spec: description: Interval between health check analysis sweeps. Each sweep may remove hosts or return hosts to the pool. type: string + maxEjectionPercent: + description: The maximum % of an upstream cluster that + can be ejected due to outlier detection. Defaults to + 10% but will eject at least one host regardless of the value. + format: int32 + type: integer maxFailures: description: MaxFailures is the count of consecutive failures that results in a host being removed from the pool. @@ -370,6 +382,12 @@ spec: how upstream proxy instances will be monitored for removal from the load balancing pool. properties: + baseEjectionTime: + description: The base time that a host is ejected for. The + real time is equal to the base time multiplied by the number + of times the host has been ejected and is capped by + max_ejection_time (Default 300s). Defaults to 30s. + type: string enforcing_consecutive_5xx: description: EnforcingConsecutive5xx is the % chance that a host will be actually ejected when an outlier @@ -382,6 +400,12 @@ spec: sweeps. Each sweep may remove hosts or return hosts to the pool. type: string + maxEjectionPercent: + description: The maximum % of an upstream cluster that + can be ejected due to outlier detection. Defaults to + 10% but will eject at least one host regardless of the value. + format: int32 + type: integer maxFailures: description: MaxFailures is the count of consecutive failures that results in a host being removed from diff --git a/control-plane/go.mod b/control-plane/go.mod index 4aec0fdcb7..a5e4547541 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20220831174802-b8af65262de8 github.com/hashicorp/consul-server-connection-manager v0.1.0 - github.com/hashicorp/consul/api v1.20.0 + github.com/hashicorp/consul/api v1.10.1-0.20230426225948-5eaeb7b8e563 github.com/hashicorp/consul/sdk v0.13.1 github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f github.com/hashicorp/go-hclog v1.2.2 @@ -130,12 +130,12 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect - golang.org/x/net v0.7.0 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect + golang.org/x/net v0.1.0 // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/term v0.5.0 // indirect - golang.org/x/tools v0.2.0 // indirect google.golang.org/api v0.43.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect diff --git a/control-plane/go.sum b/control-plane/go.sum index 3978be63d0..dce336a327 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -353,8 +353,8 @@ github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20220831174802-b8af6526 github.com/hashicorp/consul-server-connection-manager v0.1.0 h1:XCweGvMHzra88rYv2zxwwuUOjBUdcQmNKVrnQmt/muo= github.com/hashicorp/consul-server-connection-manager v0.1.0/go.mod h1:XVVlO+Yk7aiRpspiHZkrrFVn9BJIiOPnQIzqytPxGaU= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.20.0 h1:9IHTjNVSZ7MIwjlW3N3a7iGiykCMDpxZu8jsxFJh0yc= -github.com/hashicorp/consul/api v1.20.0/go.mod h1:nR64eD44KQ59Of/ECwt2vUmIK2DKsDzAwTmwmLl8Wpo= +github.com/hashicorp/consul/api v1.10.1-0.20230426225948-5eaeb7b8e563 h1:C34qTESgxbiqkhK9ydoRmC+5CcaP6eW5wS9at+Jw5X0= +github.com/hashicorp/consul/api v1.10.1-0.20230426225948-5eaeb7b8e563/go.mod h1:tXfrC6o0yFTgAW46xd5Ic8STHc9oIBcRVBcwhX5KNCQ= github.com/hashicorp/consul/proto-public v0.1.0 h1:O0LSmCqydZi363hsqc6n2v5sMz3usQMXZF6ziK3SzXU= github.com/hashicorp/consul/proto-public v0.1.0/go.mod h1:vs2KkuWwtjkIgA5ezp4YKPzQp4GitV+q/+PvksrA92k= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -765,6 +765,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -841,8 +843,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1029,7 +1031,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=