1
16
17 package volumezone
18
19 import (
20 "context"
21 "fmt"
22 "testing"
23
24 "github.com/google/go-cmp/cmp"
25 v1 "k8s.io/api/core/v1"
26 storagev1 "k8s.io/api/storage/v1"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/klog/v2/ktesting"
30 "k8s.io/kubernetes/pkg/scheduler/apis/config"
31 "k8s.io/kubernetes/pkg/scheduler/framework"
32 plugintesting "k8s.io/kubernetes/pkg/scheduler/framework/plugins/testing"
33 "k8s.io/kubernetes/pkg/scheduler/internal/cache"
34 st "k8s.io/kubernetes/pkg/scheduler/testing"
35 tf "k8s.io/kubernetes/pkg/scheduler/testing/framework"
36 )
37
38 func createPodWithVolume(pod, pvc string) *v1.Pod {
39 return st.MakePod().Name(pod).Namespace(metav1.NamespaceDefault).PVC(pvc).Obj()
40 }
41
42 func TestSingleZone(t *testing.T) {
43 pvLister := tf.PersistentVolumeLister{
44 {
45 ObjectMeta: metav1.ObjectMeta{Name: "Vol_1", Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-a"}},
46 },
47 {
48 ObjectMeta: metav1.ObjectMeta{Name: "Vol_2", Labels: map[string]string{v1.LabelFailureDomainBetaRegion: "us-west1", "uselessLabel": "none"}},
49 },
50 {
51 ObjectMeta: metav1.ObjectMeta{Name: "Vol_3", Labels: map[string]string{v1.LabelFailureDomainBetaRegion: "us-west1"}},
52 },
53 {
54 ObjectMeta: metav1.ObjectMeta{Name: "Vol_Stable_1", Labels: map[string]string{v1.LabelTopologyZone: "us-west1-a"}},
55 },
56 {
57 ObjectMeta: metav1.ObjectMeta{Name: "Vol_Stable_2", Labels: map[string]string{v1.LabelTopologyRegion: "us-west1", "uselessLabel": "none"}},
58 },
59 {
60 ObjectMeta: metav1.ObjectMeta{Name: "Vol_Stable_3", Labels: map[string]string{v1.LabelTopologyZone: "us-west1-a", v1.LabelTopologyRegion: "us-west1-a"}},
61 },
62 }
63
64 pvcLister := tf.PersistentVolumeClaimLister{
65 {
66 ObjectMeta: metav1.ObjectMeta{Name: "PVC_1", Namespace: "default"},
67 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_1"},
68 },
69 {
70 ObjectMeta: metav1.ObjectMeta{Name: "PVC_2", Namespace: "default"},
71 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_2"},
72 },
73 {
74 ObjectMeta: metav1.ObjectMeta{Name: "PVC_3", Namespace: "default"},
75 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_3"},
76 },
77 {
78 ObjectMeta: metav1.ObjectMeta{Name: "PVC_4", Namespace: "default"},
79 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_not_exist"},
80 },
81 {
82 ObjectMeta: metav1.ObjectMeta{Name: "PVC_Stable_1", Namespace: "default"},
83 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_Stable_1"},
84 },
85 {
86 ObjectMeta: metav1.ObjectMeta{Name: "PVC_Stable_2", Namespace: "default"},
87 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_Stable_2"},
88 },
89 {
90 ObjectMeta: metav1.ObjectMeta{Name: "PVC_Stable_3", Namespace: "default"},
91 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_Stable_3"},
92 },
93 }
94
95 tests := []struct {
96 name string
97 Pod *v1.Pod
98 Node *v1.Node
99 wantPreFilterStatus *framework.Status
100 wantFilterStatus *framework.Status
101 }{
102 {
103 name: "pod without volume",
104 Pod: st.MakePod().Name("pod_1").Namespace(metav1.NamespaceDefault).Obj(),
105 Node: &v1.Node{
106 ObjectMeta: metav1.ObjectMeta{
107 Name: "host1",
108 Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-a"},
109 },
110 },
111 wantPreFilterStatus: framework.NewStatus(framework.Skip),
112 },
113 {
114 name: "node without labels",
115 Pod: createPodWithVolume("pod_1", "PVC_1"),
116 Node: &v1.Node{
117 ObjectMeta: metav1.ObjectMeta{
118 Name: "host1",
119 },
120 },
121 },
122 {
123 name: "beta zone label matched",
124 Pod: createPodWithVolume("pod_1", "PVC_1"),
125 Node: &v1.Node{
126 ObjectMeta: metav1.ObjectMeta{
127 Name: "host1",
128 Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-a", "uselessLabel": "none"},
129 },
130 },
131 },
132 {
133 name: "beta region label matched",
134 Pod: createPodWithVolume("pod_1", "PVC_2"),
135 Node: &v1.Node{
136 ObjectMeta: metav1.ObjectMeta{
137 Name: "host1",
138 Labels: map[string]string{v1.LabelFailureDomainBetaRegion: "us-west1", "uselessLabel": "none"},
139 },
140 },
141 },
142 {
143 name: "beta region label doesn't match",
144 Pod: createPodWithVolume("pod_1", "PVC_2"),
145 Node: &v1.Node{
146 ObjectMeta: metav1.ObjectMeta{
147 Name: "host1",
148 Labels: map[string]string{v1.LabelFailureDomainBetaRegion: "no_us-west1", "uselessLabel": "none"},
149 },
150 },
151 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict),
152 },
153 {
154 name: "beta zone label doesn't match",
155 Pod: createPodWithVolume("pod_1", "PVC_1"),
156 Node: &v1.Node{
157 ObjectMeta: metav1.ObjectMeta{
158 Name: "host1",
159 Labels: map[string]string{v1.LabelFailureDomainBetaZone: "no_us-west1-a", "uselessLabel": "none"},
160 },
161 },
162 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict),
163 },
164 {
165 name: "zone label matched",
166 Pod: createPodWithVolume("pod_1", "PVC_Stable_1"),
167 Node: &v1.Node{
168 ObjectMeta: metav1.ObjectMeta{
169 Name: "host1",
170 Labels: map[string]string{v1.LabelTopologyZone: "us-west1-a", "uselessLabel": "none"},
171 },
172 },
173 },
174 {
175 name: "region label matched",
176 Pod: createPodWithVolume("pod_1", "PVC_Stable_2"),
177 Node: &v1.Node{
178 ObjectMeta: metav1.ObjectMeta{
179 Name: "host1",
180 Labels: map[string]string{v1.LabelTopologyRegion: "us-west1", "uselessLabel": "none"},
181 },
182 },
183 },
184 {
185 name: "region label doesn't match",
186 Pod: createPodWithVolume("pod_1", "PVC_Stable_2"),
187 Node: &v1.Node{
188 ObjectMeta: metav1.ObjectMeta{
189 Name: "host1",
190 Labels: map[string]string{v1.LabelTopologyRegion: "no_us-west1", "uselessLabel": "none"},
191 },
192 },
193 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict),
194 },
195 {
196 name: "zone label doesn't match",
197 Pod: createPodWithVolume("pod_1", "PVC_Stable_1"),
198 Node: &v1.Node{
199 ObjectMeta: metav1.ObjectMeta{
200 Name: "host1",
201 Labels: map[string]string{v1.LabelTopologyZone: "no_us-west1-a", "uselessLabel": "none"},
202 },
203 },
204 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict),
205 },
206 {
207 name: "pv with zone and region, node with only zone",
208 Pod: createPodWithVolume("pod_1", "PVC_Stable_3"),
209 Node: &v1.Node{
210 ObjectMeta: metav1.ObjectMeta{
211 Name: "host1",
212 Labels: map[string]string{
213 v1.LabelTopologyZone: "us-west1-a",
214 },
215 },
216 },
217 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict),
218 },
219 {
220 name: "pv with zone,node with beta zone",
221 Pod: createPodWithVolume("pod_1", "PVC_Stable_1"),
222 Node: &v1.Node{
223 ObjectMeta: metav1.ObjectMeta{
224 Name: "host1",
225 Labels: map[string]string{
226 v1.LabelFailureDomainBetaZone: "us-west1-a",
227 },
228 },
229 },
230 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict),
231 },
232 {
233 name: "pv with beta label,node with ga label, matched",
234 Pod: createPodWithVolume("pod_1", "PVC_1"),
235 Node: &v1.Node{
236 ObjectMeta: metav1.ObjectMeta{
237 Name: "host1",
238 Labels: map[string]string{
239 v1.LabelTopologyZone: "us-west1-a",
240 },
241 },
242 },
243 },
244 {
245 name: "pv with beta label,node with ga label, don't match",
246 Pod: createPodWithVolume("pod_1", "PVC_1"),
247 Node: &v1.Node{
248 ObjectMeta: metav1.ObjectMeta{
249 Name: "host1",
250 Labels: map[string]string{
251 v1.LabelTopologyZone: "us-west1-b",
252 },
253 },
254 },
255 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict),
256 },
257 }
258
259 for _, test := range tests {
260 t.Run(test.name, func(t *testing.T) {
261 _, ctx := ktesting.NewTestContext(t)
262 ctx, cancel := context.WithCancel(ctx)
263 defer cancel()
264
265 state := framework.NewCycleState()
266 node := &framework.NodeInfo{}
267 node.SetNode(test.Node)
268 p := &VolumeZone{
269 pvLister,
270 pvcLister,
271 nil,
272 }
273 _, preFilterStatus := p.PreFilter(ctx, state, test.Pod)
274 if diff := cmp.Diff(preFilterStatus, test.wantPreFilterStatus); diff != "" {
275 t.Errorf("PreFilter: status does not match (-want,+got):\n%s", diff)
276 }
277 filterStatus := p.Filter(ctx, state, test.Pod, node)
278 if diff := cmp.Diff(filterStatus, test.wantFilterStatus); diff != "" {
279 t.Errorf("Filter: status does not match (-want,+got):\n%s", diff)
280 }
281 })
282 }
283 }
284
285 func TestMultiZone(t *testing.T) {
286 pvLister := tf.PersistentVolumeLister{
287 {
288 ObjectMeta: metav1.ObjectMeta{Name: "Vol_1", Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-a"}},
289 },
290 {
291 ObjectMeta: metav1.ObjectMeta{Name: "Vol_2", Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-b", "uselessLabel": "none"}},
292 },
293 {
294 ObjectMeta: metav1.ObjectMeta{Name: "Vol_3", Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-c__us-west1-a"}},
295 },
296 {
297 ObjectMeta: metav1.ObjectMeta{Name: "Vol_Stable_1", Labels: map[string]string{v1.LabelTopologyZone: "us-west1-a"}},
298 },
299 {
300 ObjectMeta: metav1.ObjectMeta{Name: "Vol_Stable_2", Labels: map[string]string{v1.LabelTopologyZone: "us-west1-c__us-west1-a"}},
301 },
302 }
303
304 pvcLister := tf.PersistentVolumeClaimLister{
305 {
306 ObjectMeta: metav1.ObjectMeta{Name: "PVC_1", Namespace: "default"},
307 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_1"},
308 },
309 {
310 ObjectMeta: metav1.ObjectMeta{Name: "PVC_2", Namespace: "default"},
311 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_2"},
312 },
313 {
314 ObjectMeta: metav1.ObjectMeta{Name: "PVC_3", Namespace: "default"},
315 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_3"},
316 },
317 {
318 ObjectMeta: metav1.ObjectMeta{Name: "PVC_4", Namespace: "default"},
319 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_not_exist"},
320 },
321 {
322 ObjectMeta: metav1.ObjectMeta{Name: "PVC_Stable_1", Namespace: "default"},
323 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_Stable_1"},
324 },
325 {
326 ObjectMeta: metav1.ObjectMeta{Name: "PVC_Stable_2", Namespace: "default"},
327 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_Stable_2"},
328 },
329 }
330
331 tests := []struct {
332 name string
333 Pod *v1.Pod
334 Node *v1.Node
335 wantPreFilterStatus *framework.Status
336 wantFilterStatus *framework.Status
337 }{
338 {
339 name: "node without labels",
340 Pod: createPodWithVolume("pod_1", "PVC_3"),
341 Node: &v1.Node{
342 ObjectMeta: metav1.ObjectMeta{
343 Name: "host1",
344 },
345 },
346 },
347 {
348 name: "beta zone label matched",
349 Pod: createPodWithVolume("pod_1", "PVC_3"),
350 Node: &v1.Node{
351 ObjectMeta: metav1.ObjectMeta{
352 Name: "host1",
353 Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-a", "uselessLabel": "none"},
354 },
355 },
356 },
357 {
358 name: "beta zone label doesn't match",
359 Pod: createPodWithVolume("pod_1", "PVC_1"),
360 Node: &v1.Node{
361 ObjectMeta: metav1.ObjectMeta{
362 Name: "host1",
363 Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-b", "uselessLabel": "none"},
364 },
365 },
366 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict),
367 },
368 {
369 name: "zone label matched",
370 Pod: createPodWithVolume("pod_1", "PVC_Stable_2"),
371 Node: &v1.Node{
372 ObjectMeta: metav1.ObjectMeta{
373 Name: "host1",
374 Labels: map[string]string{v1.LabelTopologyZone: "us-west1-a", "uselessLabel": "none"},
375 },
376 },
377 },
378 {
379 name: "zone label doesn't match",
380 Pod: createPodWithVolume("pod_1", "PVC_Stable_1"),
381 Node: &v1.Node{
382 ObjectMeta: metav1.ObjectMeta{
383 Name: "host1",
384 Labels: map[string]string{v1.LabelTopologyZone: "us-west1-b", "uselessLabel": "none"},
385 },
386 },
387 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonConflict),
388 },
389 }
390
391 for _, test := range tests {
392 t.Run(test.name, func(t *testing.T) {
393 _, ctx := ktesting.NewTestContext(t)
394 ctx, cancel := context.WithCancel(ctx)
395 defer cancel()
396
397 state := framework.NewCycleState()
398 node := &framework.NodeInfo{}
399 node.SetNode(test.Node)
400 p := &VolumeZone{
401 pvLister,
402 pvcLister,
403 nil,
404 }
405 _, preFilterStatus := p.PreFilter(ctx, state, test.Pod)
406 if diff := cmp.Diff(preFilterStatus, test.wantPreFilterStatus); diff != "" {
407 t.Errorf("PreFilter: status does not match (-want,+got):\n%s", diff)
408 }
409 filterStatus := p.Filter(ctx, state, test.Pod, node)
410 if diff := cmp.Diff(filterStatus, test.wantFilterStatus); diff != "" {
411 t.Errorf("Filter: status does not match (-want,+got):\n%s", diff)
412 }
413 })
414 }
415 }
416
417 func TestWithBinding(t *testing.T) {
418 var (
419 modeWait = storagev1.VolumeBindingWaitForFirstConsumer
420
421 class0 = "Class_0"
422 classWait = "Class_Wait"
423 classImmediate = "Class_Immediate"
424 )
425
426 scLister := tf.StorageClassLister{
427 {
428 ObjectMeta: metav1.ObjectMeta{Name: classImmediate},
429 },
430 {
431 ObjectMeta: metav1.ObjectMeta{Name: classWait},
432 VolumeBindingMode: &modeWait,
433 },
434 }
435
436 pvLister := tf.PersistentVolumeLister{
437 {
438 ObjectMeta: metav1.ObjectMeta{Name: "Vol_1", Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-a"}},
439 },
440 }
441
442 pvcLister := tf.PersistentVolumeClaimLister{
443 {
444 ObjectMeta: metav1.ObjectMeta{Name: "PVC_1", Namespace: "default"},
445 Spec: v1.PersistentVolumeClaimSpec{VolumeName: "Vol_1"},
446 },
447 {
448 ObjectMeta: metav1.ObjectMeta{Name: "PVC_NoSC", Namespace: "default"},
449 Spec: v1.PersistentVolumeClaimSpec{StorageClassName: &class0},
450 },
451 {
452 ObjectMeta: metav1.ObjectMeta{Name: "PVC_EmptySC", Namespace: "default"},
453 },
454 {
455 ObjectMeta: metav1.ObjectMeta{Name: "PVC_WaitSC", Namespace: "default"},
456 Spec: v1.PersistentVolumeClaimSpec{StorageClassName: &classWait},
457 },
458 {
459 ObjectMeta: metav1.ObjectMeta{Name: "PVC_ImmediateSC", Namespace: "default"},
460 Spec: v1.PersistentVolumeClaimSpec{StorageClassName: &classImmediate},
461 },
462 }
463
464 testNode := &v1.Node{
465 ObjectMeta: metav1.ObjectMeta{
466 Name: "host1",
467 Labels: map[string]string{v1.LabelFailureDomainBetaZone: "us-west1-a", "uselessLabel": "none"},
468 },
469 }
470
471 tests := []struct {
472 name string
473 Pod *v1.Pod
474 Node *v1.Node
475 wantPreFilterStatus *framework.Status
476 wantFilterStatus *framework.Status
477 }{
478 {
479 name: "label zone failure domain matched",
480 Pod: createPodWithVolume("pod_1", "PVC_1"),
481 Node: testNode,
482 },
483 {
484 name: "unbound volume empty storage class",
485 Pod: createPodWithVolume("pod_1", "PVC_EmptySC"),
486 Node: testNode,
487 wantPreFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable,
488 "PersistentVolumeClaim had no pv name and storageClass name"),
489 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable,
490 "PersistentVolumeClaim had no pv name and storageClass name"),
491 },
492 {
493 name: "unbound volume no storage class",
494 Pod: createPodWithVolume("pod_1", "PVC_NoSC"),
495 Node: testNode,
496 wantPreFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable,
497 `storageclasses.storage.k8s.io "Class_0" not found`),
498 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable,
499 `storageclasses.storage.k8s.io "Class_0" not found`),
500 },
501 {
502 name: "unbound volume immediate binding mode",
503 Pod: createPodWithVolume("pod_1", "PVC_ImmediateSC"),
504 Node: testNode,
505 wantPreFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, "VolumeBindingMode not set for StorageClass \"Class_Immediate\""),
506 wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, "VolumeBindingMode not set for StorageClass \"Class_Immediate\""),
507 },
508 {
509 name: "unbound volume wait binding mode",
510 Pod: createPodWithVolume("pod_1", "PVC_WaitSC"),
511 Node: testNode,
512 wantPreFilterStatus: framework.NewStatus(framework.Skip),
513 },
514 }
515
516 for _, test := range tests {
517 t.Run(test.name, func(t *testing.T) {
518 _, ctx := ktesting.NewTestContext(t)
519 ctx, cancel := context.WithCancel(ctx)
520 defer cancel()
521
522 state := framework.NewCycleState()
523 node := &framework.NodeInfo{}
524 node.SetNode(test.Node)
525 p := &VolumeZone{
526 pvLister,
527 pvcLister,
528 scLister,
529 }
530 _, preFilterStatus := p.PreFilter(ctx, state, test.Pod)
531 if diff := cmp.Diff(preFilterStatus, test.wantPreFilterStatus); diff != "" {
532 t.Errorf("PreFilter: status does not match (-want,+got):\n%s", diff)
533 }
534 filterStatus := p.Filter(ctx, state, test.Pod, node)
535 if diff := cmp.Diff(filterStatus, test.wantFilterStatus); diff != "" {
536 t.Errorf("Filter: status does not match (-want,+got):\n%s", diff)
537 }
538 })
539 }
540 }
541
542 func BenchmarkVolumeZone(b *testing.B) {
543 tests := []struct {
544 Name string
545 Pod *v1.Pod
546 NumPV int
547 NumPVC int
548 NumNodes int
549 PreFilter bool
550 }{
551 {
552 Name: "with prefilter",
553 Pod: createPodWithVolume("pod_0", "PVC_Stable_0"),
554 NumPV: 1000,
555 NumPVC: 1000,
556 NumNodes: 1000,
557 PreFilter: true,
558 },
559 {
560 Name: "without prefilter",
561 Pod: createPodWithVolume("pod_0", "PVC_Stable_0"),
562 NumPV: 1000,
563 NumPVC: 1000,
564 NumNodes: 1000,
565 PreFilter: false,
566 },
567 }
568
569 for _, tt := range tests {
570 b.Run(tt.Name, func(b *testing.B) {
571 ctx, cancel := context.WithCancel(context.Background())
572 defer cancel()
573 nodes := makeNodesWithTopologyZone(tt.NumNodes)
574 pl := newPluginWithListers(ctx, b, []*v1.Pod{tt.Pod}, nodes, makePVCsWithPV(tt.NumPVC), makePVsWithZoneLabel(tt.NumPV))
575 nodeInfos := make([]*framework.NodeInfo, len(nodes), len(nodes))
576 for i := 0; i < len(nodes); i++ {
577 nodeInfo := &framework.NodeInfo{}
578 nodeInfo.SetNode(nodes[i])
579 nodeInfos[i] = nodeInfo
580 }
581 p := pl.(*VolumeZone)
582 state := framework.NewCycleState()
583
584 b.ResetTimer()
585
586 for i := 0; i < b.N; i++ {
587 if tt.PreFilter {
588 _, _ = p.PreFilter(ctx, state, tt.Pod)
589 }
590 for _, node := range nodeInfos {
591 _ = p.Filter(ctx, state, tt.Pod, node)
592 }
593 }
594 })
595 }
596 }
597
598 func newPluginWithListers(ctx context.Context, tb testing.TB, pods []*v1.Pod, nodes []*v1.Node, pvcs []*v1.PersistentVolumeClaim, pvs []*v1.PersistentVolume) framework.Plugin {
599 snapshot := cache.NewSnapshot(pods, nodes)
600
601 objects := make([]runtime.Object, 0, len(pvcs))
602 for _, pvc := range pvcs {
603 objects = append(objects, pvc)
604 }
605 for _, pv := range pvs {
606 objects = append(objects, pv)
607 }
608 return plugintesting.SetupPluginWithInformers(ctx, tb, New, &config.InterPodAffinityArgs{}, snapshot, objects)
609 }
610
611 func makePVsWithZoneLabel(num int) []*v1.PersistentVolume {
612 pvList := make([]*v1.PersistentVolume, num, num)
613 for i := 0; i < len(pvList); i++ {
614 pvName := fmt.Sprintf("Vol_Stable_%d", i)
615 zone := fmt.Sprintf("us-west-%d", i)
616 pvList[i] = &v1.PersistentVolume{
617 ObjectMeta: metav1.ObjectMeta{Name: pvName, Labels: map[string]string{v1.LabelTopologyZone: zone}},
618 }
619 }
620 return pvList
621 }
622
623 func makePVCsWithPV(num int) []*v1.PersistentVolumeClaim {
624 pvcList := make([]*v1.PersistentVolumeClaim, num, num)
625 for i := 0; i < len(pvcList); i++ {
626 pvcName := fmt.Sprintf("PVC_Stable_%d", i)
627 pvName := fmt.Sprintf("Vol_Stable_%d", i)
628 pvcList[i] = &v1.PersistentVolumeClaim{
629 ObjectMeta: metav1.ObjectMeta{Name: pvcName, Namespace: "default"},
630 Spec: v1.PersistentVolumeClaimSpec{VolumeName: pvName},
631 }
632 }
633 return pvcList
634 }
635
636 func makeNodesWithTopologyZone(num int) []*v1.Node {
637 nodeList := make([]*v1.Node, num, num)
638 for i := 0; i < len(nodeList); i++ {
639 nodeName := fmt.Sprintf("host_%d", i)
640 zone := fmt.Sprintf("us-west-0")
641 nodeList[i] = &v1.Node{
642 ObjectMeta: metav1.ObjectMeta{
643 Name: nodeName,
644 Labels: map[string]string{v1.LabelTopologyZone: zone, "uselessLabel": "none"},
645 },
646 }
647 }
648 return nodeList
649 }
650
View as plain text