mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-16 15:20:17 +00:00
Add trafficdist package for handling reconciliation of new field
This commit is contained in:
parent
646fd200b8
commit
9513f75089
143
staging/src/k8s.io/endpointslice/trafficdist/trafficdist.go
Normal file
143
staging/src/k8s.io/endpointslice/trafficdist/trafficdist.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2024 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// trafficdist handles reconciliation of hints for trafficDistribution field.
|
||||||
|
package trafficdist
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
discoveryv1 "k8s.io/api/discovery/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReconcileHints will reconcile hints for the given EndpointSlices.
|
||||||
|
//
|
||||||
|
// EndpointSlice resources within slicesUnchanged will not be modified.
|
||||||
|
func ReconcileHints(trafficDistribution *string, slicesToCreate, slicesToUpdate, slicesUnchanged []*discoveryv1.EndpointSlice) ([]*discoveryv1.EndpointSlice, []*discoveryv1.EndpointSlice, []*discoveryv1.EndpointSlice) {
|
||||||
|
var h heuristic = &defaultHeuristic{}
|
||||||
|
|
||||||
|
if trafficDistribution != nil && *trafficDistribution == corev1.ServiceTrafficDistributionPreferClose {
|
||||||
|
h = &preferCloseHeuristic{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identify the Unchanged slices that need an update because of missing or
|
||||||
|
// incorrect zone hint.
|
||||||
|
//
|
||||||
|
// Uses filtering in place to remove any endpoints that are no longer
|
||||||
|
// unchanged and need to be moved to slicesToUpdate
|
||||||
|
// (https://github.com/golang/go/wiki/SliceTricks#filter-in-place)
|
||||||
|
j := 0
|
||||||
|
for _, slice := range slicesUnchanged {
|
||||||
|
if h.needsUpdate(slice) {
|
||||||
|
// Unchanged slices are direct copies from informer cache. We need to deep
|
||||||
|
// copy an unchanged slice before making any modifications to it so that we do
|
||||||
|
// not modify the slice within the informer cache.
|
||||||
|
slicesToUpdate = append(slicesToUpdate, slice.DeepCopy())
|
||||||
|
} else {
|
||||||
|
slicesUnchanged[j] = slice
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Truncate slicesUnchanged so it only includes slices that are still
|
||||||
|
// unchanged.
|
||||||
|
slicesUnchanged = slicesUnchanged[:j]
|
||||||
|
|
||||||
|
// Add zone hints to all slices that need to be created or updated.
|
||||||
|
for _, slice := range slicesToCreate {
|
||||||
|
h.update(slice)
|
||||||
|
}
|
||||||
|
for _, slice := range slicesToUpdate {
|
||||||
|
h.update(slice)
|
||||||
|
}
|
||||||
|
|
||||||
|
return slicesToCreate, slicesToUpdate, slicesUnchanged
|
||||||
|
}
|
||||||
|
|
||||||
|
type heuristic interface {
|
||||||
|
needsUpdate(*discoveryv1.EndpointSlice) bool
|
||||||
|
update(*discoveryv1.EndpointSlice)
|
||||||
|
}
|
||||||
|
|
||||||
|
// endpointReady returns true if an Endpoint has the Ready condition set to
|
||||||
|
// true.
|
||||||
|
func endpointReady(endpoint discoveryv1.Endpoint) bool {
|
||||||
|
return endpoint.Conditions.Ready != nil && *endpoint.Conditions.Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultHeuristic means cluster wide routing, hence it will remove any hints
|
||||||
|
// present in the EndpointSlice.
|
||||||
|
type defaultHeuristic struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// needsUpdate returns true if any endpoint in the slice has a zone hint.
|
||||||
|
func (defaultHeuristic) needsUpdate(slice *discoveryv1.EndpointSlice) bool {
|
||||||
|
if slice == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, endpoint := range slice.Endpoints {
|
||||||
|
if endpoint.Hints != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// update removes zone hints from all endpoints.
|
||||||
|
func (defaultHeuristic) update(slice *discoveryv1.EndpointSlice) {
|
||||||
|
for i := range slice.Endpoints {
|
||||||
|
slice.Endpoints[i].Hints = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// preferCloseHeuristic adds
|
||||||
|
type preferCloseHeuristic struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// needsUpdate returns true if any ready endpoint in the slice has a
|
||||||
|
// missing or incorrect hint.
|
||||||
|
func (preferCloseHeuristic) needsUpdate(slice *discoveryv1.EndpointSlice) bool {
|
||||||
|
if slice == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, endpoint := range slice.Endpoints {
|
||||||
|
if !endpointReady(endpoint) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var zone string
|
||||||
|
if endpoint.Zone != nil {
|
||||||
|
zone = *endpoint.Zone
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoint.Hints == nil || len(endpoint.Hints.ForZones) != 1 || endpoint.Hints.ForZones[0].Name != zone {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// update adds a same zone topology hint for all ready endpoints
|
||||||
|
func (preferCloseHeuristic) update(slice *discoveryv1.EndpointSlice) {
|
||||||
|
for i, endpoint := range slice.Endpoints {
|
||||||
|
if !endpointReady(endpoint) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var zone string
|
||||||
|
if endpoint.Zone != nil {
|
||||||
|
zone = *endpoint.Zone
|
||||||
|
}
|
||||||
|
slice.Endpoints[i].Hints = &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: zone}}}
|
||||||
|
}
|
||||||
|
}
|
470
staging/src/k8s.io/endpointslice/trafficdist/trafficdist_test.go
Normal file
470
staging/src/k8s.io/endpointslice/trafficdist/trafficdist_test.go
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2024 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package trafficdist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
discoveryv1 "k8s.io/api/discovery/v1"
|
||||||
|
"k8s.io/utils/ptr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReconcileHints_trafficDistribution_is_PreferClose(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
|
||||||
|
trafficDistribution *string
|
||||||
|
slicesToCreate []*discoveryv1.EndpointSlice
|
||||||
|
slicesToUpdate []*discoveryv1.EndpointSlice
|
||||||
|
slicesUnchanged []*discoveryv1.EndpointSlice
|
||||||
|
|
||||||
|
wantSlicesToCreate []*discoveryv1.EndpointSlice
|
||||||
|
wantSlicesToUpdate []*discoveryv1.EndpointSlice
|
||||||
|
wantSlicesUnchanged []*discoveryv1.EndpointSlice
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "should set same zone hints",
|
||||||
|
trafficDistribution: ptrTo(corev1.ServiceTrafficDistributionPreferClose),
|
||||||
|
slicesToCreate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.1"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.2"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.3"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.4"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
slicesToUpdate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.5"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.6"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.7"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.8"},
|
||||||
|
Zone: ptr.To("zone-c"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSlicesToCreate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.1"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-a"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.2"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-b"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.3"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-a"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.4"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-b"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSlicesToUpdate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.5"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-a"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.6"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-a"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.7"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-b"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.8"},
|
||||||
|
Zone: ptr.To("zone-c"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-c"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "incorrect hints should be corrected",
|
||||||
|
trafficDistribution: ptrTo(corev1.ServiceTrafficDistributionPreferClose),
|
||||||
|
slicesToUpdate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.1"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-b"}}}, // incorrect hint as per new heuristic
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
slicesUnchanged: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.2"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-c"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.3"},
|
||||||
|
Zone: ptr.To("zone-c"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSlicesToUpdate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.1"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-a"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.2"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-b"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.3"},
|
||||||
|
Zone: ptr.To("zone-c"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-c"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unready endpoints should not trigger updates",
|
||||||
|
trafficDistribution: ptrTo(corev1.ServiceTrafficDistributionPreferClose),
|
||||||
|
slicesUnchanged: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.2"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(false)}, // endpoint is not ready
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSlicesUnchanged: []*discoveryv1.EndpointSlice{ // ... so there should be no updates
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.2"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(false)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
gotSlicesToCreate, gotSlicesToUpdate, gotSlicesUnchanged := ReconcileHints(tc.trafficDistribution, tc.slicesToCreate, tc.slicesToUpdate, tc.slicesUnchanged)
|
||||||
|
|
||||||
|
if diff := cmp.Diff(tc.wantSlicesToCreate, gotSlicesToCreate, cmpopts.EquateEmpty()); diff != "" {
|
||||||
|
t.Errorf("ReconcileHints(...) returned unexpected diff in 'slicesToCreate': (-want, +got)\n%v", diff)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(tc.wantSlicesToUpdate, gotSlicesToUpdate, cmpopts.EquateEmpty()); diff != "" {
|
||||||
|
t.Errorf("ReconcileHints(...) returned unexpected diff in 'slicesToUpdate': (-want, +got)\n%v", diff)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(tc.wantSlicesUnchanged, gotSlicesUnchanged, cmpopts.EquateEmpty()); diff != "" {
|
||||||
|
t.Errorf("ReconcileHints(...) returned unexpected diff in 'slicesUnchanged': (-want, +got)\n%v", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReconcileHints_trafficDistribution_is_nil_or_empty(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
|
||||||
|
trafficDistribution *string
|
||||||
|
slicesToCreate []*discoveryv1.EndpointSlice
|
||||||
|
slicesToUpdate []*discoveryv1.EndpointSlice
|
||||||
|
slicesUnchanged []*discoveryv1.EndpointSlice
|
||||||
|
|
||||||
|
wantSlicesToCreate []*discoveryv1.EndpointSlice
|
||||||
|
wantSlicesToUpdate []*discoveryv1.EndpointSlice
|
||||||
|
wantSlicesUnchanged []*discoveryv1.EndpointSlice
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "trafficDistribution='' should remove zone hints",
|
||||||
|
trafficDistribution: ptrTo(""),
|
||||||
|
slicesToCreate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.1"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-a"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.2"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-b"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.3"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-a"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
slicesToUpdate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.5"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-a"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSlicesToCreate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.1"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.2"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.3"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSlicesToUpdate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.5"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "trafficDistribution=nil should remove zone hints",
|
||||||
|
trafficDistribution: nil,
|
||||||
|
slicesToUpdate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.5"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-a"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
slicesUnchanged: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.6"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
Hints: &discoveryv1.EndpointHints{ForZones: []discoveryv1.ForZone{{Name: "zone-b"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSlicesToUpdate: []*discoveryv1.EndpointSlice{
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.5"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.6"},
|
||||||
|
Zone: ptr.To("zone-b"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
gotSlicesToCreate, gotSlicesToUpdate, gotSlicesUnchanged := ReconcileHints(tc.trafficDistribution, tc.slicesToCreate, tc.slicesToUpdate, tc.slicesUnchanged)
|
||||||
|
|
||||||
|
if diff := cmp.Diff(tc.wantSlicesToCreate, gotSlicesToCreate, cmpopts.EquateEmpty()); diff != "" {
|
||||||
|
t.Errorf("ReconcileHints(...) returned unexpected diff in 'slicesToCreate': (-want, +got)\n%v", diff)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(tc.wantSlicesToUpdate, gotSlicesToUpdate, cmpopts.EquateEmpty()); diff != "" {
|
||||||
|
t.Errorf("ReconcileHints(...) returned unexpected diff in 'slicesToUpdate': (-want, +got)\n%v", diff)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(tc.wantSlicesUnchanged, gotSlicesUnchanged, cmpopts.EquateEmpty()); diff != "" {
|
||||||
|
t.Errorf("ReconcileHints(...) returned unexpected diff in 'slicesUnchanged': (-want, +got)\n%v", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the EndpointSlice objects within `slicesUnchanged` don't get modified.
|
||||||
|
func TestReconcileHints_doesNotMutateUnchangedSlices(t *testing.T) {
|
||||||
|
originalEps := &discoveryv1.EndpointSlice{
|
||||||
|
Endpoints: []discoveryv1.Endpoint{
|
||||||
|
{
|
||||||
|
Addresses: []string{"10.0.0.1"},
|
||||||
|
Zone: ptr.To("zone-a"),
|
||||||
|
Conditions: discoveryv1.EndpointConditions{Ready: ptr.To(true)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
clonedEps := originalEps.DeepCopy()
|
||||||
|
|
||||||
|
// originalEps should not get modified.
|
||||||
|
ReconcileHints(ptrTo(corev1.ServiceTrafficDistributionPreferClose), nil, nil, []*discoveryv1.EndpointSlice{originalEps})
|
||||||
|
if diff := cmp.Diff(clonedEps, originalEps); diff != "" {
|
||||||
|
t.Errorf("ReconcileHints(...) modified objects within slicesUnchanged, want objects within slicesUnchanged to remain unmodified: (-want, +got)\n%v", diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrTo[T any](obj T) *T {
|
||||||
|
return &obj
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user