Skip to content

Commit

Permalink
backport pr 15979 into 1.14.x (#17287)
Browse files Browse the repository at this point in the history
* backport pr 15979 into 1.14.x

* update protobuf package and update protos
  • Loading branch information
malizz authored May 10, 2023
1 parent ef4cde6 commit 842139f
Show file tree
Hide file tree
Showing 35 changed files with 329 additions and 109 deletions.
3 changes: 3 additions & 0 deletions .changelog/15979.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
envoy: add `MaxEjectionPercent` and `BaseEjectionTime` to passive health check configs.
```
6 changes: 6 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ ui-build-image:
@echo "Building UI build container"
@docker build $(NOCACHE) $(QUIET) -t $(UI_BUILD_TAG) - < build-support/docker/Build-UI.dockerfile

# Builds consul in a docker container and then dumps executable into ./pkg/bin/...
consul-docker: go-build-image
@$(SHELL) $(CURDIR)/build-support/scripts/build-docker.sh consul

Expand Down Expand Up @@ -467,6 +468,11 @@ envoy-regen:
@find "command/connect/envoy/testdata" -name '*.golden' -delete
@go test -tags '$(GOTAGS)' ./command/connect/envoy -update

# Point your web browser to http://localhost:3000/consul to live render docs from ./website/
.PHONY: docs
docs:
make -C website

.PHONY: help
help:
$(info available make targets)
Expand Down
10 changes: 10 additions & 0 deletions agent/consul/config_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,8 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
Interval: 10,
MaxFailures: 2,
EnforcingConsecutive5xx: uintPointer(60),
MaxEjectionPercent: uintPointer(61),
BaseEjectionTime: durationPointer(62 * time.Second),
},
},
Overrides: []*structs.UpstreamConfig{
Expand Down Expand Up @@ -1462,6 +1464,8 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
"Interval": int64(10),
"MaxFailures": int64(2),
"EnforcingConsecutive5xx": int64(60),
"MaxEjectionPercent": int64(61),
"BaseEjectionTime": uint64(62 * time.Second),
},
"mesh_gateway": map[string]interface{}{
"Mode": "none",
Expand All @@ -1476,6 +1480,8 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
"Interval": int64(10),
"MaxFailures": int64(2),
"EnforcingConsecutive5xx": int64(60),
"MaxEjectionPercent": int64(61),
"BaseEjectionTime": uint64(62 * time.Second),
},
"mesh_gateway": map[string]interface{}{
"Mode": "local",
Expand Down Expand Up @@ -2546,3 +2552,7 @@ func Test_gateWriteToSecondary_AllowedKinds(t *testing.T) {
func uintPointer(v uint32) *uint32 {
return &v
}

func durationPointer(d time.Duration) *time.Duration {
return &d
}
18 changes: 18 additions & 0 deletions agent/structs/config_entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,15 @@ 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. Defaults to 100.
EnforcingConsecutive5xx *uint32 `json:",omitempty" alias:"enforcing_consecutive_5xx"`

// 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"`
}

