1
16
17 package podtopologyspread
18
19 import (
20 "testing"
21
22 "github.com/stretchr/testify/require"
23 v1 "k8s.io/api/core/v1"
24 "k8s.io/klog/v2/ktesting"
25 "k8s.io/kubernetes/pkg/scheduler/apis/config"
26 "k8s.io/kubernetes/pkg/scheduler/framework"
27 plugintesting "k8s.io/kubernetes/pkg/scheduler/framework/plugins/testing"
28 "k8s.io/kubernetes/pkg/scheduler/internal/cache"
29 st "k8s.io/kubernetes/pkg/scheduler/testing"
30 )
31
32 func Test_isSchedulableAfterNodeChange(t *testing.T) {
33 testcases := []struct {
34 name string
35 pod *v1.Pod
36 oldNode, newNode *v1.Node
37 expectedHint framework.QueueingHint
38 expectedErr bool
39 }{
40 {
41 name: "node updates label which matches topologyKey",
42 pod: st.MakePod().Name("p").SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
43 Obj(),
44 oldNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Obj(),
45 newNode: st.MakeNode().Name("node-a").Label("zone", "zone2").Obj(),
46 expectedHint: framework.Queue,
47 },
48 {
49 name: "node that doesn't match topologySpreadConstraints updates non-related label",
50 pod: st.MakePod().Name("p").SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
51 Obj(),
52 oldNode: st.MakeNode().Name("node-a").Label("foo", "bar1").Obj(),
53 newNode: st.MakeNode().Name("node-a").Label("foo", "bar2").Obj(),
54 expectedHint: framework.QueueSkip,
55 },
56 {
57 name: "node that match topologySpreadConstraints adds non-related label",
58 pod: st.MakePod().Name("p").
59 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
60 SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
61 Obj(),
62 oldNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node1").Label("foo", "bar").Obj(),
63 newNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node1").Obj(),
64 expectedHint: framework.Queue,
65 },
66 {
67 name: "create node with non-related labels",
68 pod: st.MakePod().Name("p").SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
69 Obj(),
70 newNode: st.MakeNode().Name("node-a").Label("foo", "bar").Obj(),
71 expectedHint: framework.QueueSkip,
72 },
73 {
74 name: "create node with related labels",
75 pod: st.MakePod().Name("p").SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
76 Obj(),
77 newNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Obj(),
78 expectedHint: framework.Queue,
79 },
80 {
81 name: "delete node with non-related labels",
82 pod: st.MakePod().Name("p").SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
83 Obj(),
84 oldNode: st.MakeNode().Name("node-a").Label("foo", "bar").Obj(),
85 expectedHint: framework.QueueSkip,
86 },
87 {
88 name: "delete node with related labels",
89 pod: st.MakePod().Name("p").SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
90 Obj(),
91 oldNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Obj(),
92 expectedHint: framework.Queue,
93 },
94 {
95 name: "add node with related labels that only match one of topologySpreadConstraints",
96 pod: st.MakePod().Name("p").
97 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
98 SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
99 Obj(),
100 newNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Obj(),
101 expectedHint: framework.QueueSkip,
102 },
103 {
104 name: "add node with related labels that match all topologySpreadConstraints",
105 pod: st.MakePod().Name("p").
106 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
107 SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
108 Obj(),
109 newNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node1").Obj(),
110 expectedHint: framework.Queue,
111 },
112 {
113 name: "update node with related labels that only match one of topologySpreadConstraints",
114 pod: st.MakePod().Name("p").
115 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
116 SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
117 Obj(),
118 oldNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Obj(),
119 newNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Obj(),
120 expectedHint: framework.QueueSkip,
121 },
122 {
123 name: "update node with related labels that match all topologySpreadConstraints",
124 pod: st.MakePod().Name("p").
125 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
126 SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
127 Obj(),
128 oldNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node1").Obj(),
129 newNode: st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node2").Obj(),
130 expectedHint: framework.Queue,
131 },
132 }
133
134 for _, tc := range testcases {
135 t.Run(tc.name, func(t *testing.T) {
136 logger, ctx := ktesting.NewTestContext(t)
137 snapshot := cache.NewSnapshot(nil, nil)
138 pl := plugintesting.SetupPlugin(ctx, t, topologySpreadFunc, &config.PodTopologySpreadArgs{DefaultingType: config.ListDefaulting}, snapshot)
139 p := pl.(*PodTopologySpread)
140 actualHint, err := p.isSchedulableAfterNodeChange(logger, tc.pod, tc.oldNode, tc.newNode)
141 if tc.expectedErr {
142 require.Error(t, err)
143 return
144 }
145 require.NoError(t, err)
146 require.Equal(t, tc.expectedHint, actualHint)
147 })
148 }
149 }
150
151 func Test_isSchedulableAfterPodChange(t *testing.T) {
152 testcases := []struct {
153 name string
154 pod *v1.Pod
155 oldPod, newPod *v1.Pod
156 expectedHint framework.QueueingHint
157 expectedErr bool
158 }{
159 {
160 name: "add pod with labels match topologySpreadConstraints selector",
161 pod: st.MakePod().Name("p").Label("foo", "").
162 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
163 Obj(),
164 newPod: st.MakePod().Node("fake-node").Label("foo", "").Obj(),
165 expectedHint: framework.Queue,
166 },
167 {
168 name: "add un-scheduled pod",
169 pod: st.MakePod().Name("p").Label("foo", "").
170 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
171 Obj(),
172 newPod: st.MakePod().Label("foo", "").Obj(),
173 expectedHint: framework.QueueSkip,
174 },
175 {
176 name: "update un-scheduled pod",
177 pod: st.MakePod().Name("p").Label("foo", "").
178 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
179 Obj(),
180 newPod: st.MakePod().Label("foo", "").Obj(),
181 oldPod: st.MakePod().Label("bar", "").Obj(),
182 expectedHint: framework.QueueSkip,
183 },
184 {
185 name: "delete un-scheduled pod",
186 pod: st.MakePod().Name("p").Label("foo", "").
187 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
188 Obj(),
189 oldPod: st.MakePod().Label("foo", "").Obj(),
190 expectedHint: framework.QueueSkip,
191 },
192 {
193 name: "add pod with different namespace",
194 pod: st.MakePod().Name("p").Label("foo", "").
195 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
196 Obj(),
197 newPod: st.MakePod().Node("fake-node").Namespace("fake-namespace").Label("foo", "").Obj(),
198 expectedHint: framework.QueueSkip,
199 },
200 {
201 name: "add pod with labels don't match topologySpreadConstraints selector",
202 pod: st.MakePod().Name("p").Label("foo", "").
203 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
204 Obj(),
205 newPod: st.MakePod().Node("fake-node").Label("bar", "").Obj(),
206 expectedHint: framework.QueueSkip,
207 },
208 {
209 name: "delete pod with labels that match topologySpreadConstraints selector",
210 pod: st.MakePod().Name("p").Label("foo", "").
211 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
212 Obj(),
213 oldPod: st.MakePod().Node("fake-node").Label("foo", "").Obj(),
214 expectedHint: framework.Queue,
215 },
216 {
217 name: "delete pod with labels that don't match topologySpreadConstraints selector",
218 pod: st.MakePod().Name("p").Label("foo", "").
219 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
220 Obj(),
221 oldPod: st.MakePod().Node("fake-node").Label("bar", "").Obj(),
222 expectedHint: framework.QueueSkip,
223 },
224 {
225 name: "update pod's non-related label",
226 pod: st.MakePod().Name("p").Label("foo", "").
227 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
228 Obj(),
229 oldPod: st.MakePod().Node("fake-node").Label("foo", "").Label("bar", "bar1").Obj(),
230 newPod: st.MakePod().Node("fake-node").Label("foo", "").Label("bar", "bar2").Obj(),
231 expectedHint: framework.QueueSkip,
232 },
233 {
234 name: "add pod's label that matches topologySpreadConstraints selector",
235 pod: st.MakePod().Name("p").Label("foo", "").
236 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
237 Obj(),
238 oldPod: st.MakePod().Node("fake-node").Obj(),
239 newPod: st.MakePod().Node("fake-node").Label("foo", "").Obj(),
240 expectedHint: framework.Queue,
241 },
242 {
243 name: "delete pod label that matches topologySpreadConstraints selector",
244 pod: st.MakePod().Name("p").Label("foo", "").
245 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
246 Obj(),
247 oldPod: st.MakePod().Node("fake-node").Label("foo", "").Obj(),
248 newPod: st.MakePod().Node("fake-node").Obj(),
249 expectedHint: framework.Queue,
250 },
251 {
252 name: "change pod's label that matches topologySpreadConstraints selector",
253 pod: st.MakePod().Name("p").Label("foo", "").
254 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
255 Obj(),
256 oldPod: st.MakePod().Node("fake-node").Label("foo", "foo1").Obj(),
257 newPod: st.MakePod().Node("fake-node").Label("foo", "foo2").Obj(),
258 expectedHint: framework.QueueSkip,
259 },
260 {
261 name: "change pod's label that doesn't match topologySpreadConstraints selector",
262 pod: st.MakePod().Name("p").Label("foo", "").
263 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
264 Obj(),
265 oldPod: st.MakePod().Node("fake-node").Label("foo", "").Label("bar", "bar1").Obj(),
266 newPod: st.MakePod().Node("fake-node").Label("foo", "").Label("bar", "bar2").Obj(),
267 expectedHint: framework.QueueSkip,
268 },
269 {
270 name: "add pod's label that matches topologySpreadConstraints selector with multi topologySpreadConstraints",
271 pod: st.MakePod().Name("p").Label("foo", "").
272 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
273 SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
274 Obj(),
275 oldPod: st.MakePod().Node("fake-node").Label("foo", "").Obj(),
276 newPod: st.MakePod().Node("fake-node").Label("foo", "").Label("bar", "bar2").Obj(),
277 expectedHint: framework.Queue,
278 },
279 {
280 name: "change pod's label that doesn't match topologySpreadConstraints selector with multi topologySpreadConstraints",
281 pod: st.MakePod().Name("p").Label("foo", "").
282 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
283 SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
284 Obj(),
285 oldPod: st.MakePod().Node("fake-node").Label("foo", "").Obj(),
286 newPod: st.MakePod().Node("fake-node").Label("foo", "").Label("baz", "").Obj(),
287 expectedHint: framework.QueueSkip,
288 },
289 {
290 name: "change pod's label that match topologySpreadConstraints selector with multi topologySpreadConstraints",
291 pod: st.MakePod().Name("p").Label("foo", "").
292 SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
293 SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
294 Obj(),
295 oldPod: st.MakePod().Node("fake-node").Label("foo", "").Label("bar", "").Obj(),
296 newPod: st.MakePod().Node("fake-node").Label("foo", "").Label("bar", "bar2").Obj(),
297 expectedHint: framework.QueueSkip,
298 },
299 }
300 for _, tc := range testcases {
301 t.Run(tc.name, func(t *testing.T) {
302 logger, ctx := ktesting.NewTestContext(t)
303 snapshot := cache.NewSnapshot(nil, nil)
304 pl := plugintesting.SetupPlugin(ctx, t, topologySpreadFunc, &config.PodTopologySpreadArgs{DefaultingType: config.ListDefaulting}, snapshot)
305 p := pl.(*PodTopologySpread)
306 actualHint, err := p.isSchedulableAfterPodChange(logger, tc.pod, tc.oldPod, tc.newPod)
307 if tc.expectedErr {
308 require.Error(t, err)
309 return
310 }
311 require.NoError(t, err)
312 require.Equal(t, tc.expectedHint, actualHint)
313 })
314 }
315 }
316
View as plain text