Skip to content

Commit

Permalink
Merge pull request #101764 from aojea/automated-cherry-pick-of-#10176…
Browse files Browse the repository at this point in the history
…3-upstream-release-1.19

Automated cherry pick of #101763: Updating EndpointSlice controllers to avoid duplicate
  • Loading branch information
k8s-ci-robot committed May 7, 2021
2 parents 365baf0 + 7b3b4fb commit 3f263e1
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 8 deletions.
31 changes: 29 additions & 2 deletions pkg/controller/endpointslice/endpointslice_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/rand"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
Expand All @@ -56,19 +57,45 @@ type endpointSliceController struct {
}

func newController(nodeNames []string, batchPeriod time.Duration) (*fake.Clientset, *endpointSliceController) {
client := newClientset()
client := fake.NewSimpleClientset()

informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
nodeInformer := informerFactory.Core().V1().Nodes()
indexer := nodeInformer.Informer().GetIndexer()
for _, nodeName := range nodeNames {
indexer.Add(&v1.Node{ObjectMeta: metav1.ObjectMeta{Name: nodeName}})
}

esInformer := informerFactory.Discovery().V1beta1().EndpointSlices()
esIndexer := esInformer.Informer().GetIndexer()

// These reactors are required to mock functionality that would be covered
// automatically if we weren't using the fake client.
client.PrependReactor("create", "endpointslices", k8stesting.ReactionFunc(func(action k8stesting.Action) (bool, runtime.Object, error) {
endpointSlice := action.(k8stesting.CreateAction).GetObject().(*discovery.EndpointSlice)

if endpointSlice.ObjectMeta.GenerateName != "" {
endpointSlice.ObjectMeta.Name = fmt.Sprintf("%s-%s", endpointSlice.ObjectMeta.GenerateName, rand.String(8))
endpointSlice.ObjectMeta.GenerateName = ""
}
endpointSlice.Generation = 1
esIndexer.Add(endpointSlice)

return false, endpointSlice, nil
}))
client.PrependReactor("update", "endpointslices", k8stesting.ReactionFunc(func(action k8stesting.Action) (bool, runtime.Object, error) {
endpointSlice := action.(k8stesting.CreateAction).GetObject().(*discovery.EndpointSlice)
endpointSlice.Generation++
esIndexer.Update(endpointSlice)

return false, endpointSlice, nil
}))

esController := NewController(
informerFactory.Core().V1().Pods(),
informerFactory.Core().V1().Services(),
nodeInformer,
informerFactory.Discovery().V1beta1().EndpointSlices(),
esInformer,
int32(100),
client,
batchPeriod)
Expand Down
20 changes: 17 additions & 3 deletions pkg/controller/endpointslice/endpointslice_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,12 @@ func (est *endpointSliceTracker) ShouldSync(endpointSlice *discovery.EndpointSli
return !ok || endpointSlice.Generation > g
}

// StaleSlices returns true if one or more of the provided EndpointSlices
// have older generations than the corresponding tracked ones or if the tracker
// is expecting one or more of the provided EndpointSlices to be deleted.
// StaleSlices returns true if any of the following are true:
// 1. One or more of the provided EndpointSlices have older generations than the
// corresponding tracked ones.
// 2. The tracker is expecting one or more of the provided EndpointSlices to be
// deleted.
// 3. The tracker is tracking EndpointSlices that have not been provided.
func (est *endpointSliceTracker) StaleSlices(service *v1.Service, endpointSlices []*discovery.EndpointSlice) bool {
est.lock.Lock()
defer est.lock.Unlock()
Expand All @@ -92,12 +95,23 @@ func (est *endpointSliceTracker) StaleSlices(service *v1.Service, endpointSlices
if !ok {
return false
}
providedSlices := map[types.UID]int64{}
for _, endpointSlice := range endpointSlices {
providedSlices[endpointSlice.UID] = endpointSlice.Generation
g, ok := gfs[endpointSlice.UID]
if ok && (g == deletionExpected || g > endpointSlice.Generation) {
return true
}
}
for uid, generation := range gfs {
if generation == deletionExpected {
continue
}
_, ok := providedSlices[uid]
if !ok {
return true
}
}
return false
}

Expand Down
24 changes: 24 additions & 0 deletions pkg/controller/endpointslice/endpointslice_tracker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,30 @@ func TestEndpointSliceTrackerStaleSlices(t *testing.T) {
serviceParam: &v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "svc1", Namespace: "ns1"}},
slicesParam: []*discovery.EndpointSlice{epSlice1NewerGen},
expectNewer: false,
}, {
name: "slice in params is expected to be deleted",
tracker: &endpointSliceTracker{
generationsByService: map[types.NamespacedName]generationsBySlice{
{Name: "svc1", Namespace: "ns1"}: {
epSlice1.UID: deletionExpected,
},
},
},
serviceParam: &v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "svc1", Namespace: "ns1"}},
slicesParam: []*discovery.EndpointSlice{epSlice1},
expectNewer: true,
}, {
name: "slice in tracker but not in params",
tracker: &endpointSliceTracker{
generationsByService: map[types.NamespacedName]generationsBySlice{
{Name: "svc1", Namespace: "ns1"}: {
epSlice1.UID: epSlice1.Generation,
},
},
},
serviceParam: &v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "svc1", Namespace: "ns1"}},
slicesParam: []*discovery.EndpointSlice{},
expectNewer: true,
}}