func (chk *PassiveHealthCheck) Clone() *PassiveHealthCheck {
Expand All @@ -1013,6 +1022,15 @@ func (chk PassiveHealthCheck) Validate() error {
if chk.Interval < 0*time.Second {
return fmt.Errorf("passive health check interval cannot be negative")
}
if chk.EnforcingConsecutive5xx != nil && *chk.EnforcingConsecutive5xx > 100 {
return fmt.Errorf("passive health check enforcing_consecutive_5xx must be a percentage between 0 and 100")
}
if chk.MaxEjectionPercent != nil && *chk.MaxEjectionPercent > 100 {
return fmt.Errorf("passive health check max_ejection_percent must be a percentage between 0 and 100")
}
if chk.BaseEjectionTime != nil && *chk.BaseEjectionTime < 0*time.Second {
return fmt.Errorf("passive health check base_ejection_time cannot be negative")
}
return nil
}

Expand Down
107 changes: 87 additions & 20 deletions agent/structs/config_entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,9 @@ func TestDecodeConfigEntry(t *testing.T) {
passive_health_check {
interval = "2s"
max_failures = 3
enforcing_consecutive_5xx = 4
max_ejection_percent = 5
base_ejection_time = "6s"
}
},
{
Expand Down Expand Up @@ -450,6 +453,9 @@ func TestDecodeConfigEntry(t *testing.T) {
PassiveHealthCheck {
MaxFailures = 3
Interval = "2s"
EnforcingConsecutive5xx = 4
MaxEjectionPercent = 5
BaseEjectionTime = "6s"
}
},
{
Expand Down Expand Up @@ -2242,6 +2248,39 @@ func TestPassiveHealthCheck_Validate(t *testing.T) {
wantErr: true,
wantMsg: "cannot be negative",
},
{
name: "valid enforcing_consecutive_5xx",
input: PassiveHealthCheck{EnforcingConsecutive5xx: uintPointer(100)},
wantErr: false,
},
{
name: "invalid enforcing_consecutive_5xx",
input: PassiveHealthCheck{EnforcingConsecutive5xx: uintPointer(101)},
wantErr: true,
wantMsg: "must be a percentage",
},
{
name: "valid max_ejection_percent",
input: PassiveHealthCheck{MaxEjectionPercent: uintPointer(100)},
wantErr: false,
},
{
name: "invalid max_ejection_percent",
input: PassiveHealthCheck{MaxEjectionPercent: uintPointer(101)},
wantErr: true,
wantMsg: "must be a percentage",
},
{
name: "valid base_ejection_time",
input: PassiveHealthCheck{BaseEjectionTime: durationPointer(0 * time.Second)},
wantErr: false,
},
{
name: "negative base_ejection_time",
input: PassiveHealthCheck{BaseEjectionTime: durationPointer(-1 * time.Second)},
wantErr: true,
wantMsg: "cannot be negative",
},
}

for _, tc := range tt {
Expand Down Expand Up @@ -2726,8 +2765,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
MaxConcurrentRequests: intPointer(5),
},
PassiveHealthCheck: &PassiveHealthCheck{
MaxFailures: 3,
Interval: 2 * time.Second,
MaxFailures: 3,
Interval: 2 * time.Second,
EnforcingConsecutive5xx: uintPointer(4),
MaxEjectionPercent: uintPointer(5),
BaseEjectionTime: durationPointer(6 * time.Second),
},
MeshGateway: MeshGatewayConfig{Mode: MeshGatewayModeRemote},
},
Expand All @@ -2744,8 +2786,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
MaxConcurrentRequests: intPointer(5),
},
"passive_health_check": &PassiveHealthCheck{
MaxFailures: 3,
Interval: 2 * time.Second,
MaxFailures: 3,
Interval: 2 * time.Second,
EnforcingConsecutive5xx: uintPointer(4),
MaxEjectionPercent: uintPointer(5),
BaseEjectionTime: durationPointer(6 * time.Second),
},
"mesh_gateway": MeshGatewayConfig{Mode: MeshGatewayModeRemote},
},
Expand All @@ -2764,8 +2809,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
MaxConcurrentRequests: intPointer(5),
},
PassiveHealthCheck: &PassiveHealthCheck{
MaxFailures: 3,
Interval: 2 * time.Second,
MaxFailures: 3,
Interval: 2 * time.Second,
EnforcingConsecutive5xx: uintPointer(4),
MaxEjectionPercent: uintPointer(5),
BaseEjectionTime: durationPointer(6 * time.Second),
},
MeshGateway: MeshGatewayConfig{Mode: MeshGatewayModeRemote},
},
Expand All @@ -2781,8 +2829,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
MaxConcurrentRequests: intPointer(12),
},
"passive_health_check": &PassiveHealthCheck{
MaxFailures: 13,
Interval: 14 * time.Second,
MaxFailures: 13,
Interval: 14 * time.Second,
EnforcingConsecutive5xx: uintPointer(15),
MaxEjectionPercent: uintPointer(16),
BaseEjectionTime: durationPointer(17 * time.Second),
},
"mesh_gateway": MeshGatewayConfig{Mode: MeshGatewayModeLocal},
},
Expand All @@ -2798,8 +2849,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
MaxConcurrentRequests: intPointer(5),
},
"passive_health_check": &PassiveHealthCheck{
MaxFailures: 3,
Interval: 2 * time.Second,
MaxFailures: 3,
Interval: 2 * time.Second,
EnforcingConsecutive5xx: uintPointer(4),
MaxEjectionPercent: uintPointer(5),
BaseEjectionTime: durationPointer(6 * time.Second),
},
"mesh_gateway": MeshGatewayConfig{Mode: MeshGatewayModeRemote},
},
Expand All @@ -2821,7 +2875,9 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
"passive_health_check": &PassiveHealthCheck{
MaxFailures: 13,
Interval: 14 * time.Second,
EnforcingConsecutive5xx: uintPointer(80),
EnforcingConsecutive5xx: uintPointer(15),
MaxEjectionPercent: uintPointer(16),
BaseEjectionTime: durationPointer(17 * time.Second),
},
"mesh_gateway": MeshGatewayConfig{Mode: MeshGatewayModeLocal},
},
Expand All @@ -2839,7 +2895,9 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
"passive_health_check": &PassiveHealthCheck{
MaxFailures: 13,
Interval: 14 * time.Second,
EnforcingConsecutive5xx: uintPointer(80),
EnforcingConsecutive5xx: uintPointer(15),
MaxEjectionPercent: uintPointer(16),
BaseEjectionTime: durationPointer(17 * time.Second),
},
"mesh_gateway": MeshGatewayConfig{Mode: MeshGatewayModeLocal},
},
Expand Down Expand Up @@ -2974,15 +3032,21 @@ func TestParseUpstreamConfig(t *testing.T) {
name: "passive health check map",
input: map[string]interface{}{
"passive_health_check": map[string]interface{}{
"interval": "22s",
"max_failures": 7,
"interval": "22s",
"max_failures": 7,
"enforcing_consecutive_5xx": 8,
"max_ejection_percent": 9,
"base_ejection_time": "10s",
},
},
want: UpstreamConfig{
ConnectTimeoutMs: 5000,
PassiveHealthCheck: &PassiveHealthCheck{
Interval: 22 * time.Second,
MaxFailures: 7,
Interval: 22 * time.Second,
MaxFailures: 7,
EnforcingConsecutive5xx: uintPointer(8),
MaxEjectionPercent: uintPointer(9),
BaseEjectionTime: durationPointer(10 * time.Second),
},
Protocol: "tcp",
},
Expand Down Expand Up @@ -3039,10 +3103,6 @@ func requireContainsLower(t *testing.T, haystack, needle string) {
require.Contains(t, strings.ToLower(haystack), strings.ToLower(needle))
}

func intPointer(i int) *int {
return &i
}

func TestConfigEntryQuery_CacheInfoKey(t *testing.T) {
assertCacheInfoKeyIsComplete(t, &ConfigEntryQuery{})
}
Expand Down Expand Up @@ -3136,7 +3196,14 @@ func testConfigEntryNormalizeAndValidate(t *testing.T, cases map[string]configEn
})
}
}
func intPointer(i int) *int {
return &i
}

