1
16
17 package scheme
18
19 import (
20 "bytes"
21 "testing"
22
23 "github.com/google/go-cmp/cmp"
24 corev1 "k8s.io/api/core/v1"
25 "k8s.io/apimachinery/pkg/runtime"
26 "k8s.io/apimachinery/pkg/runtime/schema"
27 v1 "k8s.io/kube-scheduler/config/v1"
28 "k8s.io/kubernetes/pkg/scheduler/apis/config"
29 "k8s.io/kubernetes/pkg/scheduler/apis/config/testing/defaults"
30 "k8s.io/utils/ptr"
31 "sigs.k8s.io/yaml"
32 )
33
34
35
36 func TestCodecsDecodePluginConfig(t *testing.T) {
37 testCases := []struct {
38 name string
39 data []byte
40 wantErr string
41 wantProfiles []config.KubeSchedulerProfile
42 }{
43
44 {
45 name: "v1 all plugin args in default profile",
46 data: []byte(`
47 apiVersion: kubescheduler.config.k8s.io/v1
48 kind: KubeSchedulerConfiguration
49 profiles:
50 - pluginConfig:
51 - name: DefaultPreemption
52 args:
53 minCandidateNodesPercentage: 50
54 minCandidateNodesAbsolute: 500
55 - name: InterPodAffinity
56 args:
57 hardPodAffinityWeight: 5
58 - name: NodeResourcesFit
59 args:
60 ignoredResources: ["foo"]
61 - name: PodTopologySpread
62 args:
63 defaultConstraints:
64 - maxSkew: 1
65 topologyKey: zone
66 whenUnsatisfiable: ScheduleAnyway
67 - name: VolumeBinding
68 args:
69 bindTimeoutSeconds: 300
70 - name: NodeAffinity
71 args:
72 addedAffinity:
73 requiredDuringSchedulingIgnoredDuringExecution:
74 nodeSelectorTerms:
75 - matchExpressions:
76 - key: foo
77 operator: In
78 values: ["bar"]
79 - name: NodeResourcesBalancedAllocation
80 args:
81 resources:
82 - name: cpu # default weight(1) will be set.
83 - name: memory # weight 0 will be replaced by 1.
84 weight: 0
85 - name: scalar0
86 weight: 1
87 - name: scalar1 # default weight(1) will be set for scalar1
88 - name: scalar2 # weight 0 will be replaced by 1.
89 weight: 0
90 - name: scalar3
91 weight: 2
92 `),
93 wantProfiles: []config.KubeSchedulerProfile{
94 {
95 SchedulerName: "default-scheduler",
96 PercentageOfNodesToScore: nil,
97 Plugins: defaults.PluginsV1,
98 PluginConfig: []config.PluginConfig{
99 {
100 Name: "DefaultPreemption",
101 Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 500},
102 },
103 {
104 Name: "InterPodAffinity",
105 Args: &config.InterPodAffinityArgs{HardPodAffinityWeight: 5},
106 },
107 {
108 Name: "NodeResourcesFit",
109 Args: &config.NodeResourcesFitArgs{
110 IgnoredResources: []string{"foo"},
111 ScoringStrategy: &config.ScoringStrategy{
112 Type: config.LeastAllocated,
113 Resources: []config.ResourceSpec{
114 {Name: "cpu", Weight: 1},
115 {Name: "memory", Weight: 1},
116 },
117 },
118 },
119 },
120 {
121 Name: "PodTopologySpread",
122 Args: &config.PodTopologySpreadArgs{
123 DefaultConstraints: []corev1.TopologySpreadConstraint{
124 {MaxSkew: 1, TopologyKey: "zone", WhenUnsatisfiable: corev1.ScheduleAnyway},
125 },
126 DefaultingType: config.SystemDefaulting,
127 },
128 },
129 {
130 Name: "VolumeBinding",
131 Args: &config.VolumeBindingArgs{
132 BindTimeoutSeconds: 300,
133 },
134 },
135 {
136 Name: "NodeAffinity",
137 Args: &config.NodeAffinityArgs{
138 AddedAffinity: &corev1.NodeAffinity{
139 RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
140 NodeSelectorTerms: []corev1.NodeSelectorTerm{
141 {
142 MatchExpressions: []corev1.NodeSelectorRequirement{
143 {
144 Key: "foo",
145 Operator: corev1.NodeSelectorOpIn,
146 Values: []string{"bar"},
147 },
148 },
149 },
150 },
151 },
152 },
153 },
154 },
155 {
156 Name: "NodeResourcesBalancedAllocation",
157 Args: &config.NodeResourcesBalancedAllocationArgs{
158 Resources: []config.ResourceSpec{
159 {Name: "cpu", Weight: 1},
160 {Name: "memory", Weight: 1},
161 {Name: "scalar0", Weight: 1},
162 {Name: "scalar1", Weight: 1},
163 {Name: "scalar2", Weight: 1},
164 {Name: "scalar3", Weight: 2}},
165 },
166 },
167 },
168 },
169 },
170 },
171 {
172 name: "v1 with non-default global percentageOfNodesToScore",
173 data: []byte(`
174 apiVersion: kubescheduler.config.k8s.io/v1
175 kind: KubeSchedulerConfiguration
176 percentageOfNodesToScore: 10
177 `),
178 wantProfiles: []config.KubeSchedulerProfile{
179 {
180 SchedulerName: "default-scheduler",
181 PercentageOfNodesToScore: nil,
182 Plugins: defaults.PluginsV1,
183 PluginConfig: defaults.PluginConfigsV1,
184 },
185 },
186 },
187 {
188 name: "v1 with non-default global and profile percentageOfNodesToScore",
189 data: []byte(`
190 apiVersion: kubescheduler.config.k8s.io/v1
191 kind: KubeSchedulerConfiguration
192 percentageOfNodesToScore: 10
193 profiles:
194 - percentageOfNodesToScore: 20
195 `),
196 wantProfiles: []config.KubeSchedulerProfile{
197 {
198 SchedulerName: "default-scheduler",
199 PercentageOfNodesToScore: ptr.To[int32](20),
200 Plugins: defaults.PluginsV1,
201 PluginConfig: defaults.PluginConfigsV1,
202 },
203 },
204 },
205 {
206 name: "v1 plugins can include version and kind",
207 data: []byte(`
208 apiVersion: kubescheduler.config.k8s.io/v1
209 kind: KubeSchedulerConfiguration
210 profiles:
211 - pluginConfig:
212 - name: DefaultPreemption
213 args:
214 apiVersion: kubescheduler.config.k8s.io/v1
215 kind: DefaultPreemptionArgs
216 minCandidateNodesPercentage: 50
217 `),
218 wantProfiles: []config.KubeSchedulerProfile{
219 {
220 SchedulerName: "default-scheduler",
221 Plugins: defaults.PluginsV1,
222 PluginConfig: []config.PluginConfig{
223 {
224 Name: "DefaultPreemption",
225 Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 100},
226 },
227 {
228 Name: "InterPodAffinity",
229 Args: &config.InterPodAffinityArgs{
230 HardPodAffinityWeight: 1,
231 },
232 },
233 {
234 Name: "NodeAffinity",
235 Args: &config.NodeAffinityArgs{},
236 },
237 {
238 Name: "NodeResourcesBalancedAllocation",
239 Args: &config.NodeResourcesBalancedAllocationArgs{
240 Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
241 },
242 },
243 {
244 Name: "NodeResourcesFit",
245 Args: &config.NodeResourcesFitArgs{
246 ScoringStrategy: &config.ScoringStrategy{
247 Type: config.LeastAllocated,
248 Resources: []config.ResourceSpec{
249 {Name: "cpu", Weight: 1},
250 {Name: "memory", Weight: 1},
251 },
252 },
253 },
254 },
255 {
256 Name: "PodTopologySpread",
257 Args: &config.PodTopologySpreadArgs{
258 DefaultingType: config.SystemDefaulting,
259 },
260 },
261 {
262 Name: "VolumeBinding",
263 Args: &config.VolumeBindingArgs{
264 BindTimeoutSeconds: 600,
265 },
266 },
267 },
268 },
269 },
270 },
271 {
272 name: "plugin group and kind should match the type",
273 data: []byte(`
274 apiVersion: kubescheduler.config.k8s.io/v1
275 kind: KubeSchedulerConfiguration
276 profiles:
277 - pluginConfig:
278 - name: DefaultPreemption
279 args:
280 apiVersion: kubescheduler.config.k8s.io/v1
281 kind: InterPodAffinityArgs
282 `),
283 wantErr: `decoding .profiles[0].pluginConfig[0]: args for plugin DefaultPreemption were not of type DefaultPreemptionArgs.kubescheduler.config.k8s.io, got InterPodAffinityArgs.kubescheduler.config.k8s.io`,
284 },
285 {
286 name: "v1 NodResourcesFitArgs shape encoding is strict",
287 data: []byte(`
288 apiVersion: kubescheduler.config.k8s.io/v1
289 kind: KubeSchedulerConfiguration
290 profiles:
291 - pluginConfig:
292 - name: NodeResourcesFit
293 args:
294 scoringStrategy:
295 requestedToCapacityRatio:
296 shape:
297 - Score: 2
298 Utilization: 1
299 `),
300 wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Score", unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Utilization"`,
301 },
302 {
303 name: "v1 NodeResourcesFitArgs resources encoding is strict",
304 data: []byte(`
305 apiVersion: kubescheduler.config.k8s.io/v1
306 kind: KubeSchedulerConfiguration
307 profiles:
308 - pluginConfig:
309 - name: NodeResourcesFit
310 args:
311 scoringStrategy:
312 resources:
313 - Name: cpu
314 Weight: 1
315 `),
316 wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.resources[0].Name", unknown field "scoringStrategy.resources[0].Weight"`,
317 },
318 {
319 name: "out-of-tree plugin args",
320 data: []byte(`
321 apiVersion: kubescheduler.config.k8s.io/v1
322 kind: KubeSchedulerConfiguration
323 profiles:
324 - pluginConfig:
325 - name: OutOfTreePlugin
326 args:
327 foo: bar
328 `),
329 wantProfiles: []config.KubeSchedulerProfile{
330 {
331 SchedulerName: "default-scheduler",
332 Plugins: defaults.PluginsV1,
333 PluginConfig: append([]config.PluginConfig{
334 {
335 Name: "OutOfTreePlugin",
336 Args: &runtime.Unknown{
337 ContentType: "application/json",
338 Raw: []byte(`{"foo":"bar"}`),
339 },
340 },
341 }, defaults.PluginConfigsV1...),
342 },
343 },
344 },
345 {
346 name: "empty and no plugin args",
347 data: []byte(`
348 apiVersion: kubescheduler.config.k8s.io/v1
349 kind: KubeSchedulerConfiguration
350 profiles:
351 - pluginConfig:
352 - name: DefaultPreemption
353 args:
354 - name: InterPodAffinity
355 args:
356 - name: NodeResourcesFit
357 - name: OutOfTreePlugin
358 args:
359 - name: VolumeBinding
360 args:
361 - name: PodTopologySpread
362 - name: NodeAffinity
363 - name: NodeResourcesBalancedAllocation
364 `),
365 wantProfiles: []config.KubeSchedulerProfile{
366 {
367 SchedulerName: "default-scheduler",
368 Plugins: defaults.PluginsV1,
369 PluginConfig: []config.PluginConfig{
370 {
371 Name: "DefaultPreemption",
372 Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
373 },
374 {
375 Name: "InterPodAffinity",
376 Args: &config.InterPodAffinityArgs{
377 HardPodAffinityWeight: 1,
378 },
379 },
380 {
381 Name: "NodeResourcesFit",
382 Args: &config.NodeResourcesFitArgs{
383 ScoringStrategy: &config.ScoringStrategy{
384 Type: config.LeastAllocated,
385 Resources: []config.ResourceSpec{
386 {Name: "cpu", Weight: 1},
387 {Name: "memory", Weight: 1},
388 },
389 },
390 },
391 },
392 {Name: "OutOfTreePlugin"},
393 {
394 Name: "VolumeBinding",
395 Args: &config.VolumeBindingArgs{
396 BindTimeoutSeconds: 600,
397 },
398 },
399 {
400 Name: "PodTopologySpread",
401 Args: &config.PodTopologySpreadArgs{
402 DefaultingType: config.SystemDefaulting,
403 },
404 },
405 {
406 Name: "NodeAffinity",
407 Args: &config.NodeAffinityArgs{},
408 },
409 {
410 Name: "NodeResourcesBalancedAllocation",
411 Args: &config.NodeResourcesBalancedAllocationArgs{
412 Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
413 },
414 },
415 },
416 },
417 },
418 },
419 {
420 name: "ignorePreferredTermsOfExistingPods is enabled",
421 data: []byte(`
422 apiVersion: kubescheduler.config.k8s.io/v1
423 kind: KubeSchedulerConfiguration
424 profiles:
425 - pluginConfig:
426 - name: InterPodAffinity
427 args:
428 ignorePreferredTermsOfExistingPods: true
429 `),
430 wantProfiles: []config.KubeSchedulerProfile{
431 {
432 SchedulerName: "default-scheduler",
433 Plugins: defaults.PluginsV1,
434 PluginConfig: []config.PluginConfig{
435 {
436 Name: "InterPodAffinity",
437 Args: &config.InterPodAffinityArgs{
438 HardPodAffinityWeight: 1,
439 IgnorePreferredTermsOfExistingPods: true,
440 },
441 },
442 {
443 Name: "DefaultPreemption",
444 Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
445 },
446 {
447 Name: "NodeAffinity",
448 Args: &config.NodeAffinityArgs{},
449 },
450 {
451 Name: "NodeResourcesBalancedAllocation",
452 Args: &config.NodeResourcesBalancedAllocationArgs{
453 Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
454 },
455 },
456 {
457 Name: "NodeResourcesFit",
458 Args: &config.NodeResourcesFitArgs{
459 ScoringStrategy: &config.ScoringStrategy{
460 Type: config.LeastAllocated,
461 Resources: []config.ResourceSpec{
462 {Name: "cpu", Weight: 1},
463 {Name: "memory", Weight: 1},
464 },
465 },
466 },
467 },
468 {
469 Name: "PodTopologySpread",
470 Args: &config.PodTopologySpreadArgs{
471 DefaultingType: config.SystemDefaulting,
472 },
473 },
474 {
475 Name: "VolumeBinding",
476 Args: &config.VolumeBindingArgs{
477 BindTimeoutSeconds: 600,
478 },
479 },
480 },
481 },
482 },
483 },
484 }
485 decoder := Codecs.UniversalDecoder()
486 for _, tt := range testCases {
487 t.Run(tt.name, func(t *testing.T) {
488 obj, gvk, err := decoder.Decode(tt.data, nil, nil)
489 if err != nil {
490 if tt.wantErr != err.Error() {
491 t.Fatalf("\ngot err:\n\t%v\nwant:\n\t%s", err, tt.wantErr)
492 }
493 return
494 }
495 if len(tt.wantErr) != 0 {
496 t.Fatalf("no error produced, wanted %v", tt.wantErr)
497 }
498 got, ok := obj.(*config.KubeSchedulerConfiguration)
499 if !ok {
500 t.Fatalf("decoded into %s, want %s", gvk, config.SchemeGroupVersion.WithKind("KubeSchedulerConfiguration"))
501 }
502 if diff := cmp.Diff(tt.wantProfiles, got.Profiles); diff != "" {
503 t.Errorf("unexpected configuration (-want,+got):\n%s", diff)
504 }
505 })
506 }
507 }
508
509 func TestCodecsEncodePluginConfig(t *testing.T) {
510 testCases := []struct {
511 name string
512 obj runtime.Object
513 version schema.GroupVersion
514 want string
515 }{
516
517 {
518 name: "v1 in-tree and out-of-tree plugins",
519 version: v1.SchemeGroupVersion,
520 obj: &v1.KubeSchedulerConfiguration{
521 Profiles: []v1.KubeSchedulerProfile{
522 {
523 PluginConfig: []v1.PluginConfig{
524 {
525 Name: "InterPodAffinity",
526 Args: runtime.RawExtension{
527 Object: &v1.InterPodAffinityArgs{
528 HardPodAffinityWeight: ptr.To[int32](5),
529 },
530 },
531 },
532 {
533 Name: "VolumeBinding",
534 Args: runtime.RawExtension{
535 Object: &v1.VolumeBindingArgs{
536 BindTimeoutSeconds: ptr.To[int64](300),
537 Shape: []v1.UtilizationShapePoint{
538 {
539 Utilization: 0,
540 Score: 0,
541 },
542 {
543 Utilization: 100,
544 Score: 10,
545 },
546 },
547 },
548 },
549 },
550 {
551 Name: "NodeResourcesFit",
552 Args: runtime.RawExtension{
553 Object: &v1.NodeResourcesFitArgs{
554 ScoringStrategy: &v1.ScoringStrategy{
555 Type: v1.RequestedToCapacityRatio,
556 Resources: []v1.ResourceSpec{{Name: "cpu", Weight: 1}},
557 RequestedToCapacityRatio: &v1.RequestedToCapacityRatioParam{
558 Shape: []v1.UtilizationShapePoint{
559 {Utilization: 1, Score: 2},
560 },
561 },
562 },
563 },
564 },
565 },
566 {
567 Name: "PodTopologySpread",
568 Args: runtime.RawExtension{
569 Object: &v1.PodTopologySpreadArgs{
570 DefaultConstraints: []corev1.TopologySpreadConstraint{},
571 },
572 },
573 },
574 {
575 Name: "OutOfTreePlugin",
576 Args: runtime.RawExtension{
577 Raw: []byte(`{"foo":"bar"}`),
578 },
579 },
580 },
581 },
582 },
583 },
584 want: `apiVersion: kubescheduler.config.k8s.io/v1
585 clientConnection:
586 acceptContentTypes: ""
587 burst: 0
588 contentType: ""
589 kubeconfig: ""
590 qps: 0
591 kind: KubeSchedulerConfiguration
592 leaderElection:
593 leaderElect: null
594 leaseDuration: 0s
595 renewDeadline: 0s
596 resourceLock: ""
597 resourceName: ""
598 resourceNamespace: ""
599 retryPeriod: 0s
600 profiles:
601 - pluginConfig:
602 - args:
603 apiVersion: kubescheduler.config.k8s.io/v1
604 hardPodAffinityWeight: 5
605 ignorePreferredTermsOfExistingPods: false
606 kind: InterPodAffinityArgs
607 name: InterPodAffinity
608 - args:
609 apiVersion: kubescheduler.config.k8s.io/v1
610 bindTimeoutSeconds: 300
611 kind: VolumeBindingArgs
612 shape:
613 - score: 0
614 utilization: 0
615 - score: 10
616 utilization: 100
617 name: VolumeBinding
618 - args:
619 apiVersion: kubescheduler.config.k8s.io/v1
620 kind: NodeResourcesFitArgs
621 scoringStrategy:
622 requestedToCapacityRatio:
623 shape:
624 - score: 2
625 utilization: 1
626 resources:
627 - name: cpu
628 weight: 1
629 type: RequestedToCapacityRatio
630 name: NodeResourcesFit
631 - args:
632 apiVersion: kubescheduler.config.k8s.io/v1
633 kind: PodTopologySpreadArgs
634 name: PodTopologySpread
635 - args:
636 foo: bar
637 name: OutOfTreePlugin
638 `,
639 },
640 {
641 name: "v1 in-tree and out-of-tree plugins from internal",
642 version: v1.SchemeGroupVersion,
643 obj: &config.KubeSchedulerConfiguration{
644 Parallelism: 8,
645 DelayCacheUntilActive: true,
646 Profiles: []config.KubeSchedulerProfile{
647 {
648 PluginConfig: []config.PluginConfig{
649 {
650 Name: "InterPodAffinity",
651 Args: &config.InterPodAffinityArgs{
652 HardPodAffinityWeight: 5,
653 },
654 },
655 {
656 Name: "NodeResourcesFit",
657 Args: &config.NodeResourcesFitArgs{
658 ScoringStrategy: &config.ScoringStrategy{
659 Type: config.LeastAllocated,
660 Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}},
661 },
662 },
663 },
664 {
665 Name: "VolumeBinding",
666 Args: &config.VolumeBindingArgs{
667 BindTimeoutSeconds: 300,
668 },
669 },
670 {
671 Name: "PodTopologySpread",
672 Args: &config.PodTopologySpreadArgs{},
673 },
674 {
675 Name: "OutOfTreePlugin",
676 Args: &runtime.Unknown{
677 Raw: []byte(`{"foo":"bar"}`),
678 },
679 },
680 },
681 },
682 },
683 },
684 want: `apiVersion: kubescheduler.config.k8s.io/v1
685 clientConnection:
686 acceptContentTypes: ""
687 burst: 0
688 contentType: ""
689 kubeconfig: ""
690 qps: 0
691 delayCacheUntilActive: true
692 enableContentionProfiling: false
693 enableProfiling: false
694 kind: KubeSchedulerConfiguration
695 leaderElection:
696 leaderElect: false
697 leaseDuration: 0s
698 renewDeadline: 0s
699 resourceLock: ""
700 resourceName: ""
701 resourceNamespace: ""
702 retryPeriod: 0s
703 parallelism: 8
704 podInitialBackoffSeconds: 0
705 podMaxBackoffSeconds: 0
706 profiles:
707 - pluginConfig:
708 - args:
709 apiVersion: kubescheduler.config.k8s.io/v1
710 hardPodAffinityWeight: 5
711 ignorePreferredTermsOfExistingPods: false
712 kind: InterPodAffinityArgs
713 name: InterPodAffinity
714 - args:
715 apiVersion: kubescheduler.config.k8s.io/v1
716 kind: NodeResourcesFitArgs
717 scoringStrategy:
718 resources:
719 - name: cpu
720 weight: 1
721 type: LeastAllocated
722 name: NodeResourcesFit
723 - args:
724 apiVersion: kubescheduler.config.k8s.io/v1
725 bindTimeoutSeconds: 300
726 kind: VolumeBindingArgs
727 name: VolumeBinding
728 - args:
729 apiVersion: kubescheduler.config.k8s.io/v1
730 kind: PodTopologySpreadArgs
731 name: PodTopologySpread
732 - args:
733 foo: bar
734 name: OutOfTreePlugin
735 schedulerName: ""
736 `,
737 },
738 {
739 name: "v1 ignorePreferredTermsOfExistingPods is enabled",
740 version: v1.SchemeGroupVersion,
741 obj: &config.KubeSchedulerConfiguration{
742 Parallelism: 8,
743 DelayCacheUntilActive: true,
744 Profiles: []config.KubeSchedulerProfile{
745 {
746 PluginConfig: []config.PluginConfig{
747 {
748 Name: "InterPodAffinity",
749 Args: &config.InterPodAffinityArgs{
750 HardPodAffinityWeight: 5,
751 IgnorePreferredTermsOfExistingPods: true,
752 },
753 },
754 },
755 },
756 },
757 },
758 want: `apiVersion: kubescheduler.config.k8s.io/v1
759 clientConnection:
760 acceptContentTypes: ""
761 burst: 0
762 contentType: ""
763 kubeconfig: ""
764 qps: 0
765 delayCacheUntilActive: true
766 enableContentionProfiling: false
767 enableProfiling: false
768 kind: KubeSchedulerConfiguration
769 leaderElection:
770 leaderElect: false
771 leaseDuration: 0s
772 renewDeadline: 0s
773 resourceLock: ""
774 resourceName: ""
775 resourceNamespace: ""
776 retryPeriod: 0s
777 parallelism: 8
778 podInitialBackoffSeconds: 0
779 podMaxBackoffSeconds: 0
780 profiles:
781 - pluginConfig:
782 - args:
783 apiVersion: kubescheduler.config.k8s.io/v1
784 hardPodAffinityWeight: 5
785 ignorePreferredTermsOfExistingPods: true
786 kind: InterPodAffinityArgs
787 name: InterPodAffinity
788 schedulerName: ""
789 `,
790 },
791 }
792 yamlInfo, ok := runtime.SerializerInfoForMediaType(Codecs.SupportedMediaTypes(), runtime.ContentTypeYAML)
793 if !ok {
794 t.Fatalf("unable to locate encoder -- %q is not a supported media type", runtime.ContentTypeYAML)
795 }
796 jsonInfo, ok := runtime.SerializerInfoForMediaType(Codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
797 if !ok {
798 t.Fatalf("unable to locate encoder -- %q is not a supported media type", runtime.ContentTypeJSON)
799 }
800 for _, tt := range testCases {
801 t.Run(tt.name, func(t *testing.T) {
802 encoder := Codecs.EncoderForVersion(yamlInfo.Serializer, tt.version)
803 var buf bytes.Buffer
804 if err := encoder.Encode(tt.obj, &buf); err != nil {
805 t.Fatal(err)
806 }
807 if diff := cmp.Diff(tt.want, buf.String()); diff != "" {
808 t.Errorf("unexpected encoded configuration:\n%s", diff)
809 }
810 encoder = Codecs.EncoderForVersion(jsonInfo.Serializer, tt.version)
811 buf = bytes.Buffer{}
812 if err := encoder.Encode(tt.obj, &buf); err != nil {
813 t.Fatal(err)
814 }
815 out, err := yaml.JSONToYAML(buf.Bytes())
816 if err != nil {
817 t.Fatal(err)
818 }
819 if diff := cmp.Diff(tt.want, string(out)); diff != "" {
820 t.Errorf("unexpected encoded configuration:\n%s", diff)
821 }
822 })
823 }
824 }
825
View as plain text