Skip to content

Commit 7331ec7

Browse files
committed
Move service affinity predicate logic to its plugin.
1 parent ded2ff3 commit 7331ec7

File tree

10 files changed

+409
-591
lines changed

10 files changed

+409
-591
lines changed

pkg/scheduler/algorithm/predicates/metadata.go

Lines changed: 4 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,15 @@ package predicates
1818

1919
import (
2020
"context"
21-
"fmt"
2221
"math"
2322
"sync"
2423

25-
"k8s.io/klog"
26-
2724
v1 "k8s.io/api/core/v1"
2825
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2926
"k8s.io/apimachinery/pkg/labels"
3027
"k8s.io/apimachinery/pkg/util/sets"
3128
"k8s.io/client-go/util/workqueue"
29+
"k8s.io/klog"
3230
priorityutil "k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/util"
3331
schedulerlisters "k8s.io/kubernetes/pkg/scheduler/listers"
3432
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
@@ -129,56 +127,6 @@ type topologySpreadConstraint struct {
129127
selector labels.Selector
130128
}
131129

132-
type serviceAffinityMetadata struct {
133-
matchingPodList []*v1.Pod
134-
matchingPodServices []*v1.Service
135-
}
136-
137-
func (m *serviceAffinityMetadata) addPod(addedPod *v1.Pod, pod *v1.Pod, node *v1.Node) {
138-
// If addedPod is in the same namespace as the pod, update the list
139-
// of matching pods if applicable.
140-
if m == nil || addedPod.Namespace != pod.Namespace {
141-
return
142-
}
143-
144-
selector := CreateSelectorFromLabels(pod.Labels)
145-
if selector.Matches(labels.Set(addedPod.Labels)) {
146-
m.matchingPodList = append(m.matchingPodList, addedPod)
147-
}
148-
}
149-
150-
func (m *serviceAffinityMetadata) removePod(deletedPod *v1.Pod, node *v1.Node) {
151-
deletedPodFullName := schedutil.GetPodFullName(deletedPod)
152-
153-
if m == nil ||
154-
len(m.matchingPodList) == 0 ||
155-
deletedPod.Namespace != m.matchingPodList[0].Namespace {
156-
return
157-
}
158-
159-
for i, pod := range m.matchingPodList {
160-
if schedutil.GetPodFullName(pod) == deletedPodFullName {
161-
m.matchingPodList = append(m.matchingPodList[:i], m.matchingPodList[i+1:]...)
162-
break
163-
}
164-
}
165-
}
166-
167-
func (m *serviceAffinityMetadata) clone() *serviceAffinityMetadata {
168-
if m == nil {
169-
return nil
170-
}
171-
172-
copy := serviceAffinityMetadata{}
173-
174-
copy.matchingPodServices = append([]*v1.Service(nil),
175-
m.matchingPodServices...)
176-
copy.matchingPodList = append([]*v1.Pod(nil),
177-
m.matchingPodList...)
178-
179-
return &copy
180-
}
181-
182130
// PodAffinityMetadata pre-computed state for inter-pod affinity predicate.
183131
type PodAffinityMetadata struct {
184132
// A map of topology pairs to the number of existing pods that has anti-affinity terms that match the "pod".
@@ -283,10 +231,8 @@ func (m *PodAffinityMetadata) Clone() *PodAffinityMetadata {
283231

284232
// NOTE: When new fields are added/removed or logic is changed, please make sure that
285233
// RemovePod, AddPod, and ShallowCopy functions are updated to work with the new changes.
234+
// TODO(ahg-g): remove, not use anymore.
286235
type predicateMetadata struct {
287-
pod *v1.Pod
288-
289-
serviceAffinityMetadata *serviceAffinityMetadata
290236
}
291237

292238
// Ensure that predicateMetadata implements algorithm.Metadata.
@@ -318,9 +264,7 @@ func (f *MetadataProducerFactory) GetPredicateMetadata(pod *v1.Pod, sharedLister
318264
return nil
319265
}
320266

321-
predicateMetadata := &predicateMetadata{
322-
pod: pod,
323-
}
267+
predicateMetadata := &predicateMetadata{}
324268
for predicateName, precomputeFunc := range predicateMetadataProducers {
325269
klog.V(10).Infof("Precompute: %v", predicateName)
326270
precomputeFunc(predicateMetadata)
@@ -519,38 +463,19 @@ func (m *PodTopologySpreadMetadata) Clone() *PodTopologySpreadMetadata {
519463
// RemovePod changes predicateMetadata assuming that the given `deletedPod` is
520464
// deleted from the system.
521465
func (meta *predicateMetadata) RemovePod(deletedPod *v1.Pod, node *v1.Node) error {
522-
deletedPodFullName := schedutil.GetPodFullName(deletedPod)
523-
if deletedPodFullName == schedutil.GetPodFullName(meta.pod) {
524-
return fmt.Errorf("deletedPod and meta.pod must not be the same")
525-
}
526-
meta.serviceAffinityMetadata.removePod(deletedPod, node)
527-
528466
return nil
529467
}
530468

531469
// AddPod changes predicateMetadata assuming that the given `addedPod` is added to the
532470
// system.
533471
func (meta *predicateMetadata) AddPod(addedPod *v1.Pod, node *v1.Node) error {
534-
addedPodFullName := schedutil.GetPodFullName(addedPod)
535-
if addedPodFullName == schedutil.GetPodFullName(meta.pod) {
536-
return fmt.Errorf("addedPod and meta.pod must not be the same")
537-
}
538-
if node == nil {
539-
return fmt.Errorf("node not found")
540-
}
541-
542-
meta.serviceAffinityMetadata.addPod(addedPod, meta.pod, node)
543-
544472
return nil
545473
}
546474

547475
// ShallowCopy copies a metadata struct into a new struct and creates a copy of
548476
// its maps and slices, but it does not copy the contents of pointer values.
549477
func (meta *predicateMetadata) ShallowCopy() Metadata {
550-
newPredMeta := &predicateMetadata{
551-
pod: meta.pod,
552-
}
553-
newPredMeta.serviceAffinityMetadata = meta.serviceAffinityMetadata.clone()
478+
newPredMeta := &predicateMetadata{}
554479
return (Metadata)(newPredMeta)
555480
}
556481

pkg/scheduler/algorithm/predicates/metadata_test.go

Lines changed: 0 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -17,181 +17,16 @@ limitations under the License.
1717
package predicates
1818

1919
import (
20-
"fmt"
2120
"reflect"
22-
"sort"
2321
"testing"
2422

2523
v1 "k8s.io/api/core/v1"
2624
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2725
"k8s.io/apimachinery/pkg/labels"
28-
fakelisters "k8s.io/kubernetes/pkg/scheduler/listers/fake"
29-
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
3026
nodeinfosnapshot "k8s.io/kubernetes/pkg/scheduler/nodeinfo/snapshot"
3127
st "k8s.io/kubernetes/pkg/scheduler/testing"
3228
)
3329

34-
// sortablePods lets us to sort pods.
35-
type sortablePods []*v1.Pod
36-
37-
func (s sortablePods) Less(i, j int) bool {
38-
return s[i].Namespace < s[j].Namespace ||
39-
(s[i].Namespace == s[j].Namespace && s[i].Name < s[j].Name)
40-
}
41-
func (s sortablePods) Len() int { return len(s) }
42-
func (s sortablePods) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
43-
44-
var _ sort.Interface = &sortablePods{}
45-
46-
// sortableServices allows us to sort services.
47-
type sortableServices []*v1.Service
48-
49-
func (s sortableServices) Less(i, j int) bool {
50-
return s[i].Namespace < s[j].Namespace ||
51-
(s[i].Namespace == s[j].Namespace && s[i].Name < s[j].Name)
52-
}
53-
func (s sortableServices) Len() int { return len(s) }
54-
func (s sortableServices) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
55-
56-
var _ sort.Interface = &sortableServices{}
57-
58-
// predicateMetadataEquivalent returns true if the two metadata are equivalent.
59-
// Note: this function does not compare podRequest.
60-
func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error {
61-
if !reflect.DeepEqual(meta1.pod, meta2.pod) {
62-
return fmt.Errorf("pods are not the same")
63-
}
64-
if meta1.serviceAffinityMetadata != nil {
65-
sortablePods1 := sortablePods(meta1.serviceAffinityMetadata.matchingPodList)
66-
sort.Sort(sortablePods1)
67-
sortablePods2 := sortablePods(meta2.serviceAffinityMetadata.matchingPodList)
68-
sort.Sort(sortablePods2)
69-
if !reflect.DeepEqual(sortablePods1, sortablePods2) {
70-
return fmt.Errorf("serviceAffinityMatchingPodLists are not euqal")
71-
}
72-
73-
sortableServices1 := sortableServices(meta1.serviceAffinityMetadata.matchingPodServices)
74-
sort.Sort(sortableServices1)
75-
sortableServices2 := sortableServices(meta2.serviceAffinityMetadata.matchingPodServices)
76-
sort.Sort(sortableServices2)
77-
if !reflect.DeepEqual(sortableServices1, sortableServices2) {
78-
return fmt.Errorf("serviceAffinityMatchingPodServices are not euqal")
79-
}
80-
}
81-
return nil
82-
}
83-
84-
func TestPredicateMetadata_AddRemovePod(t *testing.T) {
85-
var label1 = map[string]string{
86-
"region": "r1",
87-
"zone": "z11",
88-
}
89-
var label2 = map[string]string{
90-
"region": "r1",
91-
"zone": "z12",
92-
}
93-
var label3 = map[string]string{
94-
"region": "r2",
95-
"zone": "z21",
96-
}
97-
selector1 := map[string]string{"foo": "bar"}
98-
99-
tests := []struct {
100-
name string
101-
pendingPod *v1.Pod
102-
addedPod *v1.Pod
103-
existingPods []*v1.Pod
104-
nodes []*v1.Node
105-
services []*v1.Service
106-
}{
107-
{
108-
name: "no anti-affinity or service affinity exist",
109-
pendingPod: &v1.Pod{
110-
ObjectMeta: metav1.ObjectMeta{Name: "pending", Labels: selector1},
111-
},
112-
existingPods: []*v1.Pod{
113-
{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
114-
Spec: v1.PodSpec{NodeName: "nodeA"},
115-
},
116-
{ObjectMeta: metav1.ObjectMeta{Name: "p2"},
117-
Spec: v1.PodSpec{NodeName: "nodeC"},
118-
},
119-
},
120-
addedPod: &v1.Pod{
121-
ObjectMeta: metav1.ObjectMeta{Name: "addedPod", Labels: selector1},
122-
Spec: v1.PodSpec{NodeName: "nodeB"},
123-
},
124-
nodes: []*v1.Node{
125-
{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: label1}},
126-
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: label2}},
127-
{ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: label3}},
128-
},
129-
},
130-
{
131-
name: "metadata service-affinity data are updated correctly after adding and removing a pod",
132-
pendingPod: &v1.Pod{
133-
ObjectMeta: metav1.ObjectMeta{Name: "pending", Labels: selector1},
134-
},
135-
existingPods: []*v1.Pod{
136-
{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
137-
Spec: v1.PodSpec{NodeName: "nodeA"},
138-
},
139-
{ObjectMeta: metav1.ObjectMeta{Name: "p2"},
140-
Spec: v1.PodSpec{NodeName: "nodeC"},
141-
},
142-
},
143-
addedPod: &v1.Pod{
144-
ObjectMeta: metav1.ObjectMeta{Name: "addedPod", Labels: selector1},
145-
Spec: v1.PodSpec{NodeName: "nodeB"},
146-
},
147-
services: []*v1.Service{{Spec: v1.ServiceSpec{Selector: selector1}}},
148-
nodes: []*v1.Node{
149-
{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: label1}},
150-
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: label2}},
151-
{ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: label3}},
152-
},
153-
},
154-
}
155-
156-
for _, test := range tests {
157-
t.Run(test.name, func(t *testing.T) {
158-
allPodLister := fakelisters.PodLister(append(test.existingPods, test.addedPod))
159-
// getMeta creates predicate meta data given the list of pods.
160-
getMeta := func(pods []*v1.Pod) (*predicateMetadata, map[string]*schedulernodeinfo.NodeInfo) {
161-
s := nodeinfosnapshot.NewSnapshot(nodeinfosnapshot.CreateNodeInfoMap(pods, test.nodes))
162-
_, precompute := NewServiceAffinityPredicate(s.NodeInfos(), s.Pods(), fakelisters.ServiceLister(test.services), nil)
163-
RegisterPredicateMetadataProducer("ServiceAffinityMetaProducer", precompute)
164-
factory := &MetadataProducerFactory{}
165-
meta := factory.GetPredicateMetadata(test.pendingPod, s)
166-
return meta.(*predicateMetadata), s.NodeInfoMap
167-
}
168-
169-
// allPodsMeta is meta data produced when all pods, including test.addedPod
170-
// are given to the metadata producer.
171-
allPodsMeta, _ := getMeta(allPodLister)
172-
// existingPodsMeta1 is meta data produced for test.existingPods (without test.addedPod).
173-
existingPodsMeta1, nodeInfoMap := getMeta(test.existingPods)
174-
// Add test.addedPod to existingPodsMeta1 and make sure meta is equal to allPodsMeta
175-
nodeInfo := nodeInfoMap[test.addedPod.Spec.NodeName]
176-
if err := existingPodsMeta1.AddPod(test.addedPod, nodeInfo.Node()); err != nil {
177-
t.Errorf("error adding pod to meta: %v", err)
178-
}
179-
if err := predicateMetadataEquivalent(allPodsMeta, existingPodsMeta1); err != nil {
180-
t.Errorf("meta data are not equivalent: %v", err)
181-
}
182-
// Remove the added pod and from existingPodsMeta1 an make sure it is equal
183-
// to meta generated for existing pods.
184-
existingPodsMeta2, _ := getMeta(fakelisters.PodLister(test.existingPods))
185-
if err := existingPodsMeta1.RemovePod(test.addedPod, nodeInfo.Node()); err != nil {
186-
t.Errorf("error removing pod from meta: %v", err)
187-
}
188-
if err := predicateMetadataEquivalent(existingPodsMeta1, existingPodsMeta2); err != nil {
189-
t.Errorf("meta data are not equivalent: %v", err)
190-
}
191-
})
192-
}
193-
}
194-
19530
func TestPodAffinityMetadata_Clone(t *testing.T) {
19631
source := &PodAffinityMetadata{
19732
topologyToMatchedExistingAntiAffinityTerms: topologyToMatchedTermCount{
@@ -217,33 +52,6 @@ func TestPodAffinityMetadata_Clone(t *testing.T) {
21752
}
21853
}
21954

220-
// TestPredicateMetadata_ShallowCopy tests the ShallowCopy function. It is based
221-
// on the idea that shallow-copy should produce an object that is deep-equal to the original
222-
// object.
223-
func TestPredicateMetadata_ShallowCopy(t *testing.T) {
224-
source := predicateMetadata{
225-
pod: &v1.Pod{
226-
ObjectMeta: metav1.ObjectMeta{
227-
Name: "test",
228-
Namespace: "testns",
229-
},
230-
},
231-
serviceAffinityMetadata: &serviceAffinityMetadata{
232-
matchingPodList: []*v1.Pod{
233-
{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}},
234-
{ObjectMeta: metav1.ObjectMeta{Name: "pod2"}},
235-
},
236-
matchingPodServices: []*v1.Service{
237-
{ObjectMeta: metav1.ObjectMeta{Name: "service1"}},
238-
},
239-
},
240-
}
241-
242-
if !reflect.DeepEqual(source.ShallowCopy().(*predicateMetadata), &source) {
243-
t.Errorf("Copy is not equal to source!")
244-
}
245-
}
246-
24755
// TestGetTPMapMatchingIncomingAffinityAntiAffinity tests against method getTPMapMatchingIncomingAffinityAntiAffinity
24856
// on Anti Affinity cases
24957
func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {

0 commit comments

Comments
 (0)