func uintPointer(v uint32) *uint32 {
return &v
}

func durationPointer(d time.Duration) *time.Duration {
return &d
}
17 changes: 17 additions & 0 deletions agent/structs/structs.deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package structs

import (
"github.com/hashicorp/consul/types"
"time"
)

// DeepCopy generates a deep copy of *CARoot
Expand Down Expand Up @@ -802,6 +803,14 @@ func (o *UpstreamConfiguration) DeepCopy() *UpstreamConfiguration {
cp.Overrides[i2].PassiveHealthCheck.EnforcingConsecutive5xx = new(uint32)
*cp.Overrides[i2].PassiveHealthCheck.EnforcingConsecutive5xx = *o.Overrides[i2].PassiveHealthCheck.EnforcingConsecutive5xx
}
if o.Overrides[i2].PassiveHealthCheck.MaxEjectionPercent != nil {
cp.Overrides[i2].PassiveHealthCheck.MaxEjectionPercent = new(uint32)
*cp.Overrides[i2].PassiveHealthCheck.MaxEjectionPercent = *o.Overrides[i2].PassiveHealthCheck.MaxEjectionPercent
}
if o.Overrides[i2].PassiveHealthCheck.BaseEjectionTime != nil {
cp.Overrides[i2].PassiveHealthCheck.BaseEjectionTime = new(time.Duration)
*cp.Overrides[i2].PassiveHealthCheck.BaseEjectionTime = *o.Overrides[i2].PassiveHealthCheck.BaseEjectionTime
}
}
}
}
Expand Down Expand Up @@ -832,6 +841,14 @@ func (o *UpstreamConfiguration) DeepCopy() *UpstreamConfiguration {
cp.Defaults.PassiveHealthCheck.EnforcingConsecutive5xx = new(uint32)
*cp.Defaults.PassiveHealthCheck.EnforcingConsecutive5xx = *o.Defaults.PassiveHealthCheck.EnforcingConsecutive5xx
}
if o.Defaults.PassiveHealthCheck.MaxEjectionPercent != nil {
cp.Defaults.PassiveHealthCheck.MaxEjectionPercent = new(uint32)
*cp.Defaults.PassiveHealthCheck.MaxEjectionPercent = *o.Defaults.PassiveHealthCheck.MaxEjectionPercent
}
if o.Defaults.PassiveHealthCheck.BaseEjectionTime != nil {
cp.Defaults.PassiveHealthCheck.BaseEjectionTime = new(time.Duration)
*cp.Defaults.PassiveHealthCheck.BaseEjectionTime = *o.Defaults.PassiveHealthCheck.BaseEjectionTime
}
}
}
return &cp
Expand Down
20 changes: 20 additions & 0 deletions agent/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2994,6 +2994,26 @@ func DurationFromProto(d *duration.Duration) time.Duration {
return d.AsDuration()
}

// This should only be used for conversions generated by MOG
func DurationPointerToProto(d *time.Duration) *durationpb.Duration {
if d == nil {
return nil
}
return durationpb.New(*d)
}

// This should only be used for conversions generated by MOG
func DurationPointerFromProto(d *durationpb.Duration) *time.Duration {
if d == nil {
return nil
}
return DurationPointer(d.AsDuration())
}

func DurationPointer(d time.Duration) *time.Duration {
return &d
}

func TimeFromProto(s *timestamp.Timestamp) time.Time {
return s.AsTime()
}
Expand Down
5 changes: 4 additions & 1 deletion agent/xds/clusters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"sort"
"testing"
"text/template"
"time"

envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"

Expand Down Expand Up @@ -176,7 +177,9 @@ func TestClustersFromSnapshot(t *testing.T) {
ns.Proxy.Upstreams[0].Config["passive_health_check"] = map[string]interface{}{
"enforcing_consecutive_5xx": float64(80),
"max_failures": float64(5),
"interval": float64(10),
"interval": float64(10 * time.Second),
"max_ejection_percent": float64(100),
"base_ejection_time": float64(10 * time.Second),
}
}, nil)
},
Expand Down
Loading

0 comments on commit 842139f

Please sign in to comment.