Updating TopologyCache to disregard unready endpoints in calculations

This commit is contained in:
Rob Scott
2021-11-17 15:39:09 -08:00
parent 1367cca8fd
commit 9813ec7e8a
8 changed files with 333 additions and 119 deletions

View File

@@ -516,7 +516,7 @@ func TestReconcile1EndpointSlicePublishNotReadyAddresses(t *testing.T) {
endpointSlices := fetchEndpointSlices(t, client, namespace)
for _, endpointSlice := range endpointSlices {
for i, endpoint := range endpointSlice.Endpoints {
if !*endpoint.Conditions.Ready {
if !endpointsliceutil.EndpointReady(endpoint) {
t.Errorf("Expected endpoints[%d] to be ready", i)
}
}

View File

@@ -30,16 +30,16 @@ type SliceInfo struct {
Unchanged []*discovery.EndpointSlice
}
func (si *SliceInfo) getTotalEndpoints() int {
func (si *SliceInfo) getTotalReadyEndpoints() int {
totalEndpoints := 0
for _, slice := range si.ToCreate {
totalEndpoints += len(slice.Endpoints)
totalEndpoints += numReadyEndpoints(slice.Endpoints)
}
for _, slice := range si.ToUpdate {
totalEndpoints += len(slice.Endpoints)
totalEndpoints += numReadyEndpoints(slice.Endpoints)
}
for _, slice := range si.Unchanged {
totalEndpoints += len(slice.Endpoints)
totalEndpoints += numReadyEndpoints(slice.Endpoints)
}
return totalEndpoints
}

View File

@@ -21,13 +21,15 @@ import (
"testing"
discovery "k8s.io/api/discovery/v1"
utilpointer "k8s.io/utils/pointer"
)
func TestGetTotalEndpoints(t *testing.T) {
func Test_getTotalReadyEndpoints(t *testing.T) {
testCases := []struct {
name string
si *SliceInfo
expectedTotal int
name string
si *SliceInfo
expectedTotalReady int
expectedTotal int // this is really just testing the test helper
}{{
name: "empty",
si: &SliceInfo{},
@@ -35,30 +37,49 @@ func TestGetTotalEndpoints(t *testing.T) {
}, {
name: "empty slice",
si: &SliceInfo{
ToCreate: []*discovery.EndpointSlice{sliceWithNEndpoints(0)},
ToCreate: []*discovery.EndpointSlice{sliceWithNEndpoints(0, 0)},
},
expectedTotal: 0,
expectedTotalReady: 0,
expectedTotal: 0,
}, {
name: "multiple slices",
si: &SliceInfo{
ToCreate: []*discovery.EndpointSlice{sliceWithNEndpoints(15), sliceWithNEndpoints(8)},
ToCreate: []*discovery.EndpointSlice{sliceWithNEndpoints(15, 0), sliceWithNEndpoints(8, 0)},
},
expectedTotal: 23,
expectedTotalReady: 23,
expectedTotal: 23,
}, {
name: "slices for all",
si: &SliceInfo{
ToCreate: []*discovery.EndpointSlice{sliceWithNEndpoints(15), sliceWithNEndpoints(8)},
ToUpdate: []*discovery.EndpointSlice{sliceWithNEndpoints(2)},
Unchanged: []*discovery.EndpointSlice{sliceWithNEndpoints(100), sliceWithNEndpoints(90)},
ToCreate: []*discovery.EndpointSlice{sliceWithNEndpoints(15, 0), sliceWithNEndpoints(8, 0)},
ToUpdate: []*discovery.EndpointSlice{sliceWithNEndpoints(2, 0)},
Unchanged: []*discovery.EndpointSlice{sliceWithNEndpoints(100, 0), sliceWithNEndpoints(90, 0)},
},
expectedTotal: 215,
expectedTotalReady: 215,
expectedTotal: 215,
}, {
name: "slices for all with some unready",
si: &SliceInfo{
ToCreate: []*discovery.EndpointSlice{sliceWithNEndpoints(15, 3), sliceWithNEndpoints(5, 4)},
ToUpdate: []*discovery.EndpointSlice{sliceWithNEndpoints(3, 8)},
Unchanged: []*discovery.EndpointSlice{sliceWithNEndpoints(98, 2), sliceWithNEndpoints(90, 6)},
},
expectedTotalReady: 211,
expectedTotal: 234,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actualTotal := tc.si.getTotalEndpoints()
actualTotal := countEndpoints(tc.si.ToCreate) + countEndpoints(tc.si.ToUpdate) + countEndpoints(tc.si.Unchanged)
if actualTotal != tc.expectedTotal {
t.Errorf("Expected %d, got %d", tc.expectedTotal, actualTotal)
// This likely means that sliceWithNEndpoints or countEndpoints are not working as expected
t.Errorf("Problem with test or test helper. Expected %d total endpoints, got %d", tc.expectedTotal, actualTotal)
}
actualTotalReady := tc.si.getTotalReadyEndpoints()
if actualTotalReady != tc.expectedTotalReady {
t.Errorf("Expected %d, got %d", tc.expectedTotalReady, actualTotalReady)
}
})
}
@@ -66,14 +87,32 @@ func TestGetTotalEndpoints(t *testing.T) {
// helpers
func sliceWithNEndpoints(n int) *discovery.EndpointSlice {
endpoints := []discovery.Endpoint{}
func sliceWithNEndpoints(ready, unready int) *discovery.EndpointSlice {
endpoints := make([]discovery.Endpoint, ready+unready)
for i := 0; i < n; i++ {
endpoints = append(endpoints, discovery.Endpoint{Addresses: []string{fmt.Sprintf("10.1.2.%d", i)}})
for i := 0; i < ready; i++ {
endpoints[i] = discovery.Endpoint{
Addresses: []string{fmt.Sprintf("10.1.2.%d", i)},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}
}
for i := 0; i < unready; i++ {
endpoints[ready+i] = discovery.Endpoint{
Addresses: []string{fmt.Sprintf("10.1.2.%d", ready+i)},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(false)},
}
}
return &discovery.EndpointSlice{
Endpoints: endpoints,
}
}
func countEndpoints(slices []*discovery.EndpointSlice) int {
total := 0
for _, slice := range slices {
total += len(slice.Endpoints)
}
return total
}

View File

@@ -24,6 +24,7 @@ import (
discovery "k8s.io/api/discovery/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/klog/v2"
endpointsliceutil "k8s.io/kubernetes/pkg/controller/util/endpointslice"
)
const (
@@ -84,7 +85,7 @@ func (t *TopologyCache) GetOverloadedServices() []string {
// AddHints adds or updates topology hints on EndpointSlices and returns updated
// lists of EndpointSlices to create and update.
func (t *TopologyCache) AddHints(si *SliceInfo) ([]*discovery.EndpointSlice, []*discovery.EndpointSlice) {
totalEndpoints := si.getTotalEndpoints()
totalEndpoints := si.getTotalReadyEndpoints()
allocations := t.getAllocations(totalEndpoints)
if allocations == nil {
@@ -103,6 +104,10 @@ func (t *TopologyCache) AddHints(si *SliceInfo) ([]*discovery.EndpointSlice, []*
// step 1: assign same-zone hints for all endpoints as a starting point.
for _, slice := range allocatableSlices {
for i, endpoint := range slice.Endpoints {
if !endpointsliceutil.EndpointReady(endpoint) {
endpoint.Hints = nil
continue
}
if endpoint.Zone == nil || *endpoint.Zone == "" {
klog.InfoS("Endpoint found without zone specified, removing hints from service", "serviceKey", si.ServiceKey)
t.RemoveHints(si.ServiceKey, si.AddressType)

View File

@@ -53,16 +53,18 @@ func TestAddHints(t *testing.T) {
AddressType: discovery.AddressTypeIPv4,
ToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
},
expectedEndpointsByAddrType: nil,
expectedSlicesToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
expectedSlicesToUpdate: []*discovery.EndpointSlice{},
@@ -78,22 +80,26 @@ func TestAddHints(t *testing.T) {
AddressType: discovery.AddressTypeIPv4,
ToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
},
expectedEndpointsByAddrType: nil,
expectedSlicesToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
expectedSlicesToUpdate: []*discovery.EndpointSlice{},
@@ -108,10 +114,60 @@ func TestAddHints(t *testing.T) {
AddressType: discovery.AddressTypeIPv4,
ToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.4"},
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
},
expectedEndpointsByAddrType: map[discovery.AddressType]EndpointZoneInfo{
discovery.AddressTypeIPv4: {
"zone-a": 1,
"zone-b": 1,
},
},
expectedSlicesToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
expectedSlicesToUpdate: []*discovery.EndpointSlice{},
}, {
name: "slice to create with 2 ready, 1 unready, 1 unknown endpoints, zone ratios only require 2",
cpuRatiosByZone: map[string]float64{
"zone-a": 0.45,
"zone-b": 0.55,
},
sliceInfo: &SliceInfo{
ServiceKey: "ns/svc",
AddressType: discovery.AddressTypeIPv4,
ToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.5"},
Zone: utilpointer.StringPtr("zone-b"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(false)},
}, {
Addresses: []string{"10.1.2.6"},
Zone: utilpointer.StringPtr("zone-b"),
}},
}},
@@ -124,13 +180,24 @@ func TestAddHints(t *testing.T) {
},
expectedSlicesToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.4"},
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.5"},
Zone: utilpointer.StringPtr("zone-b"),
Hints: nil,
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(false)},
}, {
Addresses: []string{"10.1.2.6"},
Zone: utilpointer.StringPtr("zone-b"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Hints: nil,
}},
}},
expectedSlicesToUpdate: []*discovery.EndpointSlice{},
@@ -146,42 +213,52 @@ func TestAddHints(t *testing.T) {
AddressType: discovery.AddressTypeIPv4,
ToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}, {
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.3.3"},
Zone: utilpointer.StringPtr("zone-c"),
Addresses: []string{"10.1.3.3"},
Zone: utilpointer.StringPtr("zone-c"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.3.4"},
Zone: utilpointer.StringPtr("zone-c"),
Addresses: []string{"10.1.3.4"},
Zone: utilpointer.StringPtr("zone-c"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.3.4"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.1.3.4"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
ToUpdate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.2.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.2.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.2.2.4"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.2.2.4"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}, {
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.2.3.3"},
Zone: utilpointer.StringPtr("zone-b"),
Addresses: []string{"10.2.3.3"},
Zone: utilpointer.StringPtr("zone-b"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.2.3.4"},
Zone: utilpointer.StringPtr("zone-c"),
Addresses: []string{"10.2.3.4"},
Zone: utilpointer.StringPtr("zone-c"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.2.3.4"},
Zone: utilpointer.StringPtr("zone-a"),
Addresses: []string{"10.2.3.4"},
Zone: utilpointer.StringPtr("zone-a"),
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
},
@@ -194,52 +271,62 @@ func TestAddHints(t *testing.T) {
},
expectedSlicesToCreate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Addresses: []string{"10.1.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Addresses: []string{"10.1.2.4"},
Zone: utilpointer.StringPtr("zone-b"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}, {
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.1.3.3"},
Zone: utilpointer.StringPtr("zone-c"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-c"}}},
Addresses: []string{"10.1.3.3"},
Zone: utilpointer.StringPtr("zone-c"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-c"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.3.4"},
Zone: utilpointer.StringPtr("zone-c"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-c"}}},
Addresses: []string{"10.1.3.4"},
Zone: utilpointer.StringPtr("zone-c"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-c"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.1.3.4"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Addresses: []string{"10.1.3.4"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
expectedSlicesToUpdate: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.2.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Addresses: []string{"10.2.2.3"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.2.2.4"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Addresses: []string{"10.2.2.4"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}, {
Endpoints: []discovery.Endpoint{{
Addresses: []string{"10.2.3.3"},
Zone: utilpointer.StringPtr("zone-b"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Addresses: []string{"10.2.3.3"},
Zone: utilpointer.StringPtr("zone-b"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.2.3.4"},
Zone: utilpointer.StringPtr("zone-c"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-c"}}},
Addresses: []string{"10.2.3.4"},
Zone: utilpointer.StringPtr("zone-c"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-c"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Addresses: []string{"10.2.3.4"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Addresses: []string{"10.2.3.4"},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
}}

View File

@@ -19,9 +19,10 @@ package topologycache
import (
"math"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
discovery "k8s.io/api/discovery/v1"
"k8s.io/klog/v2"
endpointsliceutil "k8s.io/kubernetes/pkg/controller/util/endpointslice"
)
// RemoveHintsFromSlices removes topology hints on EndpointSlices and returns
@@ -75,6 +76,10 @@ func redistributeHints(slices []*discovery.EndpointSlice, givingZones, receiving
for _, slice := range slices {
for i, endpoint := range slice.Endpoints {
if !endpointsliceutil.EndpointReady(endpoint) {
endpoint.Hints = nil
continue
}
if len(givingZones) == 0 || len(receivingZones) == 0 {
return redistributions
}
@@ -185,6 +190,9 @@ func getMost(zones map[string]float64) (string, float64) {
func getHintsByZone(slice *discovery.EndpointSlice, allocatedHintsByZone EndpointZoneInfo, allocations map[string]Allocation) map[string]int {
hintsByZone := map[string]int{}
for _, endpoint := range slice.Endpoints {
if !endpointsliceutil.EndpointReady(endpoint) {
continue
}
if endpoint.Hints == nil || len(endpoint.Hints.ForZones) == 0 {
return nil
}
@@ -248,3 +256,15 @@ func NodeReady(nodeStatus v1.NodeStatus) bool {
}
return false
}
// numReadyEndpoints returns the number of Endpoints that are ready from the
// specified list.
func numReadyEndpoints(endpoints []discovery.Endpoint) int {
var total int
for _, ep := range endpoints {
if ep.Conditions.Ready != nil && *ep.Conditions.Ready {
total++
}
}
return total
}

View File

@@ -41,8 +41,9 @@ func Test_redistributeHints(t *testing.T) {
name: "single endpoint",
slices: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
givingZones: map[string]int{"zone-a": 1},
@@ -52,14 +53,17 @@ func Test_redistributeHints(t *testing.T) {
name: "endpoints from 1 zone redistributed to 2 other zones",
slices: []*discovery.EndpointSlice{{
Endpoints: []discovery.Endpoint{{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
}},
givingZones: map[string]int{"zone-a": 2},
@@ -211,6 +215,30 @@ func Test_getHintsByZone(t *testing.T) {
name: "single zone hint",
slice: discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}},
},
allocations: map[string]Allocation{
"zone-a": {Maximum: 3},
},
allocatedHintsByZone: EndpointZoneInfo{"zone-a": 1},
expectedHintsByZone: map[string]int{
"zone-a": 1,
},
}, {
name: "single zone hint with 1 unready endpoint and 1 unknown endpoint",
slice: discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
}, {
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(false)},
}, {
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
}},
@@ -227,16 +255,19 @@ func Test_getHintsByZone(t *testing.T) {
slice: discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
},
{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
},
{
Zone: utilpointer.StringPtr("zone-b"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Zone: utilpointer.StringPtr("zone-b"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-b"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
},
},
},
@@ -255,8 +286,9 @@ func Test_getHintsByZone(t *testing.T) {
slice: discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-non-existent"}}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-non-existent"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
},
},
},
@@ -270,8 +302,9 @@ func Test_getHintsByZone(t *testing.T) {
slice: discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
Zone: utilpointer.StringPtr("zone-a"),
Hints: nil,
Zone: utilpointer.StringPtr("zone-a"),
Hints: nil,
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
},
},
},
@@ -285,8 +318,9 @@ func Test_getHintsByZone(t *testing.T) {
slice: discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
},
},
},
@@ -300,12 +334,14 @@ func Test_getHintsByZone(t *testing.T) {
slice: discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
},
{
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Zone: utilpointer.StringPtr("zone-a"),
Hints: &discovery.EndpointHints{ForZones: []discovery.ForZone{{Name: "zone-a"}}},
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
},
},
},