for _, tc := range testCases {
Expand Down
20 changes: 17 additions & 3 deletions pkg/controller/endpointslicemirroring/endpointslice_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,12 @@ func (est *endpointSliceTracker) ShouldSync(endpointSlice *discovery.EndpointSli
return !ok || endpointSlice.Generation > g
}

// StaleSlices returns true if one or more of the provided EndpointSlices
// have older generations than the corresponding tracked ones or if the tracker
// is expecting one or more of the provided EndpointSlices to be deleted.
// StaleSlices returns true if any of the following are true:
// 1. One or more of the provided EndpointSlices have older generations than the
// corresponding tracked ones.
// 2. The tracker is expecting one or more of the provided EndpointSlices to be
// deleted.
// 3. The tracker is tracking EndpointSlices that have not been provided.
func (est *endpointSliceTracker) StaleSlices(service *v1.Service, endpointSlices []*discovery.EndpointSlice) bool {
est.lock.Lock()
defer est.lock.Unlock()
Expand All @@ -92,12 +95,23 @@ func (est *endpointSliceTracker) StaleSlices(service *v1.Service, endpointSlices
if !ok {
return false
}
providedSlices := map[types.UID]int64{}
for _, endpointSlice := range endpointSlices {
providedSlices[endpointSlice.UID] = endpointSlice.Generation
g, ok := gfs[endpointSlice.UID]
if ok && (g == deletionExpected || g > endpointSlice.Generation) {
return true
}
}
for uid, generation := range gfs {
if generation == deletionExpected {
continue
}
_, ok := providedSlices[uid]
if !ok {
return true
}
}
return false
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,30 @@ func TestEndpointSliceTrackerStaleSlices(t *testing.T) {
serviceParam: &v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "svc1", Namespace: "ns1"}},
slicesParam: []*discovery.EndpointSlice{epSlice1NewerGen},
expectNewer: false,
}, {
name: "slice in params is expected to be deleted",
tracker: &endpointSliceTracker{
generationsByService: map[types.NamespacedName]generationsBySlice{
{Name: "svc1", Namespace: "ns1"}: {
epSlice1.UID: deletionExpected,
},
},
},
serviceParam: &v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "svc1", Namespace: "ns1"}},
slicesParam: []*discovery.EndpointSlice{epSlice1},
expectNewer: true,
}, {
name: "slice in tracker but not in params",
tracker: &endpointSliceTracker{
generationsByService: map[types.NamespacedName]generationsBySlice{
{Name: "svc1", Namespace: "ns1"}: {
epSlice1.UID: epSlice1.Generation,
},
},
},
serviceParam: &v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "svc1", Namespace: "ns1"}},
slicesParam: []*discovery.EndpointSlice{},
expectNewer: true,
}}

for _, tc := range testCases {
Expand Down

0 comments on commit 3f263e1

Please sign in to comment.