1
16
17 package memorymanager
18
19 import (
20 "fmt"
21 "reflect"
22 "testing"
23
24 "k8s.io/klog/v2"
25
26 cadvisorapi "github.com/google/cadvisor/info/v1"
27 "github.com/google/go-cmp/cmp"
28
29 v1 "k8s.io/api/core/v1"
30 "k8s.io/apimachinery/pkg/api/resource"
31 "k8s.io/kubernetes/pkg/kubelet/cm/memorymanager/state"
32 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager"
33 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
34 )
35
36 const (
37 mb = 1024 * 1024
38 gb = mb * 1024
39 pageSize1Gb = 1048576
40 hugepages1Gi = v1.ResourceName(v1.ResourceHugePagesPrefix + "1Gi")
41 )
42
43 var (
44 containerRestartPolicyAlways = v1.ContainerRestartPolicyAlways
45
46 requirementsGuaranteed = &v1.ResourceRequirements{
47 Limits: v1.ResourceList{
48 v1.ResourceCPU: resource.MustParse("1000Mi"),
49 v1.ResourceMemory: resource.MustParse("1Gi"),
50 hugepages1Gi: resource.MustParse("1Gi"),
51 },
52 Requests: v1.ResourceList{
53 v1.ResourceCPU: resource.MustParse("1000Mi"),
54 v1.ResourceMemory: resource.MustParse("1Gi"),
55 hugepages1Gi: resource.MustParse("1Gi"),
56 },
57 }
58 requirementsBurstable = &v1.ResourceRequirements{
59 Limits: v1.ResourceList{
60 v1.ResourceCPU: resource.MustParse("1000Mi"),
61 v1.ResourceMemory: resource.MustParse("2Gi"),
62 hugepages1Gi: resource.MustParse("2Gi"),
63 },
64 Requests: v1.ResourceList{
65 v1.ResourceCPU: resource.MustParse("1000Mi"),
66 v1.ResourceMemory: resource.MustParse("1Gi"),
67 hugepages1Gi: resource.MustParse("1Gi"),
68 },
69 }
70 )
71
72 func areMemoryBlocksEqual(mb1, mb2 []state.Block) bool {
73 if len(mb1) != len(mb2) {
74 return false
75 }
76
77 copyMemoryBlocks := make([]state.Block, len(mb2))
78 copy(copyMemoryBlocks, mb2)
79 for _, block := range mb1 {
80 for i, copyBlock := range copyMemoryBlocks {
81 if reflect.DeepEqual(block, copyBlock) {
82
83 copyMemoryBlocks[i] = copyMemoryBlocks[len(copyMemoryBlocks)-1]
84
85
86 copyMemoryBlocks = copyMemoryBlocks[:len(copyMemoryBlocks)-1]
87
88 break
89 }
90 }
91 }
92
93 return len(copyMemoryBlocks) == 0
94 }
95
96 func areContainerMemoryAssignmentsEqual(t *testing.T, cma1, cma2 state.ContainerMemoryAssignments) bool {
97 if len(cma1) != len(cma2) {
98 return false
99 }
100
101 for podUID, container := range cma1 {
102 if _, ok := cma2[podUID]; !ok {
103 t.Logf("[memorymanager_tests] the assignment does not have pod UID %s", podUID)
104 return false
105 }
106
107 for containerName, memoryBlocks := range container {
108 if _, ok := cma2[podUID][containerName]; !ok {
109 t.Logf("[memorymanager_tests] the assignment does not have container name %s", containerName)
110 return false
111 }
112
113 if !areMemoryBlocksEqual(memoryBlocks, cma2[podUID][containerName]) {
114 t.Logf("[memorymanager_tests] assignments memory blocks are different: %v != %v", memoryBlocks, cma2[podUID][containerName])
115 return false
116 }
117 }
118 }
119 return true
120 }
121
122 type testStaticPolicy struct {
123 description string
124 assignments state.ContainerMemoryAssignments
125 expectedAssignments state.ContainerMemoryAssignments
126 machineState state.NUMANodeMap
127 expectedMachineState state.NUMANodeMap
128 systemReserved systemReservedMemory
129 expectedError error
130 machineInfo *cadvisorapi.MachineInfo
131 pod *v1.Pod
132 topologyHint *topologymanager.TopologyHint
133 expectedTopologyHints map[string][]topologymanager.TopologyHint
134 initContainersReusableMemory reusableMemory
135 }
136
137 func initTests(t *testing.T, testCase *testStaticPolicy, hint *topologymanager.TopologyHint, initContainersReusableMemory reusableMemory) (Policy, state.State, error) {
138 manager := topologymanager.NewFakeManager()
139 if hint != nil {
140 manager = topologymanager.NewFakeManagerWithHint(hint)
141 }
142
143 p, err := NewPolicyStatic(testCase.machineInfo, testCase.systemReserved, manager)
144 if err != nil {
145 return nil, nil, err
146 }
147 if initContainersReusableMemory != nil {
148 p.(*staticPolicy).initContainersReusableMemory = initContainersReusableMemory
149 }
150 s := state.NewMemoryState()
151 s.SetMachineState(testCase.machineState)
152 s.SetMemoryAssignments(testCase.assignments)
153 return p, s, nil
154 }
155
156 func newNUMAAffinity(bits ...int) bitmask.BitMask {
157 affinity, err := bitmask.NewBitMask(bits...)
158 if err != nil {
159 panic(err)
160 }
161 return affinity
162 }
163
164 func TestStaticPolicyNew(t *testing.T) {
165 testCases := []testStaticPolicy{
166 {
167 description: "should fail, when machine does not have reserved memory for the system workloads",
168 expectedError: fmt.Errorf("[memorymanager] you should specify the system reserved memory"),
169 },
170 {
171 description: "should succeed, when at least one NUMA node has reserved memory",
172 systemReserved: systemReservedMemory{
173 0: map[v1.ResourceName]uint64{},
174 1: map[v1.ResourceName]uint64{
175 v1.ResourceMemory: 512 * mb,
176 },
177 },
178 },
179 }
180
181 for _, testCase := range testCases {
182 t.Run(testCase.description, func(t *testing.T) {
183 _, _, err := initTests(t, &testCase, nil, nil)
184 if !reflect.DeepEqual(err, testCase.expectedError) {
185 t.Fatalf("The actual error: %v is different from the expected one: %v", err, testCase.expectedError)
186 }
187 })
188 }
189 }
190
191 func TestStaticPolicyName(t *testing.T) {
192 testCases := []testStaticPolicy{
193 {
194 description: "should return the correct policy name",
195 systemReserved: systemReservedMemory{
196 0: map[v1.ResourceName]uint64{
197 v1.ResourceMemory: 512 * mb,
198 },
199 },
200 },
201 }
202 for _, testCase := range testCases {
203 t.Run(testCase.description, func(t *testing.T) {
204 p, _, err := initTests(t, &testCase, nil, nil)
205 if err != nil {
206 t.Fatalf("Unexpected error: %v", err)
207 }
208 if p.Name() != string(policyTypeStatic) {
209 t.Errorf("policy name is different, expected: %q, actual: %q", p.Name(), policyTypeStatic)
210 }
211 })
212 }
213 }
214
215 func TestStaticPolicyStart(t *testing.T) {
216 testCases := []testStaticPolicy{
217 {
218 description: "should fail, if machine state is empty, but it has memory assignments",
219 assignments: state.ContainerMemoryAssignments{
220 "pod": map[string][]state.Block{
221 "container1": {
222 {
223 NUMAAffinity: []int{0},
224 Type: v1.ResourceMemory,
225 Size: 512 * mb,
226 },
227 },
228 },
229 },
230 systemReserved: systemReservedMemory{
231 0: map[v1.ResourceName]uint64{
232 v1.ResourceMemory: 512 * mb,
233 },
234 },
235 expectedError: fmt.Errorf("[memorymanager] machine state can not be empty when it has memory assignments"),
236 },
237 {
238 description: "should fill the state with default values, when the state is empty",
239 expectedAssignments: state.ContainerMemoryAssignments{},
240 expectedMachineState: state.NUMANodeMap{
241 0: &state.NUMANodeState{
242 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
243 v1.ResourceMemory: {
244 Allocatable: 1536 * mb,
245 Free: 1536 * mb,
246 Reserved: 0,
247 SystemReserved: 512 * mb,
248 TotalMemSize: 3 * gb,
249 },
250 hugepages1Gi: {
251 Allocatable: gb,
252 Free: gb,
253 Reserved: 0,
254 SystemReserved: 0,
255 TotalMemSize: gb,
256 },
257 },
258 NumberOfAssignments: 0,
259 Cells: []int{0},
260 },
261 },
262 systemReserved: systemReservedMemory{
263 0: map[v1.ResourceName]uint64{
264 v1.ResourceMemory: 512 * mb,
265 },
266 },
267 machineInfo: &cadvisorapi.MachineInfo{
268 Topology: []cadvisorapi.Node{
269 {
270 Id: 0,
271 Memory: 3 * gb,
272 HugePages: []cadvisorapi.HugePagesInfo{
273 {
274
275 PageSize: pageSize1Gb,
276 NumPages: 1,
277 },
278 },
279 },
280 },
281 },
282 },
283 {
284 description: "should fail when machine state does not have all NUMA nodes",
285 machineState: state.NUMANodeMap{
286 0: &state.NUMANodeState{
287 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
288 v1.ResourceMemory: {
289 Allocatable: 1536 * mb,
290 Free: 1536 * mb,
291 Reserved: 0,
292 SystemReserved: 512 * mb,
293 TotalMemSize: 2 * gb,
294 },
295 hugepages1Gi: {
296 Allocatable: gb,
297 Free: gb,
298 Reserved: 0,
299 SystemReserved: 0,
300 TotalMemSize: gb,
301 },
302 },
303 Cells: []int{0},
304 NumberOfAssignments: 0,
305 },
306 },
307 systemReserved: systemReservedMemory{
308 0: map[v1.ResourceName]uint64{
309 v1.ResourceMemory: 512 * mb,
310 },
311 },
312 machineInfo: &cadvisorapi.MachineInfo{
313 Topology: []cadvisorapi.Node{
314 {
315 Id: 0,
316 Memory: 2 * gb,
317 HugePages: []cadvisorapi.HugePagesInfo{
318 {
319
320 PageSize: pageSize1Gb,
321 NumPages: 1,
322 },
323 },
324 },
325 {
326 Id: 1,
327 Memory: 2 * gb,
328 HugePages: []cadvisorapi.HugePagesInfo{
329 {
330
331 PageSize: pageSize1Gb,
332 NumPages: 1,
333 },
334 },
335 },
336 },
337 },
338 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"),
339 },
340 {
341 description: "should fail when machine state does not have memory resource",
342 machineState: state.NUMANodeMap{
343 0: &state.NUMANodeState{
344 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
345 hugepages1Gi: {
346 Allocatable: gb,
347 Free: gb,
348 Reserved: 0,
349 SystemReserved: 0,
350 TotalMemSize: gb,
351 },
352 },
353 Cells: []int{0},
354 NumberOfAssignments: 0,
355 },
356 },
357 machineInfo: &cadvisorapi.MachineInfo{
358 Topology: []cadvisorapi.Node{
359 {
360 Id: 0,
361 Memory: 2 * gb,
362 HugePages: []cadvisorapi.HugePagesInfo{
363 {
364
365 PageSize: pageSize1Gb,
366 NumPages: 1,
367 },
368 },
369 },
370 },
371 },
372 systemReserved: systemReservedMemory{
373 0: map[v1.ResourceName]uint64{
374 v1.ResourceMemory: 512 * mb,
375 },
376 },
377 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"),
378 },
379 {
380 description: "should fail when machine state has wrong size of total memory",
381 machineState: state.NUMANodeMap{
382 0: &state.NUMANodeState{
383 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
384 v1.ResourceMemory: {
385 Allocatable: 1536 * mb,
386 Free: 1536 * mb,
387 Reserved: 0,
388 SystemReserved: 512 * mb,
389 TotalMemSize: 1536 * mb,
390 },
391 },
392 Cells: []int{0},
393 NumberOfAssignments: 0,
394 },
395 },
396 systemReserved: systemReservedMemory{
397 0: map[v1.ResourceName]uint64{
398 v1.ResourceMemory: 512 * mb,
399 },
400 },
401 machineInfo: &cadvisorapi.MachineInfo{
402 Topology: []cadvisorapi.Node{
403 {
404 Id: 0,
405 Memory: 2 * gb,
406 HugePages: []cadvisorapi.HugePagesInfo{
407 {
408
409 PageSize: pageSize1Gb,
410 NumPages: 1,
411 },
412 },
413 },
414 },
415 },
416 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"),
417 },
418 {
419 description: "should fail when machine state has wrong size of system reserved memory",
420 machineState: state.NUMANodeMap{
421 0: &state.NUMANodeState{
422 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
423 v1.ResourceMemory: {
424 Allocatable: 1536 * mb,
425 Free: 1536 * mb,
426 Reserved: 0,
427 SystemReserved: 1024,
428 TotalMemSize: 2 * gb,
429 },
430 },
431 Cells: []int{0},
432 NumberOfAssignments: 0,
433 },
434 },
435 systemReserved: systemReservedMemory{
436 0: map[v1.ResourceName]uint64{
437 v1.ResourceMemory: 512 * mb,
438 },
439 },
440 machineInfo: &cadvisorapi.MachineInfo{
441 Topology: []cadvisorapi.Node{
442 {
443 Id: 0,
444 Memory: 2 * gb,
445 HugePages: []cadvisorapi.HugePagesInfo{
446 {
447
448 PageSize: pageSize1Gb,
449 NumPages: 1,
450 },
451 },
452 },
453 },
454 },
455 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"),
456 },
457 {
458 description: "should fail when machine state reserved memory is different from the memory of all containers memory assignments",
459 assignments: state.ContainerMemoryAssignments{
460 "pod": map[string][]state.Block{
461 "container1": {
462 {
463 NUMAAffinity: []int{0},
464 Type: v1.ResourceMemory,
465 Size: 512 * mb,
466 },
467 },
468 },
469 },
470 machineState: state.NUMANodeMap{
471 0: &state.NUMANodeState{
472 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
473 v1.ResourceMemory: {
474 Allocatable: 1536 * mb,
475 Free: 1536 * mb,
476 Reserved: 0,
477 SystemReserved: 512 * mb,
478 TotalMemSize: 2 * gb,
479 },
480 },
481 Cells: []int{0},
482 NumberOfAssignments: 1,
483 },
484 },
485 systemReserved: systemReservedMemory{
486 0: map[v1.ResourceName]uint64{
487 v1.ResourceMemory: 512 * mb,
488 },
489 },
490 machineInfo: &cadvisorapi.MachineInfo{
491 Topology: []cadvisorapi.Node{
492 {
493 Id: 0,
494 Memory: 2 * gb,
495 HugePages: []cadvisorapi.HugePagesInfo{
496 {
497
498 PageSize: pageSize1Gb,
499 NumPages: 1,
500 },
501 },
502 },
503 },
504 },
505 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"),
506 },
507 {
508 description: "should fail when machine state has wrong size of hugepages",
509 machineState: state.NUMANodeMap{
510 0: &state.NUMANodeState{
511 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
512 v1.ResourceMemory: {
513 Allocatable: 1536 * mb,
514 Free: 1536 * mb,
515 Reserved: 0,
516 SystemReserved: 512 * mb,
517 TotalMemSize: 2 * gb,
518 },
519 hugepages1Gi: {
520 Allocatable: gb,
521 Free: gb,
522 Reserved: 0,
523 SystemReserved: 0,
524 TotalMemSize: gb,
525 },
526 },
527 Cells: []int{0},
528 NumberOfAssignments: 0,
529 },
530 },
531 systemReserved: systemReservedMemory{
532 0: map[v1.ResourceName]uint64{
533 v1.ResourceMemory: 512 * mb,
534 },
535 },
536 machineInfo: &cadvisorapi.MachineInfo{
537 Topology: []cadvisorapi.Node{
538 {
539 Id: 0,
540 Memory: 2 * gb,
541 HugePages: []cadvisorapi.HugePagesInfo{
542 {
543
544 PageSize: pageSize1Gb,
545 NumPages: 2,
546 },
547 },
548 },
549 },
550 },
551 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"),
552 },
553 {
554 description: "should fail when machine state has wrong size of system reserved hugepages",
555 machineState: state.NUMANodeMap{
556 0: &state.NUMANodeState{
557 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
558 v1.ResourceMemory: {
559 Allocatable: 1536 * mb,
560 Free: 1536 * mb,
561 Reserved: 0,
562 SystemReserved: 512 * mb,
563 TotalMemSize: 2 * gb,
564 },
565 hugepages1Gi: {
566 Allocatable: gb,
567 Free: gb,
568 Reserved: 0,
569 SystemReserved: gb,
570 TotalMemSize: 2 * gb,
571 },
572 },
573 Cells: []int{0},
574 NumberOfAssignments: 0,
575 },
576 },
577 systemReserved: systemReservedMemory{
578 0: map[v1.ResourceName]uint64{
579 v1.ResourceMemory: 512 * mb,
580 },
581 },
582 machineInfo: &cadvisorapi.MachineInfo{
583 Topology: []cadvisorapi.Node{
584 {
585 Id: 0,
586 Memory: 2 * gb,
587 HugePages: []cadvisorapi.HugePagesInfo{
588 {
589
590 PageSize: pageSize1Gb,
591 NumPages: 2,
592 },
593 },
594 },
595 },
596 },
597 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"),
598 },
599 {
600 description: "should fail when the hugepages reserved machine state is different from the hugepages of all containers memory assignments",
601 assignments: state.ContainerMemoryAssignments{
602 "pod1": map[string][]state.Block{
603 "container1": {
604 {
605 NUMAAffinity: []int{0},
606 Type: hugepages1Gi,
607 Size: gb,
608 },
609 },
610 },
611 "pod2": map[string][]state.Block{
612 "container2": {
613 {
614 NUMAAffinity: []int{0},
615 Type: hugepages1Gi,
616 Size: gb,
617 },
618 },
619 },
620 },
621 machineState: state.NUMANodeMap{
622 0: &state.NUMANodeState{
623 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
624 v1.ResourceMemory: {
625 Allocatable: 1536 * mb,
626 Free: 1536 * mb,
627 Reserved: 0,
628 SystemReserved: 512 * mb,
629 TotalMemSize: 2 * gb,
630 },
631 hugepages1Gi: {
632 Allocatable: 4 * gb,
633 Free: gb,
634 Reserved: 3 * gb,
635 SystemReserved: 0,
636 TotalMemSize: 4 * gb,
637 },
638 },
639 Cells: []int{0},
640 NumberOfAssignments: 2,
641 },
642 },
643 systemReserved: systemReservedMemory{
644 0: map[v1.ResourceName]uint64{
645 v1.ResourceMemory: 512 * mb,
646 },
647 },
648 machineInfo: &cadvisorapi.MachineInfo{
649 Topology: []cadvisorapi.Node{
650 {
651 Id: 0,
652 Memory: 2 * gb,
653 HugePages: []cadvisorapi.HugePagesInfo{
654 {
655
656 PageSize: pageSize1Gb,
657 NumPages: 4,
658 },
659 },
660 },
661 },
662 },
663 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"),
664 },
665 {
666 description: "should fail when machine state does not have NUMA node that used under the memory assignment",
667 assignments: state.ContainerMemoryAssignments{
668 "pod1": map[string][]state.Block{
669 "container1": {
670 {
671 NUMAAffinity: []int{1},
672 Type: v1.ResourceMemory,
673 Size: gb,
674 },
675 },
676 },
677 },
678 machineState: state.NUMANodeMap{
679 0: &state.NUMANodeState{
680 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
681 v1.ResourceMemory: {
682 Allocatable: 1536 * mb,
683 Free: 1536 * mb,
684 Reserved: 0,
685 SystemReserved: 512 * mb,
686 TotalMemSize: 2 * gb,
687 },
688 hugepages1Gi: {
689 Allocatable: gb,
690 Free: gb,
691 Reserved: 0,
692 SystemReserved: 0,
693 TotalMemSize: gb,
694 },
695 },
696 Cells: []int{0},
697 NumberOfAssignments: 0,
698 },
699 },
700 systemReserved: systemReservedMemory{
701 0: map[v1.ResourceName]uint64{
702 v1.ResourceMemory: 512 * mb,
703 },
704 },
705 machineInfo: &cadvisorapi.MachineInfo{
706 Topology: []cadvisorapi.Node{
707 {
708 Id: 0,
709 Memory: 2 * gb,
710 HugePages: []cadvisorapi.HugePagesInfo{
711 {
712
713 PageSize: pageSize1Gb,
714 NumPages: 1,
715 },
716 },
717 },
718 },
719 },
720 expectedError: fmt.Errorf("[memorymanager] (pod: pod1, container: container1) the memory assignment uses the NUMA that does not exist"),
721 },
722 {
723 description: "should fail when machine state does not have resource that used under the memory assignment",
724 assignments: state.ContainerMemoryAssignments{
725 "pod1": map[string][]state.Block{
726 "container1": {
727 {
728 NUMAAffinity: []int{0},
729 Type: v1.ResourceMemory,
730 Size: gb,
731 },
732 {
733 NUMAAffinity: []int{0},
734 Type: hugepages2M,
735 Size: gb,
736 },
737 },
738 },
739 },
740 machineState: state.NUMANodeMap{
741 0: &state.NUMANodeState{
742 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
743 v1.ResourceMemory: {
744 Allocatable: 1536 * mb,
745 Free: 1536 * mb,
746 Reserved: 0,
747 SystemReserved: 512 * mb,
748 TotalMemSize: 2 * gb,
749 },
750 hugepages1Gi: {
751 Allocatable: gb,
752 Free: gb,
753 Reserved: 0,
754 SystemReserved: 0,
755 TotalMemSize: gb,
756 },
757 },
758 Cells: []int{0},
759 NumberOfAssignments: 2,
760 },
761 },
762 systemReserved: systemReservedMemory{
763 0: map[v1.ResourceName]uint64{
764 v1.ResourceMemory: 512 * mb,
765 },
766 },
767 machineInfo: &cadvisorapi.MachineInfo{
768 Topology: []cadvisorapi.Node{
769 {
770 Id: 0,
771 Memory: 2 * gb,
772 HugePages: []cadvisorapi.HugePagesInfo{
773 {
774
775 PageSize: pageSize1Gb,
776 NumPages: 1,
777 },
778 },
779 },
780 },
781 },
782 expectedError: fmt.Errorf("[memorymanager] (pod: pod1, container: container1) the memory assignment uses memory resource that does not exist"),
783 },
784 {
785 description: "should fail when machine state number of assignments is different from the expected one",
786 assignments: state.ContainerMemoryAssignments{
787 "pod1": map[string][]state.Block{
788 "container1": {
789 {
790 NUMAAffinity: []int{0},
791 Type: v1.ResourceMemory,
792 Size: gb,
793 },
794 {
795 NUMAAffinity: []int{0},
796 Type: hugepages1Gi,
797 Size: gb,
798 },
799 },
800 },
801 },
802 machineState: state.NUMANodeMap{
803 0: &state.NUMANodeState{
804 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
805 v1.ResourceMemory: {
806 Allocatable: 1536 * mb,
807 Free: 1536 * mb,
808 Reserved: 0,
809 SystemReserved: 512 * mb,
810 TotalMemSize: 2 * gb,
811 },
812 hugepages1Gi: {
813 Allocatable: gb,
814 Free: gb,
815 Reserved: 0,
816 SystemReserved: 0,
817 TotalMemSize: gb,
818 },
819 },
820 Cells: []int{0},
821 NumberOfAssignments: 1,
822 },
823 },
824 systemReserved: systemReservedMemory{
825 0: map[v1.ResourceName]uint64{
826 v1.ResourceMemory: 512 * mb,
827 },
828 },
829 machineInfo: &cadvisorapi.MachineInfo{
830 Topology: []cadvisorapi.Node{
831 {
832 Id: 0,
833 Memory: 2 * gb,
834 HugePages: []cadvisorapi.HugePagesInfo{
835 {
836
837 PageSize: pageSize1Gb,
838 NumPages: 1,
839 },
840 },
841 },
842 },
843 },
844 expectedError: fmt.Errorf("[memorymanager] the expected machine state is different from the real one"),
845 },
846 {
847 description: "should validate cross NUMA reserved memory vs container assignments",
848 assignments: state.ContainerMemoryAssignments{
849 "pod1": map[string][]state.Block{
850 "container1": {
851 {
852 NUMAAffinity: []int{0, 1},
853 Type: v1.ResourceMemory,
854 Size: 768 * mb,
855 },
856 {
857 NUMAAffinity: []int{0, 1},
858 Type: hugepages1Gi,
859 Size: gb,
860 },
861 },
862 },
863 "pod2": map[string][]state.Block{
864 "container2": {
865 {
866 NUMAAffinity: []int{0, 1},
867 Type: v1.ResourceMemory,
868 Size: 256 * mb,
869 },
870 {
871 NUMAAffinity: []int{0, 1},
872 Type: hugepages1Gi,
873 Size: gb,
874 },
875 },
876 },
877 },
878 expectedAssignments: state.ContainerMemoryAssignments{
879 "pod1": map[string][]state.Block{
880 "container1": {
881 {
882 NUMAAffinity: []int{0, 1},
883 Type: v1.ResourceMemory,
884 Size: 768 * mb,
885 },
886 {
887 NUMAAffinity: []int{0, 1},
888 Type: hugepages1Gi,
889 Size: gb,
890 },
891 },
892 },
893 "pod2": map[string][]state.Block{
894 "container2": {
895 {
896 NUMAAffinity: []int{0, 1},
897 Type: v1.ResourceMemory,
898 Size: 256 * mb,
899 },
900 {
901 NUMAAffinity: []int{0, 1},
902 Type: hugepages1Gi,
903 Size: gb,
904 },
905 },
906 },
907 },
908 machineState: state.NUMANodeMap{
909 0: &state.NUMANodeState{
910 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
911 v1.ResourceMemory: {
912 Allocatable: 640 * mb,
913 Free: 0,
914 Reserved: 640 * mb,
915 SystemReserved: 512 * mb,
916 TotalMemSize: 2176 * mb,
917 },
918 hugepages1Gi: {
919 Allocatable: gb,
920 Free: 0,
921 Reserved: gb,
922 SystemReserved: 0,
923 TotalMemSize: gb,
924 },
925 },
926 Cells: []int{0, 1},
927 NumberOfAssignments: 4,
928 },
929 1: &state.NUMANodeState{
930 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
931 v1.ResourceMemory: {
932 Allocatable: 640 * mb,
933 Free: 256 * mb,
934 Reserved: 384 * mb,
935 SystemReserved: 512 * mb,
936 TotalMemSize: 2176 * mb,
937 },
938 hugepages1Gi: {
939 Allocatable: gb,
940 Free: 0,
941 Reserved: gb,
942 SystemReserved: 0,
943 TotalMemSize: gb,
944 },
945 },
946 Cells: []int{0, 1},
947 NumberOfAssignments: 4,
948 },
949 },
950 expectedMachineState: state.NUMANodeMap{
951 0: &state.NUMANodeState{
952 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
953 v1.ResourceMemory: {
954 Allocatable: 640 * mb,
955 Free: 0,
956 Reserved: 640 * mb,
957 SystemReserved: 512 * mb,
958 TotalMemSize: 2176 * mb,
959 },
960 hugepages1Gi: {
961 Allocatable: gb,
962 Free: 0,
963 Reserved: gb,
964 SystemReserved: 0,
965 TotalMemSize: gb,
966 },
967 },
968 Cells: []int{0, 1},
969 NumberOfAssignments: 4,
970 },
971 1: &state.NUMANodeState{
972 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
973 v1.ResourceMemory: {
974 Allocatable: 640 * mb,
975 Free: 256 * mb,
976 Reserved: 384 * mb,
977 SystemReserved: 512 * mb,
978 TotalMemSize: 2176 * mb,
979 },
980 hugepages1Gi: {
981 Allocatable: gb,
982 Free: 0,
983 Reserved: gb,
984 SystemReserved: 0,
985 TotalMemSize: gb,
986 },
987 },
988 Cells: []int{0, 1},
989 NumberOfAssignments: 4,
990 },
991 },
992 systemReserved: systemReservedMemory{
993 0: map[v1.ResourceName]uint64{
994 v1.ResourceMemory: 512 * mb,
995 },
996 1: map[v1.ResourceName]uint64{
997 v1.ResourceMemory: 512 * mb,
998 },
999 },
1000 machineInfo: &cadvisorapi.MachineInfo{
1001 Topology: []cadvisorapi.Node{
1002 {
1003 Id: 0,
1004 Memory: 2176 * mb,
1005 HugePages: []cadvisorapi.HugePagesInfo{
1006 {
1007
1008 PageSize: pageSize1Gb,
1009 NumPages: 1,
1010 },
1011 },
1012 },
1013 {
1014 Id: 1,
1015 Memory: 2176 * mb,
1016 HugePages: []cadvisorapi.HugePagesInfo{
1017 {
1018
1019 PageSize: pageSize1Gb,
1020 NumPages: 1,
1021 },
1022 },
1023 },
1024 },
1025 },
1026 },
1027 }
1028
1029 for _, testCase := range testCases {
1030 t.Run(testCase.description, func(t *testing.T) {
1031 t.Logf("[Start] %s", testCase.description)
1032 p, s, err := initTests(t, &testCase, nil, nil)
1033 if err != nil {
1034 t.Fatalf("Unexpected error: %v", err)
1035 }
1036
1037 err = p.Start(s)
1038 if !reflect.DeepEqual(err, testCase.expectedError) {
1039 t.Fatalf("The actual error: %v is different from the expected one: %v", err, testCase.expectedError)
1040 }
1041
1042 if err != nil {
1043 return
1044 }
1045
1046 assignments := s.GetMemoryAssignments()
1047 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) {
1048 t.Fatalf("Actual assignments: %v is different from the expected one: %v", assignments, testCase.expectedAssignments)
1049 }
1050
1051 machineState := s.GetMachineState()
1052 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) {
1053 t.Fatalf("The actual machine state: %v is different from the expected one: %v", machineState, testCase.expectedMachineState)
1054 }
1055 })
1056 }
1057 }
1058
1059 func TestStaticPolicyAllocate(t *testing.T) {
1060 testCases := []testStaticPolicy{
1061 {
1062 description: "should do nothing for non-guaranteed pods",
1063 expectedAssignments: state.ContainerMemoryAssignments{},
1064 machineState: state.NUMANodeMap{
1065 0: &state.NUMANodeState{
1066 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1067 v1.ResourceMemory: {
1068 Allocatable: 1536 * mb,
1069 Free: 1536 * mb,
1070 Reserved: 0,
1071 SystemReserved: 512 * mb,
1072 TotalMemSize: 2 * gb,
1073 },
1074 hugepages1Gi: {
1075 Allocatable: gb,
1076 Free: gb,
1077 Reserved: 0,
1078 SystemReserved: 0,
1079 TotalMemSize: gb,
1080 },
1081 },
1082 Cells: []int{},
1083 },
1084 },
1085 expectedMachineState: state.NUMANodeMap{
1086 0: &state.NUMANodeState{
1087 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1088 v1.ResourceMemory: {
1089 Allocatable: 1536 * mb,
1090 Free: 1536 * mb,
1091 Reserved: 0,
1092 SystemReserved: 512 * mb,
1093 TotalMemSize: 2 * gb,
1094 },
1095 hugepages1Gi: {
1096 Allocatable: gb,
1097 Free: gb,
1098 Reserved: 0,
1099 SystemReserved: 0,
1100 TotalMemSize: gb,
1101 },
1102 },
1103 Cells: []int{},
1104 },
1105 },
1106 systemReserved: systemReservedMemory{
1107 0: map[v1.ResourceName]uint64{
1108 v1.ResourceMemory: 512 * mb,
1109 },
1110 },
1111 pod: getPod("pod1", "container1", requirementsBurstable),
1112 expectedTopologyHints: nil,
1113 topologyHint: &topologymanager.TopologyHint{},
1114 },
1115 {
1116 description: "should do nothing once container already exists under the state file",
1117 assignments: state.ContainerMemoryAssignments{
1118 "pod1": map[string][]state.Block{
1119 "container1": {
1120 {
1121 NUMAAffinity: []int{0},
1122 Type: v1.ResourceMemory,
1123 Size: gb,
1124 },
1125 },
1126 },
1127 },
1128 expectedAssignments: state.ContainerMemoryAssignments{
1129 "pod1": map[string][]state.Block{
1130 "container1": {
1131 {
1132 NUMAAffinity: []int{0},
1133 Type: v1.ResourceMemory,
1134 Size: gb,
1135 },
1136 },
1137 },
1138 },
1139 machineState: state.NUMANodeMap{
1140 0: &state.NUMANodeState{
1141 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1142 v1.ResourceMemory: {
1143 Allocatable: 1536 * mb,
1144 Free: 512 * mb,
1145 Reserved: 1024 * mb,
1146 SystemReserved: 512 * mb,
1147 TotalMemSize: 2 * gb,
1148 },
1149 hugepages1Gi: {
1150 Allocatable: gb,
1151 Free: gb,
1152 Reserved: 0,
1153 SystemReserved: 0,
1154 TotalMemSize: gb,
1155 },
1156 },
1157 Cells: []int{},
1158 },
1159 },
1160 expectedMachineState: state.NUMANodeMap{
1161 0: &state.NUMANodeState{
1162 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1163 v1.ResourceMemory: {
1164 Allocatable: 1536 * mb,
1165 Free: 512 * mb,
1166 Reserved: 1024 * mb,
1167 SystemReserved: 512 * mb,
1168 TotalMemSize: 2 * gb,
1169 },
1170 hugepages1Gi: {
1171 Allocatable: gb,
1172 Free: gb,
1173 Reserved: 0,
1174 SystemReserved: 0,
1175 TotalMemSize: gb,
1176 },
1177 },
1178 Cells: []int{},
1179 },
1180 },
1181 systemReserved: systemReservedMemory{
1182 0: map[v1.ResourceName]uint64{
1183 v1.ResourceMemory: 512 * mb,
1184 },
1185 },
1186 pod: getPod("pod1", "container1", requirementsGuaranteed),
1187 expectedTopologyHints: nil,
1188 topologyHint: &topologymanager.TopologyHint{},
1189 },
1190 {
1191 description: "should calculate a default topology hint when no NUMA affinity was provided by the topology manager hint",
1192 assignments: state.ContainerMemoryAssignments{},
1193 expectedAssignments: state.ContainerMemoryAssignments{
1194 "pod1": map[string][]state.Block{
1195 "container1": {
1196 {
1197 NUMAAffinity: []int{0},
1198 Type: v1.ResourceMemory,
1199 Size: gb,
1200 },
1201 {
1202 NUMAAffinity: []int{0},
1203 Type: hugepages1Gi,
1204 Size: gb,
1205 },
1206 },
1207 },
1208 },
1209 machineState: state.NUMANodeMap{
1210 0: &state.NUMANodeState{
1211 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1212 v1.ResourceMemory: {
1213 Allocatable: 1536 * mb,
1214 Free: 1536 * mb,
1215 Reserved: 0,
1216 SystemReserved: 512 * mb,
1217 TotalMemSize: 2 * gb,
1218 },
1219 hugepages1Gi: {
1220 Allocatable: gb,
1221 Free: gb,
1222 Reserved: 0,
1223 SystemReserved: 0,
1224 TotalMemSize: gb,
1225 },
1226 },
1227 Cells: []int{0},
1228 },
1229 },
1230 expectedMachineState: state.NUMANodeMap{
1231 0: &state.NUMANodeState{
1232 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1233 v1.ResourceMemory: {
1234 Allocatable: 1536 * mb,
1235 Free: 512 * mb,
1236 Reserved: 1024 * mb,
1237 SystemReserved: 512 * mb,
1238 TotalMemSize: 2 * gb,
1239 },
1240 hugepages1Gi: {
1241 Allocatable: gb,
1242 Free: 0,
1243 Reserved: gb,
1244 SystemReserved: 0,
1245 TotalMemSize: gb,
1246 },
1247 },
1248 Cells: []int{0},
1249 NumberOfAssignments: 2,
1250 },
1251 },
1252 systemReserved: systemReservedMemory{
1253 0: map[v1.ResourceName]uint64{
1254 v1.ResourceMemory: 512 * mb,
1255 },
1256 },
1257 pod: getPod("pod1", "container1", requirementsGuaranteed),
1258 topologyHint: &topologymanager.TopologyHint{},
1259 },
1260 {
1261 description: "should fail when no NUMA affinity was provided under the topology manager hint and calculation of the default hint failed",
1262 assignments: state.ContainerMemoryAssignments{
1263 "pod1": map[string][]state.Block{
1264 "container1": {
1265 {
1266 NUMAAffinity: []int{0},
1267 Type: v1.ResourceMemory,
1268 Size: gb,
1269 },
1270 {
1271 NUMAAffinity: []int{0},
1272 Type: hugepages1Gi,
1273 Size: gb,
1274 },
1275 },
1276 },
1277 },
1278 machineState: state.NUMANodeMap{
1279 0: &state.NUMANodeState{
1280 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1281 v1.ResourceMemory: {
1282 Allocatable: 1536 * mb,
1283 Free: 512 * mb,
1284 Reserved: 1024 * mb,
1285 SystemReserved: 512 * mb,
1286 TotalMemSize: 2 * gb,
1287 },
1288 hugepages1Gi: {
1289 Allocatable: gb,
1290 Free: 0,
1291 Reserved: gb,
1292 SystemReserved: 0,
1293 TotalMemSize: gb,
1294 },
1295 },
1296 Cells: []int{0},
1297 NumberOfAssignments: 2,
1298 },
1299 },
1300 systemReserved: systemReservedMemory{
1301 0: map[v1.ResourceName]uint64{
1302 v1.ResourceMemory: 512 * mb,
1303 },
1304 },
1305 pod: getPod("pod2", "container2", requirementsGuaranteed),
1306 expectedError: fmt.Errorf("[memorymanager] failed to get the default NUMA affinity, no NUMA nodes with enough memory is available"),
1307 topologyHint: &topologymanager.TopologyHint{},
1308 },
1309 {
1310 description: "should fail when no NUMA affinity was provided under the topology manager preferred hint and default hint has preferred false",
1311 assignments: state.ContainerMemoryAssignments{
1312 "pod1": map[string][]state.Block{
1313 "container1": {
1314 {
1315 NUMAAffinity: []int{0},
1316 Type: v1.ResourceMemory,
1317 Size: 512 * mb,
1318 },
1319 },
1320 },
1321 },
1322 machineState: state.NUMANodeMap{
1323 0: &state.NUMANodeState{
1324 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1325 v1.ResourceMemory: {
1326 Allocatable: gb,
1327 Free: 512 * mb,
1328 Reserved: 512 * mb,
1329 SystemReserved: 512 * mb,
1330 TotalMemSize: 1536 * mb,
1331 },
1332 hugepages1Gi: {
1333 Allocatable: gb,
1334 Free: gb,
1335 Reserved: 0,
1336 SystemReserved: 0,
1337 TotalMemSize: gb,
1338 },
1339 },
1340 Cells: []int{0},
1341 NumberOfAssignments: 1,
1342 },
1343 1: &state.NUMANodeState{
1344 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1345 v1.ResourceMemory: {
1346 Allocatable: 512 * mb,
1347 Free: 512 * mb,
1348 Reserved: 0,
1349 SystemReserved: 512 * mb,
1350 TotalMemSize: 1536 * mb,
1351 },
1352 hugepages1Gi: {
1353 Allocatable: gb,
1354 Free: gb,
1355 Reserved: 0,
1356 SystemReserved: 0,
1357 TotalMemSize: gb,
1358 },
1359 },
1360 Cells: []int{1},
1361 NumberOfAssignments: 0,
1362 },
1363 2: &state.NUMANodeState{
1364 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1365 v1.ResourceMemory: {
1366 Allocatable: 512 * mb,
1367 Free: 512 * mb,
1368 Reserved: 0,
1369 SystemReserved: 512 * mb,
1370 TotalMemSize: 1536 * mb,
1371 },
1372 hugepages1Gi: {
1373 Allocatable: gb,
1374 Free: gb,
1375 Reserved: 0,
1376 SystemReserved: 0,
1377 TotalMemSize: gb,
1378 },
1379 },
1380 Cells: []int{2},
1381 NumberOfAssignments: 0,
1382 },
1383 },
1384 systemReserved: systemReservedMemory{
1385 0: map[v1.ResourceName]uint64{
1386 v1.ResourceMemory: 512 * mb,
1387 },
1388 1: map[v1.ResourceName]uint64{
1389 v1.ResourceMemory: 512 * mb,
1390 },
1391 2: map[v1.ResourceName]uint64{
1392 v1.ResourceMemory: 512 * mb,
1393 },
1394 },
1395 pod: getPod("pod2", "container2", requirementsGuaranteed),
1396 expectedError: fmt.Errorf("[memorymanager] failed to find the default preferred hint"),
1397 topologyHint: &topologymanager.TopologyHint{Preferred: true},
1398 },
1399 {
1400 description: "should fail when NUMA affinity provided under the topology manager hint did not satisfy container requirements and extended hint generation failed",
1401 machineState: state.NUMANodeMap{
1402 0: &state.NUMANodeState{
1403 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1404 v1.ResourceMemory: {
1405 Allocatable: 512 * mb,
1406 Free: 512 * mb,
1407 Reserved: 0,
1408 SystemReserved: 512 * mb,
1409 TotalMemSize: gb,
1410 },
1411 hugepages1Gi: {
1412 Allocatable: gb,
1413 Free: gb,
1414 Reserved: 0,
1415 SystemReserved: 0,
1416 TotalMemSize: gb,
1417 },
1418 },
1419 Cells: []int{0},
1420 NumberOfAssignments: 0,
1421 },
1422 1: &state.NUMANodeState{
1423 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1424 v1.ResourceMemory: {
1425 Allocatable: 1536 * mb,
1426 Free: 512 * mb,
1427 Reserved: gb,
1428 SystemReserved: 512 * mb,
1429 TotalMemSize: 2 * gb,
1430 },
1431 hugepages1Gi: {
1432 Allocatable: gb,
1433 Free: gb,
1434 Reserved: 0,
1435 SystemReserved: 0,
1436 TotalMemSize: gb,
1437 },
1438 },
1439 Cells: []int{1, 2},
1440 NumberOfAssignments: 1,
1441 },
1442 2: &state.NUMANodeState{
1443 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1444 v1.ResourceMemory: {
1445 Allocatable: 1536 * mb,
1446 Free: 512 * mb,
1447 Reserved: gb,
1448 SystemReserved: 512 * mb,
1449 TotalMemSize: 2 * gb,
1450 },
1451 hugepages1Gi: {
1452 Allocatable: gb,
1453 Free: gb,
1454 Reserved: 0,
1455 SystemReserved: 0,
1456 TotalMemSize: gb,
1457 },
1458 },
1459 Cells: []int{1, 2},
1460 NumberOfAssignments: 1,
1461 },
1462 },
1463 systemReserved: systemReservedMemory{
1464 0: map[v1.ResourceName]uint64{
1465 v1.ResourceMemory: 512 * mb,
1466 },
1467 1: map[v1.ResourceName]uint64{
1468 v1.ResourceMemory: 512 * mb,
1469 },
1470 2: map[v1.ResourceName]uint64{
1471 v1.ResourceMemory: 512 * mb,
1472 },
1473 },
1474 pod: getPod("pod1", "container1", requirementsGuaranteed),
1475 expectedError: fmt.Errorf("[memorymanager] failed to find NUMA nodes to extend the current topology hint"),
1476 topologyHint: &topologymanager.TopologyHint{NUMANodeAffinity: newNUMAAffinity(0), Preferred: false},
1477 },
1478 {
1479 description: "should fail when the topology manager provided the preferred hint and extended hint has preferred false",
1480 assignments: state.ContainerMemoryAssignments{
1481 "pod1": map[string][]state.Block{
1482 "container1": {
1483 {
1484 NUMAAffinity: []int{0},
1485 Type: v1.ResourceMemory,
1486 Size: 512 * mb,
1487 },
1488 },
1489 },
1490 },
1491 machineState: state.NUMANodeMap{
1492 0: &state.NUMANodeState{
1493 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1494 v1.ResourceMemory: {
1495 Allocatable: gb,
1496 Free: 512 * mb,
1497 Reserved: 512 * mb,
1498 SystemReserved: 512 * mb,
1499 TotalMemSize: 1536 * mb,
1500 },
1501 hugepages1Gi: {
1502 Allocatable: gb,
1503 Free: gb,
1504 Reserved: 0,
1505 SystemReserved: 0,
1506 TotalMemSize: gb,
1507 },
1508 },
1509 Cells: []int{0},
1510 NumberOfAssignments: 1,
1511 },
1512 1: &state.NUMANodeState{
1513 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1514 v1.ResourceMemory: {
1515 Allocatable: 512 * mb,
1516 Free: 512 * mb,
1517 Reserved: 0,
1518 SystemReserved: 512 * mb,
1519 TotalMemSize: 1536 * mb,
1520 },
1521 hugepages1Gi: {
1522 Allocatable: gb,
1523 Free: gb,
1524 Reserved: 0,
1525 SystemReserved: 0,
1526 TotalMemSize: gb,
1527 },
1528 },
1529 Cells: []int{1},
1530 NumberOfAssignments: 0,
1531 },
1532 2: &state.NUMANodeState{
1533 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1534 v1.ResourceMemory: {
1535 Allocatable: 512 * mb,
1536 Free: 512 * mb,
1537 Reserved: 0,
1538 SystemReserved: 512 * mb,
1539 TotalMemSize: 1536 * mb,
1540 },
1541 hugepages1Gi: {
1542 Allocatable: gb,
1543 Free: gb,
1544 Reserved: 0,
1545 SystemReserved: 0,
1546 TotalMemSize: gb,
1547 },
1548 },
1549 Cells: []int{2},
1550 NumberOfAssignments: 0,
1551 },
1552 },
1553 systemReserved: systemReservedMemory{
1554 0: map[v1.ResourceName]uint64{
1555 v1.ResourceMemory: 512 * mb,
1556 },
1557 1: map[v1.ResourceName]uint64{
1558 v1.ResourceMemory: 512 * mb,
1559 },
1560 2: map[v1.ResourceName]uint64{
1561 v1.ResourceMemory: 512 * mb,
1562 },
1563 },
1564 pod: getPod("pod2", "container2", requirementsGuaranteed),
1565 expectedError: fmt.Errorf("[memorymanager] failed to find the extended preferred hint"),
1566 topologyHint: &topologymanager.TopologyHint{NUMANodeAffinity: newNUMAAffinity(1), Preferred: true},
1567 },
1568 {
1569 description: "should succeed to allocate memory from multiple NUMA nodes",
1570 assignments: state.ContainerMemoryAssignments{},
1571 expectedAssignments: state.ContainerMemoryAssignments{
1572 "pod1": map[string][]state.Block{
1573 "container1": {
1574 {
1575 NUMAAffinity: []int{0, 1},
1576 Type: v1.ResourceMemory,
1577 Size: gb,
1578 },
1579 {
1580 NUMAAffinity: []int{0, 1},
1581 Type: hugepages1Gi,
1582 Size: gb,
1583 },
1584 },
1585 },
1586 },
1587 machineState: state.NUMANodeMap{
1588 0: &state.NUMANodeState{
1589 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1590 v1.ResourceMemory: {
1591 Allocatable: 512 * mb,
1592 Free: 512 * mb,
1593 Reserved: 0,
1594 SystemReserved: 512 * mb,
1595 TotalMemSize: gb,
1596 },
1597 hugepages1Gi: {
1598 Allocatable: gb,
1599 Free: gb,
1600 Reserved: 0,
1601 SystemReserved: 0,
1602 TotalMemSize: gb,
1603 },
1604 },
1605 Cells: []int{0},
1606 NumberOfAssignments: 0,
1607 },
1608 1: &state.NUMANodeState{
1609 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1610 v1.ResourceMemory: {
1611 Allocatable: 512 * mb,
1612 Free: 512 * mb,
1613 Reserved: 0,
1614 SystemReserved: 512 * mb,
1615 TotalMemSize: gb,
1616 },
1617 hugepages1Gi: {
1618 Allocatable: gb,
1619 Free: gb,
1620 Reserved: 0,
1621 SystemReserved: 0,
1622 TotalMemSize: gb,
1623 },
1624 },
1625 Cells: []int{1},
1626 NumberOfAssignments: 0,
1627 },
1628 2: &state.NUMANodeState{
1629 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1630 v1.ResourceMemory: {
1631 Allocatable: 512 * mb,
1632 Free: 512 * mb,
1633 Reserved: 0,
1634 SystemReserved: 512 * mb,
1635 TotalMemSize: gb,
1636 },
1637 hugepages1Gi: {
1638 Allocatable: gb,
1639 Free: gb,
1640 Reserved: 0,
1641 SystemReserved: 0,
1642 TotalMemSize: gb,
1643 },
1644 },
1645 Cells: []int{2},
1646 NumberOfAssignments: 0,
1647 },
1648 3: &state.NUMANodeState{
1649 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1650 v1.ResourceMemory: {
1651 Allocatable: 512 * mb,
1652 Free: 512 * mb,
1653 Reserved: 0,
1654 SystemReserved: 512 * mb,
1655 TotalMemSize: gb,
1656 },
1657 hugepages1Gi: {
1658 Allocatable: gb,
1659 Free: gb,
1660 Reserved: 0,
1661 SystemReserved: 0,
1662 TotalMemSize: gb,
1663 },
1664 },
1665 Cells: []int{3},
1666 NumberOfAssignments: 0,
1667 },
1668 },
1669 expectedMachineState: state.NUMANodeMap{
1670 0: &state.NUMANodeState{
1671 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1672 v1.ResourceMemory: {
1673 Allocatable: 512 * mb,
1674 Free: 0,
1675 Reserved: 512 * mb,
1676 SystemReserved: 512 * mb,
1677 TotalMemSize: gb,
1678 },
1679 hugepages1Gi: {
1680 Allocatable: gb,
1681 Free: 0,
1682 Reserved: gb,
1683 SystemReserved: 0,
1684 TotalMemSize: gb,
1685 },
1686 },
1687 Cells: []int{0, 1},
1688 NumberOfAssignments: 2,
1689 },
1690 1: &state.NUMANodeState{
1691 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1692 v1.ResourceMemory: {
1693 Allocatable: 512 * mb,
1694 Free: 0,
1695 Reserved: 512 * mb,
1696 SystemReserved: 512 * mb,
1697 TotalMemSize: gb,
1698 },
1699 hugepages1Gi: {
1700 Allocatable: gb,
1701 Free: gb,
1702 Reserved: 0,
1703 SystemReserved: 0,
1704 TotalMemSize: gb,
1705 },
1706 },
1707 Cells: []int{0, 1},
1708 NumberOfAssignments: 2,
1709 },
1710 2: &state.NUMANodeState{
1711 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1712 v1.ResourceMemory: {
1713 Allocatable: 512 * mb,
1714 Free: 512 * mb,
1715 Reserved: 0,
1716 SystemReserved: 512 * mb,
1717 TotalMemSize: gb,
1718 },
1719 hugepages1Gi: {
1720 Allocatable: gb,
1721 Free: gb,
1722 Reserved: 0,
1723 SystemReserved: 0,
1724 TotalMemSize: gb,
1725 },
1726 },
1727 Cells: []int{2},
1728 NumberOfAssignments: 0,
1729 },
1730 3: &state.NUMANodeState{
1731 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1732 v1.ResourceMemory: {
1733 Allocatable: 512 * mb,
1734 Free: 512 * mb,
1735 Reserved: 0,
1736 SystemReserved: 512 * mb,
1737 TotalMemSize: gb,
1738 },
1739 hugepages1Gi: {
1740 Allocatable: gb,
1741 Free: gb,
1742 Reserved: 0,
1743 SystemReserved: 0,
1744 TotalMemSize: gb,
1745 },
1746 },
1747 Cells: []int{3},
1748 NumberOfAssignments: 0,
1749 },
1750 },
1751 systemReserved: systemReservedMemory{
1752 0: map[v1.ResourceName]uint64{
1753 v1.ResourceMemory: 512 * mb,
1754 },
1755 1: map[v1.ResourceName]uint64{
1756 v1.ResourceMemory: 512 * mb,
1757 },
1758 2: map[v1.ResourceName]uint64{
1759 v1.ResourceMemory: 512 * mb,
1760 },
1761 3: map[v1.ResourceName]uint64{
1762 v1.ResourceMemory: 512 * mb,
1763 },
1764 },
1765 pod: getPod("pod1", "container1", requirementsGuaranteed),
1766 topologyHint: &topologymanager.TopologyHint{Preferred: true},
1767 },
1768 }
1769
1770 for _, testCase := range testCases {
1771 t.Run(testCase.description, func(t *testing.T) {
1772 t.Logf("TestStaticPolicyAllocate %s", testCase.description)
1773 p, s, err := initTests(t, &testCase, testCase.topologyHint, nil)
1774 if err != nil {
1775 t.Fatalf("Unexpected error: %v", err)
1776 }
1777
1778 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.Containers[0])
1779 if !reflect.DeepEqual(err, testCase.expectedError) {
1780 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError)
1781 }
1782
1783 if err != nil {
1784 return
1785 }
1786
1787 assignments := s.GetMemoryAssignments()
1788 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) {
1789 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments)
1790 }
1791
1792 machineState := s.GetMachineState()
1793 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) {
1794 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState)
1795 }
1796 })
1797 }
1798 }
1799
1800 func TestStaticPolicyAllocateWithInitContainers(t *testing.T) {
1801 testCases := []testStaticPolicy{
1802 {
1803 description: "should re-use init containers memory, init containers requests 1Gi and 2Gi, apps containers 3Gi and 4Gi",
1804 assignments: state.ContainerMemoryAssignments{},
1805 expectedAssignments: state.ContainerMemoryAssignments{
1806 "pod1": map[string][]state.Block{
1807 "initContainer1": {
1808 {
1809 NUMAAffinity: []int{0},
1810 Type: v1.ResourceMemory,
1811 Size: 0,
1812 },
1813 {
1814 NUMAAffinity: []int{0},
1815 Type: hugepages1Gi,
1816 Size: 0,
1817 },
1818 },
1819 "initContainer2": {
1820 {
1821 NUMAAffinity: []int{0},
1822 Type: v1.ResourceMemory,
1823 Size: 0,
1824 },
1825 {
1826 NUMAAffinity: []int{0},
1827 Type: hugepages1Gi,
1828 Size: 0,
1829 },
1830 },
1831 "container1": {
1832 {
1833 NUMAAffinity: []int{0},
1834 Type: v1.ResourceMemory,
1835 Size: 3 * gb,
1836 },
1837 {
1838 NUMAAffinity: []int{0},
1839 Type: hugepages1Gi,
1840 Size: 3 * gb,
1841 },
1842 },
1843 "container2": {
1844 {
1845 NUMAAffinity: []int{0},
1846 Type: v1.ResourceMemory,
1847 Size: 4 * gb,
1848 },
1849 {
1850 NUMAAffinity: []int{0},
1851 Type: hugepages1Gi,
1852 Size: 4 * gb,
1853 },
1854 },
1855 },
1856 },
1857 machineState: state.NUMANodeMap{
1858 0: &state.NUMANodeState{
1859 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1860 v1.ResourceMemory: {
1861 Allocatable: 7680 * mb,
1862 Free: 7680 * mb,
1863 Reserved: 0,
1864 SystemReserved: 512 * mb,
1865 TotalMemSize: 8 * gb,
1866 },
1867 hugepages1Gi: {
1868 Allocatable: 8 * gb,
1869 Free: 8 * gb,
1870 Reserved: 0,
1871 SystemReserved: 0,
1872 TotalMemSize: 8 * gb,
1873 },
1874 },
1875 Cells: []int{0},
1876 },
1877 },
1878 expectedMachineState: state.NUMANodeMap{
1879 0: &state.NUMANodeState{
1880 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
1881 v1.ResourceMemory: {
1882 Allocatable: 7680 * mb,
1883 Free: 512 * mb,
1884 Reserved: 7 * gb,
1885 SystemReserved: 512 * mb,
1886 TotalMemSize: 8 * gb,
1887 },
1888 hugepages1Gi: {
1889 Allocatable: 8 * gb,
1890 Free: 1 * gb,
1891 Reserved: 7 * gb,
1892 SystemReserved: 0,
1893 TotalMemSize: 8 * gb,
1894 },
1895 },
1896 Cells: []int{0},
1897 NumberOfAssignments: 8,
1898 },
1899 },
1900 systemReserved: systemReservedMemory{
1901 0: map[v1.ResourceName]uint64{
1902 v1.ResourceMemory: 512 * mb,
1903 },
1904 },
1905 pod: getPodWithInitContainers(
1906 "pod1",
1907 []v1.Container{
1908 {
1909 Name: "container1",
1910 Resources: v1.ResourceRequirements{
1911 Limits: v1.ResourceList{
1912 v1.ResourceCPU: resource.MustParse("1000Mi"),
1913 v1.ResourceMemory: resource.MustParse("3Gi"),
1914 hugepages1Gi: resource.MustParse("3Gi"),
1915 },
1916 Requests: v1.ResourceList{
1917 v1.ResourceCPU: resource.MustParse("1000Mi"),
1918 v1.ResourceMemory: resource.MustParse("3Gi"),
1919 hugepages1Gi: resource.MustParse("3Gi"),
1920 },
1921 },
1922 },
1923 {
1924 Name: "container2",
1925 Resources: v1.ResourceRequirements{
1926 Limits: v1.ResourceList{
1927 v1.ResourceCPU: resource.MustParse("1000Mi"),
1928 v1.ResourceMemory: resource.MustParse("4Gi"),
1929 hugepages1Gi: resource.MustParse("4Gi"),
1930 },
1931 Requests: v1.ResourceList{
1932 v1.ResourceCPU: resource.MustParse("1000Mi"),
1933 v1.ResourceMemory: resource.MustParse("4Gi"),
1934 hugepages1Gi: resource.MustParse("4Gi"),
1935 },
1936 },
1937 },
1938 },
1939 []v1.Container{
1940 {
1941 Name: "initContainer1",
1942 Resources: v1.ResourceRequirements{
1943 Limits: v1.ResourceList{
1944 v1.ResourceCPU: resource.MustParse("1000Mi"),
1945 v1.ResourceMemory: resource.MustParse("1Gi"),
1946 hugepages1Gi: resource.MustParse("1Gi"),
1947 },
1948 Requests: v1.ResourceList{
1949 v1.ResourceCPU: resource.MustParse("1000Mi"),
1950 v1.ResourceMemory: resource.MustParse("1Gi"),
1951 hugepages1Gi: resource.MustParse("1Gi"),
1952 },
1953 },
1954 },
1955 {
1956 Name: "initContainer2",
1957 Resources: v1.ResourceRequirements{
1958 Limits: v1.ResourceList{
1959 v1.ResourceCPU: resource.MustParse("1000Mi"),
1960 v1.ResourceMemory: resource.MustParse("2Gi"),
1961 hugepages1Gi: resource.MustParse("2Gi"),
1962 },
1963 Requests: v1.ResourceList{
1964 v1.ResourceCPU: resource.MustParse("1000Mi"),
1965 v1.ResourceMemory: resource.MustParse("2Gi"),
1966 hugepages1Gi: resource.MustParse("2Gi"),
1967 },
1968 },
1969 },
1970 },
1971 ),
1972 topologyHint: &topologymanager.TopologyHint{},
1973 },
1974 {
1975 description: "should re-use init containers memory, init containers requests 4Gi and 3Gi, apps containers 2Gi and 1Gi",
1976 assignments: state.ContainerMemoryAssignments{},
1977 expectedAssignments: state.ContainerMemoryAssignments{
1978 "pod1": map[string][]state.Block{
1979 "initContainer1": {
1980 {
1981 NUMAAffinity: []int{0},
1982 Type: v1.ResourceMemory,
1983 Size: 0,
1984 },
1985 {
1986 NUMAAffinity: []int{0},
1987 Type: hugepages1Gi,
1988 Size: 0,
1989 },
1990 },
1991 "initContainer2": {
1992 {
1993 NUMAAffinity: []int{0},
1994 Type: v1.ResourceMemory,
1995 Size: gb,
1996 },
1997 {
1998 NUMAAffinity: []int{0},
1999 Type: hugepages1Gi,
2000 Size: gb,
2001 },
2002 },
2003 "container1": {
2004 {
2005 NUMAAffinity: []int{0},
2006 Type: v1.ResourceMemory,
2007 Size: 2 * gb,
2008 },
2009 {
2010 NUMAAffinity: []int{0},
2011 Type: hugepages1Gi,
2012 Size: 2 * gb,
2013 },
2014 },
2015 "container2": {
2016 {
2017 NUMAAffinity: []int{0},
2018 Type: v1.ResourceMemory,
2019 Size: gb,
2020 },
2021 {
2022 NUMAAffinity: []int{0},
2023 Type: hugepages1Gi,
2024 Size: gb,
2025 },
2026 },
2027 },
2028 },
2029 machineState: state.NUMANodeMap{
2030 0: &state.NUMANodeState{
2031 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2032 v1.ResourceMemory: {
2033 Allocatable: 7680 * mb,
2034 Free: 7680 * mb,
2035 Reserved: 0,
2036 SystemReserved: 512 * mb,
2037 TotalMemSize: 8 * gb,
2038 },
2039 hugepages1Gi: {
2040 Allocatable: 8 * gb,
2041 Free: 8 * gb,
2042 Reserved: 0,
2043 SystemReserved: 0,
2044 TotalMemSize: 8 * gb,
2045 },
2046 },
2047 Cells: []int{0},
2048 },
2049 },
2050 expectedMachineState: state.NUMANodeMap{
2051 0: &state.NUMANodeState{
2052 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2053 v1.ResourceMemory: {
2054 Allocatable: 7680 * mb,
2055 Free: 3584 * mb,
2056 Reserved: 4 * gb,
2057 SystemReserved: 512 * mb,
2058 TotalMemSize: 8 * gb,
2059 },
2060 hugepages1Gi: {
2061 Allocatable: 8 * gb,
2062 Free: 4 * gb,
2063 Reserved: 4 * gb,
2064 SystemReserved: 0,
2065 TotalMemSize: 8 * gb,
2066 },
2067 },
2068 Cells: []int{0},
2069 NumberOfAssignments: 8,
2070 },
2071 },
2072 systemReserved: systemReservedMemory{
2073 0: map[v1.ResourceName]uint64{
2074 v1.ResourceMemory: 512 * mb,
2075 },
2076 },
2077 pod: getPodWithInitContainers(
2078 "pod1",
2079 []v1.Container{
2080 {
2081 Name: "container1",
2082 Resources: v1.ResourceRequirements{
2083 Limits: v1.ResourceList{
2084 v1.ResourceCPU: resource.MustParse("1000Mi"),
2085 v1.ResourceMemory: resource.MustParse("2Gi"),
2086 hugepages1Gi: resource.MustParse("2Gi"),
2087 },
2088 Requests: v1.ResourceList{
2089 v1.ResourceCPU: resource.MustParse("1000Mi"),
2090 v1.ResourceMemory: resource.MustParse("2Gi"),
2091 hugepages1Gi: resource.MustParse("2Gi"),
2092 },
2093 },
2094 },
2095 {
2096 Name: "container2",
2097 Resources: v1.ResourceRequirements{
2098 Limits: v1.ResourceList{
2099 v1.ResourceCPU: resource.MustParse("1000Mi"),
2100 v1.ResourceMemory: resource.MustParse("1Gi"),
2101 hugepages1Gi: resource.MustParse("1Gi"),
2102 },
2103 Requests: v1.ResourceList{
2104 v1.ResourceCPU: resource.MustParse("1000Mi"),
2105 v1.ResourceMemory: resource.MustParse("1Gi"),
2106 hugepages1Gi: resource.MustParse("1Gi"),
2107 },
2108 },
2109 },
2110 },
2111 []v1.Container{
2112 {
2113 Name: "initContainer1",
2114 Resources: v1.ResourceRequirements{
2115 Limits: v1.ResourceList{
2116 v1.ResourceCPU: resource.MustParse("1000Mi"),
2117 v1.ResourceMemory: resource.MustParse("4Gi"),
2118 hugepages1Gi: resource.MustParse("4Gi"),
2119 },
2120 Requests: v1.ResourceList{
2121 v1.ResourceCPU: resource.MustParse("1000Mi"),
2122 v1.ResourceMemory: resource.MustParse("4Gi"),
2123 hugepages1Gi: resource.MustParse("4Gi"),
2124 },
2125 },
2126 },
2127 {
2128 Name: "initContainer2",
2129 Resources: v1.ResourceRequirements{
2130 Limits: v1.ResourceList{
2131 v1.ResourceCPU: resource.MustParse("1000Mi"),
2132 v1.ResourceMemory: resource.MustParse("3Gi"),
2133 hugepages1Gi: resource.MustParse("3Gi"),
2134 },
2135 Requests: v1.ResourceList{
2136 v1.ResourceCPU: resource.MustParse("1000Mi"),
2137 v1.ResourceMemory: resource.MustParse("3Gi"),
2138 hugepages1Gi: resource.MustParse("3Gi"),
2139 },
2140 },
2141 },
2142 },
2143 ),
2144 topologyHint: &topologymanager.TopologyHint{},
2145 },
2146 {
2147 description: "should re-use init containers memory, init containers requests 7Gi and 4Gi, apps containers 4Gi and 3Gi",
2148 assignments: state.ContainerMemoryAssignments{},
2149 expectedAssignments: state.ContainerMemoryAssignments{
2150 "pod1": map[string][]state.Block{
2151 "initContainer1": {
2152 {
2153 NUMAAffinity: []int{0},
2154 Type: v1.ResourceMemory,
2155 Size: 0,
2156 },
2157 {
2158 NUMAAffinity: []int{0},
2159 Type: hugepages1Gi,
2160 Size: 0,
2161 },
2162 },
2163 "initContainer2": {
2164 {
2165 NUMAAffinity: []int{0},
2166 Type: v1.ResourceMemory,
2167 Size: 0,
2168 },
2169 {
2170 NUMAAffinity: []int{0},
2171 Type: hugepages1Gi,
2172 Size: 0,
2173 },
2174 },
2175 "container1": {
2176 {
2177 NUMAAffinity: []int{0},
2178 Type: v1.ResourceMemory,
2179 Size: 4 * gb,
2180 },
2181 {
2182 NUMAAffinity: []int{0},
2183 Type: hugepages1Gi,
2184 Size: 4 * gb,
2185 },
2186 },
2187 "container2": {
2188 {
2189 NUMAAffinity: []int{0},
2190 Type: v1.ResourceMemory,
2191 Size: 3 * gb,
2192 },
2193 {
2194 NUMAAffinity: []int{0},
2195 Type: hugepages1Gi,
2196 Size: 3 * gb,
2197 },
2198 },
2199 },
2200 },
2201 machineState: state.NUMANodeMap{
2202 0: &state.NUMANodeState{
2203 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2204 v1.ResourceMemory: {
2205 Allocatable: 7680 * mb,
2206 Free: 7680 * mb,
2207 Reserved: 0,
2208 SystemReserved: 512 * mb,
2209 TotalMemSize: 8 * gb,
2210 },
2211 hugepages1Gi: {
2212 Allocatable: 8 * gb,
2213 Free: 8 * gb,
2214 Reserved: 0,
2215 SystemReserved: 0,
2216 TotalMemSize: 8 * gb,
2217 },
2218 },
2219 Cells: []int{0},
2220 },
2221 },
2222 expectedMachineState: state.NUMANodeMap{
2223 0: &state.NUMANodeState{
2224 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2225 v1.ResourceMemory: {
2226 Allocatable: 7680 * mb,
2227 Free: 512 * mb,
2228 Reserved: 7 * gb,
2229 SystemReserved: 512 * mb,
2230 TotalMemSize: 8 * gb,
2231 },
2232 hugepages1Gi: {
2233 Allocatable: 8 * gb,
2234 Free: 1 * gb,
2235 Reserved: 7 * gb,
2236 SystemReserved: 0,
2237 TotalMemSize: 8 * gb,
2238 },
2239 },
2240 Cells: []int{0},
2241 NumberOfAssignments: 8,
2242 },
2243 },
2244 systemReserved: systemReservedMemory{
2245 0: map[v1.ResourceName]uint64{
2246 v1.ResourceMemory: 512 * mb,
2247 },
2248 },
2249 pod: getPodWithInitContainers(
2250 "pod1",
2251 []v1.Container{
2252 {
2253 Name: "container1",
2254 Resources: v1.ResourceRequirements{
2255 Limits: v1.ResourceList{
2256 v1.ResourceCPU: resource.MustParse("1000Mi"),
2257 v1.ResourceMemory: resource.MustParse("4Gi"),
2258 hugepages1Gi: resource.MustParse("4Gi"),
2259 },
2260 Requests: v1.ResourceList{
2261 v1.ResourceCPU: resource.MustParse("1000Mi"),
2262 v1.ResourceMemory: resource.MustParse("4Gi"),
2263 hugepages1Gi: resource.MustParse("4Gi"),
2264 },
2265 },
2266 },
2267 {
2268 Name: "container2",
2269 Resources: v1.ResourceRequirements{
2270 Limits: v1.ResourceList{
2271 v1.ResourceCPU: resource.MustParse("1000Mi"),
2272 v1.ResourceMemory: resource.MustParse("3Gi"),
2273 hugepages1Gi: resource.MustParse("3Gi"),
2274 },
2275 Requests: v1.ResourceList{
2276 v1.ResourceCPU: resource.MustParse("1000Mi"),
2277 v1.ResourceMemory: resource.MustParse("3Gi"),
2278 hugepages1Gi: resource.MustParse("3Gi"),
2279 },
2280 },
2281 },
2282 },
2283 []v1.Container{
2284 {
2285 Name: "initContainer1",
2286 Resources: v1.ResourceRequirements{
2287 Limits: v1.ResourceList{
2288 v1.ResourceCPU: resource.MustParse("1000Mi"),
2289 v1.ResourceMemory: resource.MustParse("7Gi"),
2290 hugepages1Gi: resource.MustParse("7Gi"),
2291 },
2292 Requests: v1.ResourceList{
2293 v1.ResourceCPU: resource.MustParse("1000Mi"),
2294 v1.ResourceMemory: resource.MustParse("7Gi"),
2295 hugepages1Gi: resource.MustParse("7Gi"),
2296 },
2297 },
2298 },
2299 {
2300 Name: "initContainer2",
2301 Resources: v1.ResourceRequirements{
2302 Limits: v1.ResourceList{
2303 v1.ResourceCPU: resource.MustParse("1000Mi"),
2304 v1.ResourceMemory: resource.MustParse("4Gi"),
2305 hugepages1Gi: resource.MustParse("4Gi"),
2306 },
2307 Requests: v1.ResourceList{
2308 v1.ResourceCPU: resource.MustParse("1000Mi"),
2309 v1.ResourceMemory: resource.MustParse("4Gi"),
2310 hugepages1Gi: resource.MustParse("4Gi"),
2311 },
2312 },
2313 },
2314 },
2315 ),
2316 topologyHint: &topologymanager.TopologyHint{},
2317 },
2318 {
2319 description: "should re-use init containers memory, init containers requests 7Gi and 4Gi, apps containers 5Gi and 2Gi",
2320 assignments: state.ContainerMemoryAssignments{},
2321 initContainersReusableMemory: reusableMemory{"pod0": map[string]map[v1.ResourceName]uint64{}},
2322 expectedAssignments: state.ContainerMemoryAssignments{
2323 "pod1": map[string][]state.Block{
2324 "initContainer1": {
2325 {
2326 NUMAAffinity: []int{0},
2327 Type: v1.ResourceMemory,
2328 Size: 0,
2329 },
2330 {
2331 NUMAAffinity: []int{0},
2332 Type: hugepages1Gi,
2333 Size: 0,
2334 },
2335 },
2336 "initContainer2": {
2337 {
2338 NUMAAffinity: []int{0},
2339 Type: v1.ResourceMemory,
2340 Size: 0,
2341 },
2342 {
2343 NUMAAffinity: []int{0},
2344 Type: hugepages1Gi,
2345 Size: 0,
2346 },
2347 },
2348 "container1": {
2349 {
2350 NUMAAffinity: []int{0},
2351 Type: v1.ResourceMemory,
2352 Size: 5 * gb,
2353 },
2354 {
2355 NUMAAffinity: []int{0},
2356 Type: hugepages1Gi,
2357 Size: 5 * gb,
2358 },
2359 },
2360 "container2": {
2361 {
2362 NUMAAffinity: []int{0},
2363 Type: v1.ResourceMemory,
2364 Size: 2 * gb,
2365 },
2366 {
2367 NUMAAffinity: []int{0},
2368 Type: hugepages1Gi,
2369 Size: 2 * gb,
2370 },
2371 },
2372 },
2373 },
2374 machineState: state.NUMANodeMap{
2375 0: &state.NUMANodeState{
2376 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2377 v1.ResourceMemory: {
2378 Allocatable: 10240 * mb,
2379 Free: 10240 * mb,
2380 Reserved: 0,
2381 SystemReserved: 512 * mb,
2382 TotalMemSize: 10 * gb,
2383 },
2384 hugepages1Gi: {
2385 Allocatable: 10 * gb,
2386 Free: 10 * gb,
2387 Reserved: 0,
2388 SystemReserved: 0,
2389 TotalMemSize: 10 * gb,
2390 },
2391 },
2392 Cells: []int{0},
2393 },
2394 },
2395 expectedMachineState: state.NUMANodeMap{
2396 0: &state.NUMANodeState{
2397 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2398 v1.ResourceMemory: {
2399 Allocatable: 10240 * mb,
2400 Free: 3072 * mb,
2401 Reserved: 7 * gb,
2402 SystemReserved: 512 * mb,
2403 TotalMemSize: 10 * gb,
2404 },
2405 hugepages1Gi: {
2406 Allocatable: 10 * gb,
2407 Free: 3 * gb,
2408 Reserved: 7 * gb,
2409 SystemReserved: 0,
2410 TotalMemSize: 10 * gb,
2411 },
2412 },
2413 Cells: []int{0},
2414 NumberOfAssignments: 8,
2415 },
2416 },
2417 systemReserved: systemReservedMemory{
2418 0: map[v1.ResourceName]uint64{
2419 v1.ResourceMemory: 512 * mb,
2420 },
2421 },
2422 pod: getPodWithInitContainers(
2423 "pod1",
2424 []v1.Container{
2425 {
2426 Name: "container1",
2427 Resources: v1.ResourceRequirements{
2428 Limits: v1.ResourceList{
2429 v1.ResourceCPU: resource.MustParse("1000Mi"),
2430 v1.ResourceMemory: resource.MustParse("5Gi"),
2431 hugepages1Gi: resource.MustParse("5Gi"),
2432 },
2433 Requests: v1.ResourceList{
2434 v1.ResourceCPU: resource.MustParse("1000Mi"),
2435 v1.ResourceMemory: resource.MustParse("5Gi"),
2436 hugepages1Gi: resource.MustParse("5Gi"),
2437 },
2438 },
2439 },
2440 {
2441 Name: "container2",
2442 Resources: v1.ResourceRequirements{
2443 Limits: v1.ResourceList{
2444 v1.ResourceCPU: resource.MustParse("1000Mi"),
2445 v1.ResourceMemory: resource.MustParse("2Gi"),
2446 hugepages1Gi: resource.MustParse("2Gi"),
2447 },
2448 Requests: v1.ResourceList{
2449 v1.ResourceCPU: resource.MustParse("1000Mi"),
2450 v1.ResourceMemory: resource.MustParse("2Gi"),
2451 hugepages1Gi: resource.MustParse("2Gi"),
2452 },
2453 },
2454 },
2455 },
2456 []v1.Container{
2457 {
2458 Name: "initContainer1",
2459 Resources: v1.ResourceRequirements{
2460 Limits: v1.ResourceList{
2461 v1.ResourceCPU: resource.MustParse("1000Mi"),
2462 v1.ResourceMemory: resource.MustParse("7Gi"),
2463 hugepages1Gi: resource.MustParse("7Gi"),
2464 },
2465 Requests: v1.ResourceList{
2466 v1.ResourceCPU: resource.MustParse("1000Mi"),
2467 v1.ResourceMemory: resource.MustParse("7Gi"),
2468 hugepages1Gi: resource.MustParse("7Gi"),
2469 },
2470 },
2471 },
2472 {
2473 Name: "initContainer2",
2474 Resources: v1.ResourceRequirements{
2475 Limits: v1.ResourceList{
2476 v1.ResourceCPU: resource.MustParse("1000Mi"),
2477 v1.ResourceMemory: resource.MustParse("4Gi"),
2478 hugepages1Gi: resource.MustParse("4Gi"),
2479 },
2480 Requests: v1.ResourceList{
2481 v1.ResourceCPU: resource.MustParse("1000Mi"),
2482 v1.ResourceMemory: resource.MustParse("4Gi"),
2483 hugepages1Gi: resource.MustParse("4Gi"),
2484 },
2485 },
2486 },
2487 },
2488 ),
2489 topologyHint: &topologymanager.TopologyHint{},
2490 },
2491 }
2492
2493 for _, testCase := range testCases {
2494 t.Run(testCase.description, func(t *testing.T) {
2495 klog.InfoS("TestStaticPolicyAllocateWithInitContainers", "name", testCase.description)
2496 p, s, err := initTests(t, &testCase, testCase.topologyHint, testCase.initContainersReusableMemory)
2497 if err != nil {
2498 t.Fatalf("Unexpected error: %v", err)
2499 }
2500
2501 for i := range testCase.pod.Spec.InitContainers {
2502 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.InitContainers[i])
2503 if !reflect.DeepEqual(err, testCase.expectedError) {
2504 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError)
2505 }
2506 }
2507
2508 for i := range testCase.pod.Spec.Containers {
2509 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.Containers[i])
2510 if !reflect.DeepEqual(err, testCase.expectedError) {
2511 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError)
2512 }
2513 }
2514
2515 assignments := s.GetMemoryAssignments()
2516 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) {
2517 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments)
2518 }
2519
2520 machineState := s.GetMachineState()
2521 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) {
2522 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState)
2523 }
2524 })
2525 }
2526 }
2527
2528 func TestStaticPolicyAllocateWithRestartableInitContainers(t *testing.T) {
2529 testCases := []testStaticPolicy{
2530 {
2531 description: "should do nothing once containers already exist under the state file",
2532 assignments: state.ContainerMemoryAssignments{
2533 "pod1": map[string][]state.Block{
2534 "initContainer1": {
2535 {
2536 NUMAAffinity: []int{0},
2537 Type: v1.ResourceMemory,
2538 Size: gb,
2539 },
2540 },
2541 "container1": {
2542 {
2543 NUMAAffinity: []int{0},
2544 Type: v1.ResourceMemory,
2545 Size: gb,
2546 },
2547 },
2548 },
2549 },
2550 expectedAssignments: state.ContainerMemoryAssignments{
2551 "pod1": map[string][]state.Block{
2552 "initContainer1": {
2553 {
2554 NUMAAffinity: []int{0},
2555 Type: v1.ResourceMemory,
2556 Size: gb,
2557 },
2558 },
2559 "container1": {
2560 {
2561 NUMAAffinity: []int{0},
2562 Type: v1.ResourceMemory,
2563 Size: gb,
2564 },
2565 },
2566 },
2567 },
2568 machineState: state.NUMANodeMap{
2569 0: &state.NUMANodeState{
2570 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2571 v1.ResourceMemory: {
2572 Allocatable: 2560 * mb,
2573 Free: 512 * mb,
2574 Reserved: 2048 * mb,
2575 SystemReserved: 512 * mb,
2576 TotalMemSize: 3 * gb,
2577 },
2578 hugepages1Gi: {
2579 Allocatable: 2 * gb,
2580 Free: 2 * gb,
2581 Reserved: 0,
2582 SystemReserved: 0,
2583 TotalMemSize: 2 * gb,
2584 },
2585 },
2586 Cells: []int{},
2587 },
2588 },
2589 expectedMachineState: state.NUMANodeMap{
2590 0: &state.NUMANodeState{
2591 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2592 v1.ResourceMemory: {
2593 Allocatable: 2560 * mb,
2594 Free: 512 * mb,
2595 Reserved: 2048 * mb,
2596 SystemReserved: 512 * mb,
2597 TotalMemSize: 3 * gb,
2598 },
2599 hugepages1Gi: {
2600 Allocatable: 2 * gb,
2601 Free: 2 * gb,
2602 Reserved: 0,
2603 SystemReserved: 0,
2604 TotalMemSize: 2 * gb,
2605 },
2606 },
2607 Cells: []int{},
2608 },
2609 },
2610 systemReserved: systemReservedMemory{
2611 0: map[v1.ResourceName]uint64{
2612 v1.ResourceMemory: 512 * mb,
2613 },
2614 },
2615 pod: getPodWithInitContainers(
2616 "pod1",
2617 []v1.Container{
2618 {
2619 Name: "container1",
2620 Resources: *requirementsGuaranteed,
2621 },
2622 },
2623 []v1.Container{
2624 {
2625 Name: "initContainer1",
2626 Resources: *requirementsGuaranteed,
2627 RestartPolicy: &containerRestartPolicyAlways,
2628 },
2629 },
2630 ),
2631 expectedTopologyHints: nil,
2632 topologyHint: &topologymanager.TopologyHint{},
2633 },
2634 {
2635 description: "should not re-use restartable init containers memory",
2636 assignments: state.ContainerMemoryAssignments{},
2637 expectedAssignments: state.ContainerMemoryAssignments{
2638 "pod1": map[string][]state.Block{
2639 "initContainer1": {
2640 {
2641 NUMAAffinity: []int{0},
2642 Type: v1.ResourceMemory,
2643 Size: 0,
2644 },
2645 {
2646 NUMAAffinity: []int{0},
2647 Type: hugepages1Gi,
2648 Size: 0,
2649 },
2650 },
2651 "restartableInitContainer2": {
2652 {
2653 NUMAAffinity: []int{0},
2654 Type: v1.ResourceMemory,
2655 Size: 2 * gb,
2656 },
2657 {
2658 NUMAAffinity: []int{0},
2659 Type: hugepages1Gi,
2660 Size: 2 * gb,
2661 },
2662 },
2663 "initContainer3": {
2664 {
2665 NUMAAffinity: []int{0},
2666 Type: v1.ResourceMemory,
2667 Size: 0,
2668 },
2669 {
2670 NUMAAffinity: []int{0},
2671 Type: hugepages1Gi,
2672 Size: 0,
2673 },
2674 },
2675 "restartableInitContainer4": {
2676 {
2677 NUMAAffinity: []int{0},
2678 Type: v1.ResourceMemory,
2679 Size: 4 * gb,
2680 },
2681 {
2682 NUMAAffinity: []int{0},
2683 Type: hugepages1Gi,
2684 Size: 4 * gb,
2685 },
2686 },
2687 "container1": {
2688 {
2689 NUMAAffinity: []int{0},
2690 Type: v1.ResourceMemory,
2691 Size: 1 * gb,
2692 },
2693 {
2694 NUMAAffinity: []int{0},
2695 Type: hugepages1Gi,
2696 Size: 1 * gb,
2697 },
2698 },
2699 },
2700 },
2701 machineState: state.NUMANodeMap{
2702 0: &state.NUMANodeState{
2703 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2704 v1.ResourceMemory: {
2705 Allocatable: 7 * gb,
2706 Free: 7 * gb,
2707 Reserved: 0,
2708 SystemReserved: 512 * mb,
2709 TotalMemSize: 7680 * mb,
2710 },
2711 hugepages1Gi: {
2712 Allocatable: 7 * gb,
2713 Free: 7 * gb,
2714 Reserved: 0,
2715 SystemReserved: 0,
2716 TotalMemSize: 7 * gb,
2717 },
2718 },
2719 Cells: []int{0},
2720 },
2721 },
2722 expectedMachineState: state.NUMANodeMap{
2723 0: &state.NUMANodeState{
2724 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2725 v1.ResourceMemory: {
2726 Allocatable: 7 * gb,
2727 Free: 0,
2728 Reserved: 7 * gb,
2729 SystemReserved: 512 * mb,
2730 TotalMemSize: 7680 * mb,
2731 },
2732 hugepages1Gi: {
2733 Allocatable: 7 * gb,
2734 Free: 0,
2735 Reserved: 7 * gb,
2736 SystemReserved: 0,
2737 TotalMemSize: 7 * gb,
2738 },
2739 },
2740 Cells: []int{0},
2741 NumberOfAssignments: 10,
2742 },
2743 },
2744 systemReserved: systemReservedMemory{
2745 0: map[v1.ResourceName]uint64{
2746 v1.ResourceMemory: 512 * mb,
2747 },
2748 },
2749 pod: getPodWithInitContainers(
2750 "pod1",
2751 []v1.Container{
2752 {
2753 Name: "container1",
2754 Resources: *requirementsGuaranteed,
2755 },
2756 },
2757 []v1.Container{
2758 {
2759 Name: "initContainer1",
2760 Resources: v1.ResourceRequirements{
2761 Limits: v1.ResourceList{
2762 v1.ResourceCPU: resource.MustParse("1000Mi"),
2763 v1.ResourceMemory: resource.MustParse("1Gi"),
2764 hugepages1Gi: resource.MustParse("1Gi"),
2765 },
2766 Requests: v1.ResourceList{
2767 v1.ResourceCPU: resource.MustParse("1000Mi"),
2768 v1.ResourceMemory: resource.MustParse("1Gi"),
2769 hugepages1Gi: resource.MustParse("1Gi"),
2770 },
2771 },
2772 },
2773 {
2774 Name: "restartableInitContainer2",
2775 Resources: v1.ResourceRequirements{
2776 Limits: v1.ResourceList{
2777 v1.ResourceCPU: resource.MustParse("1000Mi"),
2778 v1.ResourceMemory: resource.MustParse("2Gi"),
2779 hugepages1Gi: resource.MustParse("2Gi"),
2780 },
2781 Requests: v1.ResourceList{
2782 v1.ResourceCPU: resource.MustParse("1000Mi"),
2783 v1.ResourceMemory: resource.MustParse("2Gi"),
2784 hugepages1Gi: resource.MustParse("2Gi"),
2785 },
2786 },
2787 RestartPolicy: &containerRestartPolicyAlways,
2788 },
2789 {
2790 Name: "initContainer3",
2791 Resources: v1.ResourceRequirements{
2792 Limits: v1.ResourceList{
2793 v1.ResourceCPU: resource.MustParse("1000Mi"),
2794 v1.ResourceMemory: resource.MustParse("3Gi"),
2795 hugepages1Gi: resource.MustParse("3Gi"),
2796 },
2797 Requests: v1.ResourceList{
2798 v1.ResourceCPU: resource.MustParse("1000Mi"),
2799 v1.ResourceMemory: resource.MustParse("3Gi"),
2800 hugepages1Gi: resource.MustParse("3Gi"),
2801 },
2802 },
2803 },
2804 {
2805 Name: "restartableInitContainer4",
2806 Resources: v1.ResourceRequirements{
2807 Limits: v1.ResourceList{
2808 v1.ResourceCPU: resource.MustParse("1000Mi"),
2809 v1.ResourceMemory: resource.MustParse("4Gi"),
2810 hugepages1Gi: resource.MustParse("4Gi"),
2811 },
2812 Requests: v1.ResourceList{
2813 v1.ResourceCPU: resource.MustParse("1000Mi"),
2814 v1.ResourceMemory: resource.MustParse("4Gi"),
2815 hugepages1Gi: resource.MustParse("4Gi"),
2816 },
2817 },
2818 RestartPolicy: &containerRestartPolicyAlways,
2819 },
2820 },
2821 ),
2822 topologyHint: &topologymanager.TopologyHint{},
2823 },
2824 }
2825
2826 for _, testCase := range testCases {
2827 t.Run(testCase.description, func(t *testing.T) {
2828 klog.InfoS("TestStaticPolicyAllocateWithRestartableInitContainers", "name", testCase.description)
2829 p, s, err := initTests(t, &testCase, testCase.topologyHint, testCase.initContainersReusableMemory)
2830 if err != nil {
2831 t.Fatalf("Unexpected error: %v", err)
2832 }
2833
2834 for i := range testCase.pod.Spec.InitContainers {
2835 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.InitContainers[i])
2836 if !reflect.DeepEqual(err, testCase.expectedError) {
2837 t.Fatalf("The actual error %v is different from the expected one %v", err, testCase.expectedError)
2838 }
2839 }
2840
2841 if err != nil {
2842 return
2843 }
2844
2845 for i := range testCase.pod.Spec.Containers {
2846 err = p.Allocate(s, testCase.pod, &testCase.pod.Spec.Containers[i])
2847 if err != nil {
2848 t.Fatalf("Unexpected error: %v", err)
2849 }
2850 }
2851
2852 assignments := s.GetMemoryAssignments()
2853 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) {
2854 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments)
2855 }
2856
2857 machineState := s.GetMachineState()
2858 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) {
2859 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState)
2860 }
2861 })
2862 }
2863 }
2864
2865 func TestStaticPolicyRemoveContainer(t *testing.T) {
2866 testCases := []testStaticPolicy{
2867 {
2868 description: "should do nothing when the container does not exist under the state",
2869 expectedAssignments: state.ContainerMemoryAssignments{},
2870 machineState: state.NUMANodeMap{
2871 0: &state.NUMANodeState{
2872 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2873 v1.ResourceMemory: {
2874 Allocatable: 1536 * mb,
2875 Free: 1536 * mb,
2876 Reserved: 0,
2877 SystemReserved: 512 * mb,
2878 TotalMemSize: 2 * gb,
2879 },
2880 hugepages1Gi: {
2881 Allocatable: gb,
2882 Free: gb,
2883 Reserved: 0,
2884 SystemReserved: 0,
2885 TotalMemSize: gb,
2886 },
2887 },
2888 Cells: []int{},
2889 },
2890 },
2891 expectedMachineState: state.NUMANodeMap{
2892 0: &state.NUMANodeState{
2893 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2894 v1.ResourceMemory: {
2895 Allocatable: 1536 * mb,
2896 Free: 1536 * mb,
2897 Reserved: 0,
2898 SystemReserved: 512 * mb,
2899 TotalMemSize: 2 * gb,
2900 },
2901 hugepages1Gi: {
2902 Allocatable: gb,
2903 Free: gb,
2904 Reserved: 0,
2905 SystemReserved: 0,
2906 TotalMemSize: gb,
2907 },
2908 },
2909 Cells: []int{},
2910 },
2911 },
2912 systemReserved: systemReservedMemory{
2913 0: map[v1.ResourceName]uint64{
2914 v1.ResourceMemory: 512 * mb,
2915 },
2916 },
2917 },
2918 {
2919 description: "should delete the container assignment and update the machine state",
2920 assignments: state.ContainerMemoryAssignments{
2921 "pod1": map[string][]state.Block{
2922 "container1": {
2923 {
2924 NUMAAffinity: []int{0},
2925 Type: v1.ResourceMemory,
2926 Size: gb,
2927 },
2928 {
2929 NUMAAffinity: []int{0},
2930 Type: hugepages1Gi,
2931 Size: gb,
2932 },
2933 },
2934 },
2935 },
2936 expectedAssignments: state.ContainerMemoryAssignments{},
2937 machineState: state.NUMANodeMap{
2938 0: &state.NUMANodeState{
2939 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2940 v1.ResourceMemory: {
2941 Allocatable: 1536 * mb,
2942 Free: 512 * mb,
2943 Reserved: 1024 * mb,
2944 SystemReserved: 512 * mb,
2945 TotalMemSize: 2 * gb,
2946 },
2947 hugepages1Gi: {
2948 Allocatable: gb,
2949 Free: 0,
2950 Reserved: gb,
2951 SystemReserved: 0,
2952 TotalMemSize: gb,
2953 },
2954 },
2955 NumberOfAssignments: 2,
2956 Cells: []int{0},
2957 },
2958 },
2959 expectedMachineState: state.NUMANodeMap{
2960 0: &state.NUMANodeState{
2961 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
2962 v1.ResourceMemory: {
2963 Allocatable: 1536 * mb,
2964 Free: 1536 * mb,
2965 Reserved: 0,
2966 SystemReserved: 512 * mb,
2967 TotalMemSize: 2 * gb,
2968 },
2969 hugepages1Gi: {
2970 Allocatable: gb,
2971 Free: gb,
2972 Reserved: 0,
2973 SystemReserved: 0,
2974 TotalMemSize: gb,
2975 },
2976 },
2977 Cells: []int{0},
2978 NumberOfAssignments: 0,
2979 },
2980 },
2981 systemReserved: systemReservedMemory{
2982 0: map[v1.ResourceName]uint64{
2983 v1.ResourceMemory: 512 * mb,
2984 },
2985 },
2986 },
2987 {
2988 description: "should delete the cross NUMA container assignment and update the machine state",
2989 assignments: state.ContainerMemoryAssignments{
2990 "pod1": map[string][]state.Block{
2991 "container1": {
2992 {
2993 NUMAAffinity: []int{0, 1},
2994 Type: v1.ResourceMemory,
2995 Size: gb,
2996 },
2997 {
2998 NUMAAffinity: []int{0, 1},
2999 Type: hugepages1Gi,
3000 Size: gb,
3001 },
3002 },
3003 },
3004 },
3005 expectedAssignments: state.ContainerMemoryAssignments{},
3006 machineState: state.NUMANodeMap{
3007 0: &state.NUMANodeState{
3008 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3009 v1.ResourceMemory: {
3010 Allocatable: 512 * mb,
3011 Free: 0,
3012 Reserved: 512 * mb,
3013 SystemReserved: 512 * mb,
3014 TotalMemSize: gb,
3015 },
3016 hugepages1Gi: {
3017 Allocatable: gb,
3018 Free: 0,
3019 Reserved: gb,
3020 SystemReserved: 0,
3021 TotalMemSize: gb,
3022 },
3023 },
3024 NumberOfAssignments: 2,
3025 Cells: []int{0, 1},
3026 },
3027 1: &state.NUMANodeState{
3028 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3029 v1.ResourceMemory: {
3030 Allocatable: 512 * mb,
3031 Free: 0,
3032 Reserved: 512 * mb,
3033 SystemReserved: 512 * mb,
3034 TotalMemSize: gb,
3035 },
3036 hugepages1Gi: {
3037 Allocatable: gb,
3038 Free: gb,
3039 Reserved: 0,
3040 SystemReserved: 0,
3041 TotalMemSize: gb,
3042 },
3043 },
3044 NumberOfAssignments: 2,
3045 Cells: []int{0, 1},
3046 },
3047 },
3048 expectedMachineState: state.NUMANodeMap{
3049 0: &state.NUMANodeState{
3050 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3051 v1.ResourceMemory: {
3052 Allocatable: 512 * mb,
3053 Free: 512 * mb,
3054 Reserved: 0,
3055 SystemReserved: 512 * mb,
3056 TotalMemSize: gb,
3057 },
3058 hugepages1Gi: {
3059 Allocatable: gb,
3060 Free: gb,
3061 Reserved: 0,
3062 SystemReserved: 0,
3063 TotalMemSize: gb,
3064 },
3065 },
3066 NumberOfAssignments: 0,
3067 Cells: []int{0},
3068 },
3069 1: &state.NUMANodeState{
3070 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3071 v1.ResourceMemory: {
3072 Allocatable: 512 * mb,
3073 Free: 512 * mb,
3074 Reserved: 0,
3075 SystemReserved: 512 * mb,
3076 TotalMemSize: gb,
3077 },
3078 hugepages1Gi: {
3079 Allocatable: gb,
3080 Free: gb,
3081 Reserved: 0,
3082 SystemReserved: 0,
3083 TotalMemSize: gb,
3084 },
3085 },
3086 NumberOfAssignments: 0,
3087 Cells: []int{1},
3088 },
3089 },
3090 systemReserved: systemReservedMemory{
3091 0: map[v1.ResourceName]uint64{
3092 v1.ResourceMemory: 512 * mb,
3093 },
3094 1: map[v1.ResourceName]uint64{
3095 v1.ResourceMemory: 512 * mb,
3096 },
3097 },
3098 },
3099 }
3100
3101 for _, testCase := range testCases {
3102 t.Run(testCase.description, func(t *testing.T) {
3103 p, s, err := initTests(t, &testCase, nil, nil)
3104 if err != nil {
3105 t.Fatalf("Unexpected error: %v", err)
3106 }
3107
3108 p.RemoveContainer(s, "pod1", "container1")
3109 assignments := s.GetMemoryAssignments()
3110 if !areContainerMemoryAssignmentsEqual(t, assignments, testCase.expectedAssignments) {
3111 t.Fatalf("Actual assignments %v are different from the expected %v", assignments, testCase.expectedAssignments)
3112 }
3113
3114 machineState := s.GetMachineState()
3115 if !areMachineStatesEqual(machineState, testCase.expectedMachineState) {
3116 t.Fatalf("The actual machine state %v is different from the expected %v", machineState, testCase.expectedMachineState)
3117 }
3118 })
3119 }
3120 }
3121
3122 func TestStaticPolicyGetTopologyHints(t *testing.T) {
3123 testCases := []testStaticPolicy{
3124 {
3125 description: "should not provide topology hints for non-guaranteed pods",
3126 pod: getPod("pod1", "container1", requirementsBurstable),
3127 systemReserved: systemReservedMemory{
3128 0: map[v1.ResourceName]uint64{
3129 v1.ResourceMemory: 512 * mb,
3130 },
3131 },
3132 expectedTopologyHints: nil,
3133 },
3134 {
3135 description: "should provide topology hints based on the existent memory assignment",
3136 assignments: state.ContainerMemoryAssignments{
3137 "pod1": map[string][]state.Block{
3138 "container1": {
3139 {
3140 NUMAAffinity: []int{0},
3141 Type: v1.ResourceMemory,
3142 Size: gb,
3143 },
3144 {
3145 NUMAAffinity: []int{0},
3146 Type: hugepages1Gi,
3147 Size: gb,
3148 },
3149 },
3150 },
3151 },
3152 pod: getPod("pod1", "container1", requirementsGuaranteed),
3153 systemReserved: systemReservedMemory{
3154 0: map[v1.ResourceName]uint64{
3155 v1.ResourceMemory: 512 * mb,
3156 },
3157 },
3158 expectedTopologyHints: map[string][]topologymanager.TopologyHint{
3159 string(v1.ResourceMemory): {
3160 {
3161 NUMANodeAffinity: newNUMAAffinity(0),
3162 Preferred: true,
3163 },
3164 },
3165 string(hugepages1Gi): {
3166 {
3167 NUMANodeAffinity: newNUMAAffinity(0),
3168 Preferred: true,
3169 },
3170 },
3171 },
3172 },
3173 {
3174 description: "should calculate new topology hints, when the container does not exist under assignments",
3175 assignments: state.ContainerMemoryAssignments{
3176 "pod1": map[string][]state.Block{
3177 "container1": {
3178 {
3179 NUMAAffinity: []int{0, 1},
3180 Type: v1.ResourceMemory,
3181 Size: 2 * gb,
3182 },
3183 {
3184 NUMAAffinity: []int{0, 1},
3185 Type: hugepages1Gi,
3186 Size: 2 * gb,
3187 },
3188 },
3189 },
3190 },
3191 machineState: state.NUMANodeMap{
3192 0: &state.NUMANodeState{
3193 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3194 v1.ResourceMemory: {
3195 Allocatable: 1536 * mb,
3196 Free: 0,
3197 Reserved: 1536 * mb,
3198 SystemReserved: 512 * mb,
3199 TotalMemSize: 2 * gb,
3200 },
3201 hugepages1Gi: {
3202 Allocatable: gb,
3203 Free: 0,
3204 Reserved: gb,
3205 SystemReserved: 0,
3206 TotalMemSize: gb,
3207 },
3208 },
3209 Cells: []int{0, 1},
3210 NumberOfAssignments: 2,
3211 },
3212 1: &state.NUMANodeState{
3213 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3214 v1.ResourceMemory: {
3215 Allocatable: 1536 * mb,
3216 Free: gb,
3217 Reserved: 512 * mb,
3218 SystemReserved: 512 * mb,
3219 TotalMemSize: 2 * gb,
3220 },
3221 hugepages1Gi: {
3222 Allocatable: gb,
3223 Free: 0,
3224 Reserved: gb,
3225 SystemReserved: 0,
3226 TotalMemSize: gb,
3227 },
3228 },
3229 Cells: []int{0, 1},
3230 NumberOfAssignments: 2,
3231 },
3232 2: &state.NUMANodeState{
3233 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3234 v1.ResourceMemory: {
3235 Allocatable: 1536 * mb,
3236 Free: 1536 * mb,
3237 Reserved: 0,
3238 SystemReserved: 512 * mb,
3239 TotalMemSize: 2 * gb,
3240 },
3241 hugepages1Gi: {
3242 Allocatable: gb,
3243 Free: gb,
3244 Reserved: 0,
3245 SystemReserved: 0,
3246 TotalMemSize: gb,
3247 },
3248 },
3249 Cells: []int{2},
3250 NumberOfAssignments: 0,
3251 },
3252 3: &state.NUMANodeState{
3253 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3254 v1.ResourceMemory: {
3255 Allocatable: 1536 * mb,
3256 Free: 1536 * mb,
3257 Reserved: 0,
3258 SystemReserved: 512 * mb,
3259 TotalMemSize: 2 * gb,
3260 },
3261 hugepages1Gi: {
3262 Allocatable: gb,
3263 Free: gb,
3264 Reserved: 0,
3265 SystemReserved: 0,
3266 TotalMemSize: gb,
3267 },
3268 },
3269 Cells: []int{3},
3270 NumberOfAssignments: 0,
3271 },
3272 },
3273 pod: getPod("pod2", "container2", requirementsGuaranteed),
3274 systemReserved: systemReservedMemory{
3275 0: map[v1.ResourceName]uint64{
3276 v1.ResourceMemory: 512 * mb,
3277 },
3278 1: map[v1.ResourceName]uint64{
3279 v1.ResourceMemory: 512 * mb,
3280 },
3281 2: map[v1.ResourceName]uint64{
3282 v1.ResourceMemory: 512 * mb,
3283 },
3284 3: map[v1.ResourceName]uint64{
3285 v1.ResourceMemory: 512 * mb,
3286 },
3287 },
3288 expectedTopologyHints: map[string][]topologymanager.TopologyHint{
3289 string(v1.ResourceMemory): {
3290 {
3291 NUMANodeAffinity: newNUMAAffinity(2),
3292 Preferred: true,
3293 },
3294 {
3295 NUMANodeAffinity: newNUMAAffinity(3),
3296 Preferred: true,
3297 },
3298 {
3299 NUMANodeAffinity: newNUMAAffinity(2, 3),
3300 Preferred: false,
3301 },
3302 },
3303 string(hugepages1Gi): {
3304 {
3305 NUMANodeAffinity: newNUMAAffinity(2),
3306 Preferred: true,
3307 },
3308 {
3309 NUMANodeAffinity: newNUMAAffinity(3),
3310 Preferred: true,
3311 },
3312 {
3313 NUMANodeAffinity: newNUMAAffinity(2, 3),
3314 Preferred: false,
3315 },
3316 },
3317 },
3318 },
3319 {
3320 description: "should fail when number of existing memory assignment resources are different from resources requested by container",
3321 assignments: state.ContainerMemoryAssignments{
3322 "pod1": map[string][]state.Block{
3323 "container1": {
3324 {
3325 NUMAAffinity: []int{0},
3326 Type: v1.ResourceMemory,
3327 Size: gb,
3328 },
3329 },
3330 },
3331 },
3332 pod: getPod("pod1", "container1", requirementsGuaranteed),
3333 systemReserved: systemReservedMemory{
3334 0: map[v1.ResourceName]uint64{
3335 v1.ResourceMemory: 512 * mb,
3336 },
3337 },
3338 expectedTopologyHints: nil,
3339 },
3340 {
3341 description: "should fail when existing memory assignment resources are different from resources requested by container",
3342 assignments: state.ContainerMemoryAssignments{
3343 "pod1": map[string][]state.Block{
3344 "container1": {
3345 {
3346 NUMAAffinity: []int{0},
3347 Type: v1.ResourceMemory,
3348 Size: gb,
3349 },
3350 {
3351 NUMAAffinity: []int{0},
3352 Type: hugepages2M,
3353 Size: gb,
3354 },
3355 },
3356 },
3357 },
3358 pod: getPod("pod1", "container1", requirementsGuaranteed),
3359 systemReserved: systemReservedMemory{
3360 0: map[v1.ResourceName]uint64{
3361 v1.ResourceMemory: 512 * mb,
3362 },
3363 },
3364 expectedTopologyHints: nil,
3365 },
3366 {
3367 description: "should fail when existing memory assignment size is different from one requested by the container",
3368 assignments: state.ContainerMemoryAssignments{
3369 "pod1": map[string][]state.Block{
3370 "container1": {
3371 {
3372 NUMAAffinity: []int{0},
3373 Type: v1.ResourceMemory,
3374 Size: 512 * mb,
3375 },
3376 {
3377 NUMAAffinity: []int{0},
3378 Type: hugepages1Gi,
3379 Size: gb,
3380 },
3381 },
3382 },
3383 },
3384 pod: getPod("pod1", "container1", requirementsGuaranteed),
3385 systemReserved: systemReservedMemory{
3386 0: map[v1.ResourceName]uint64{
3387 v1.ResourceMemory: 512 * mb,
3388 },
3389 },
3390 expectedTopologyHints: nil,
3391 },
3392 {
3393 description: "should not return preferred hints with multiple NUMA nodes for the pod with resources satisfied by a single NUMA node",
3394 assignments: state.ContainerMemoryAssignments{
3395 "pod1": map[string][]state.Block{
3396 "container1": {
3397 {
3398 NUMAAffinity: []int{0, 1},
3399 Type: v1.ResourceMemory,
3400 Size: 2 * gb,
3401 },
3402 {
3403 NUMAAffinity: []int{0, 1},
3404 Type: hugepages2M,
3405 Size: 24 * mb,
3406 },
3407 },
3408 },
3409 },
3410 machineState: state.NUMANodeMap{
3411 0: &state.NUMANodeState{
3412 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3413 v1.ResourceMemory: {
3414 Allocatable: 1536 * mb,
3415 Free: 0,
3416 Reserved: 1536 * mb,
3417 SystemReserved: 512 * mb,
3418 TotalMemSize: 2 * gb,
3419 },
3420 hugepages2M: {
3421 Allocatable: 20 * mb,
3422 Free: 0,
3423 Reserved: 20 * mb,
3424 SystemReserved: 0,
3425 TotalMemSize: 20 * mb,
3426 },
3427 },
3428 Cells: []int{0, 1},
3429 NumberOfAssignments: 2,
3430 },
3431 1: &state.NUMANodeState{
3432 MemoryMap: map[v1.ResourceName]*state.MemoryTable{
3433 v1.ResourceMemory: {
3434 Allocatable: 1536 * mb,
3435 Free: gb,
3436 Reserved: 512 * mb,
3437 SystemReserved: 512 * mb,
3438 TotalMemSize: 2 * gb,
3439 },
3440 hugepages2M: {
3441 Allocatable: 20 * mb,
3442 Free: 16 * mb,
3443 Reserved: 4 * mb,
3444 SystemReserved: 0,
3445 TotalMemSize: 20 * mb,
3446 },
3447 },
3448 Cells: []int{0, 1},
3449 NumberOfAssignments: 2,
3450 },
3451 },
3452 pod: getPod("pod2",
3453 "container2",
3454 &v1.ResourceRequirements{
3455 Limits: v1.ResourceList{
3456 v1.ResourceCPU: resource.MustParse("1000Mi"),
3457 v1.ResourceMemory: resource.MustParse("1Gi"),
3458 hugepages2M: resource.MustParse("16Mi"),
3459 },
3460 Requests: v1.ResourceList{
3461 v1.ResourceCPU: resource.MustParse("1000Mi"),
3462 v1.ResourceMemory: resource.MustParse("1Gi"),
3463 hugepages2M: resource.MustParse("16Mi"),
3464 },
3465 },
3466 ),
3467 systemReserved: systemReservedMemory{
3468 0: map[v1.ResourceName]uint64{
3469 v1.ResourceMemory: 512 * mb,
3470 },
3471 1: map[v1.ResourceName]uint64{
3472 v1.ResourceMemory: 512 * mb,
3473 },
3474 },
3475 expectedTopologyHints: map[string][]topologymanager.TopologyHint{
3476 string(v1.ResourceMemory): {
3477 {
3478 NUMANodeAffinity: newNUMAAffinity(0, 1),
3479 Preferred: false,
3480 },
3481 },
3482 hugepages2M: {
3483 {
3484 NUMANodeAffinity: newNUMAAffinity(0, 1),
3485 Preferred: false,
3486 },
3487 },
3488 },
3489 },
3490 }
3491
3492 for _, testCase := range testCases {
3493 t.Run(testCase.description, func(t *testing.T) {
3494 p, s, err := initTests(t, &testCase, nil, nil)
3495 if err != nil {
3496 t.Fatalf("Unexpected error: %v", err)
3497 }
3498
3499 topologyHints := p.GetTopologyHints(s, testCase.pod, &testCase.pod.Spec.Containers[0])
3500 if !reflect.DeepEqual(topologyHints, testCase.expectedTopologyHints) {
3501 t.Fatalf("The actual topology hints: '%+v' are different from the expected one: '%+v'", topologyHints, testCase.expectedTopologyHints)
3502 }
3503 })
3504 }
3505 }
3506
3507 func Test_getPodRequestedResources(t *testing.T) {
3508 testCases := []struct {
3509 description string
3510 pod *v1.Pod
3511 expected map[v1.ResourceName]uint64
3512 }{
3513 {
3514 description: "maximum resources of init containers > total resources of containers",
3515 pod: getPodWithInitContainers(
3516 "",
3517 []v1.Container{
3518 {
3519 Name: "container1",
3520 Resources: v1.ResourceRequirements{
3521 Requests: v1.ResourceList{
3522 v1.ResourceMemory: resource.MustParse("1Gi"),
3523 hugepages1Gi: resource.MustParse("1Gi"),
3524 },
3525 },
3526 },
3527 {
3528 Name: "container2",
3529 Resources: v1.ResourceRequirements{
3530 Requests: v1.ResourceList{
3531 v1.ResourceMemory: resource.MustParse("2Gi"),
3532 hugepages1Gi: resource.MustParse("2Gi"),
3533 },
3534 },
3535 },
3536 },
3537 []v1.Container{
3538 {
3539 Name: "initContainer1",
3540 Resources: v1.ResourceRequirements{
3541 Requests: v1.ResourceList{
3542 v1.ResourceMemory: resource.MustParse("1Gi"),
3543 hugepages1Gi: resource.MustParse("1Gi"),
3544 },
3545 },
3546 },
3547 {
3548 Name: "initContainer2",
3549 Resources: v1.ResourceRequirements{
3550 Requests: v1.ResourceList{
3551 v1.ResourceMemory: resource.MustParse("4Gi"),
3552 hugepages1Gi: resource.MustParse("4Gi"),
3553 },
3554 },
3555 },
3556 },
3557 ),
3558 expected: map[v1.ResourceName]uint64{
3559 v1.ResourceMemory: 4 * gb,
3560 hugepages1Gi: 4 * gb,
3561 },
3562 },
3563 {
3564 description: "maximum resources of init containers < total resources of containers",
3565 pod: getPodWithInitContainers(
3566 "",
3567 []v1.Container{
3568 {
3569 Name: "container1",
3570 Resources: v1.ResourceRequirements{
3571 Requests: v1.ResourceList{
3572 v1.ResourceMemory: resource.MustParse("2Gi"),
3573 hugepages1Gi: resource.MustParse("2Gi"),
3574 },
3575 },
3576 },
3577 {
3578 Name: "container2",
3579 Resources: v1.ResourceRequirements{
3580 Requests: v1.ResourceList{
3581 v1.ResourceMemory: resource.MustParse("3Gi"),
3582 hugepages1Gi: resource.MustParse("3Gi"),
3583 },
3584 },
3585 },
3586 },
3587 []v1.Container{
3588 {
3589 Name: "initContainer1",
3590 Resources: v1.ResourceRequirements{
3591 Requests: v1.ResourceList{
3592 v1.ResourceMemory: resource.MustParse("1Gi"),
3593 hugepages1Gi: resource.MustParse("1Gi"),
3594 },
3595 },
3596 },
3597 {
3598 Name: "initContainer2",
3599 Resources: v1.ResourceRequirements{
3600 Requests: v1.ResourceList{
3601 v1.ResourceMemory: resource.MustParse("3Gi"),
3602 hugepages1Gi: resource.MustParse("3Gi"),
3603 },
3604 },
3605 },
3606 },
3607 ),
3608 expected: map[v1.ResourceName]uint64{
3609 v1.ResourceMemory: 5 * gb,
3610 hugepages1Gi: 5 * gb,
3611 },
3612 },
3613 {
3614 description: "calculate different resources independently",
3615 pod: getPodWithInitContainers(
3616 "",
3617 []v1.Container{
3618 {
3619 Name: "container1",
3620 Resources: v1.ResourceRequirements{
3621 Requests: v1.ResourceList{
3622 v1.ResourceMemory: resource.MustParse("2Gi"),
3623 hugepages1Gi: resource.MustParse("1Gi"),
3624 },
3625 },
3626 },
3627 {
3628 Name: "container2",
3629 Resources: v1.ResourceRequirements{
3630 Requests: v1.ResourceList{
3631 v1.ResourceMemory: resource.MustParse("3Gi"),
3632 hugepages1Gi: resource.MustParse("2Gi"),
3633 },
3634 },
3635 },
3636 },
3637 []v1.Container{
3638 {
3639 Name: "initContainer1",
3640 Resources: v1.ResourceRequirements{
3641 Requests: v1.ResourceList{
3642 v1.ResourceMemory: resource.MustParse("1Gi"),
3643 hugepages1Gi: resource.MustParse("1Gi"),
3644 },
3645 },
3646 },
3647 {
3648 Name: "initContainer2",
3649 Resources: v1.ResourceRequirements{
3650 Requests: v1.ResourceList{
3651 v1.ResourceMemory: resource.MustParse("3Gi"),
3652 hugepages1Gi: resource.MustParse("4Gi"),
3653 },
3654 },
3655 },
3656 },
3657 ),
3658 expected: map[v1.ResourceName]uint64{
3659 v1.ResourceMemory: 5 * gb,
3660 hugepages1Gi: 4 * gb,
3661 },
3662 },
3663 {
3664 description: "maximum resources of init containers > total resources of long running containers, including restartable init containers",
3665 pod: getPodWithInitContainers(
3666 "",
3667 []v1.Container{
3668 {
3669 Name: "container1",
3670 Resources: v1.ResourceRequirements{
3671 Requests: v1.ResourceList{
3672 v1.ResourceMemory: resource.MustParse("1Gi"),
3673 hugepages1Gi: resource.MustParse("1Gi"),
3674 },
3675 },
3676 },
3677 {
3678 Name: "container2",
3679 Resources: v1.ResourceRequirements{
3680 Requests: v1.ResourceList{
3681 v1.ResourceMemory: resource.MustParse("2Gi"),
3682 hugepages1Gi: resource.MustParse("2Gi"),
3683 },
3684 },
3685 },
3686 },
3687 []v1.Container{
3688 {
3689 Name: "restartableInit1",
3690 Resources: v1.ResourceRequirements{
3691 Requests: v1.ResourceList{
3692 v1.ResourceMemory: resource.MustParse("2Gi"),
3693 hugepages1Gi: resource.MustParse("2Gi"),
3694 },
3695 },
3696 RestartPolicy: &containerRestartPolicyAlways,
3697 },
3698 {
3699 Name: "initContainer2",
3700 Resources: v1.ResourceRequirements{
3701 Requests: v1.ResourceList{
3702 v1.ResourceMemory: resource.MustParse("4Gi"),
3703 hugepages1Gi: resource.MustParse("4Gi"),
3704 },
3705 },
3706 },
3707 },
3708 ),
3709 expected: map[v1.ResourceName]uint64{
3710 v1.ResourceMemory: 6 * gb,
3711 hugepages1Gi: 6 * gb,
3712 },
3713 },
3714 {
3715 description: "maximum resources of init containers < total resources of long running containers, including restartable init containers",
3716 pod: getPodWithInitContainers(
3717 "",
3718 []v1.Container{
3719 {
3720 Name: "container1",
3721 Resources: v1.ResourceRequirements{
3722 Requests: v1.ResourceList{
3723 v1.ResourceMemory: resource.MustParse("2Gi"),
3724 hugepages1Gi: resource.MustParse("2Gi"),
3725 },
3726 },
3727 },
3728 {
3729 Name: "container2",
3730 Resources: v1.ResourceRequirements{
3731 Requests: v1.ResourceList{
3732 v1.ResourceMemory: resource.MustParse("3Gi"),
3733 hugepages1Gi: resource.MustParse("3Gi"),
3734 },
3735 },
3736 },
3737 },
3738 []v1.Container{
3739 {
3740 Name: "restartableInit1",
3741 Resources: v1.ResourceRequirements{
3742 Requests: v1.ResourceList{
3743 v1.ResourceMemory: resource.MustParse("2Gi"),
3744 hugepages1Gi: resource.MustParse("2Gi"),
3745 },
3746 },
3747 RestartPolicy: &containerRestartPolicyAlways,
3748 },
3749 {
3750 Name: "initContainer2",
3751 Resources: v1.ResourceRequirements{
3752 Requests: v1.ResourceList{
3753 v1.ResourceMemory: resource.MustParse("4Gi"),
3754 hugepages1Gi: resource.MustParse("4Gi"),
3755 },
3756 },
3757 },
3758 },
3759 ),
3760 expected: map[v1.ResourceName]uint64{
3761 v1.ResourceMemory: 7 * gb,
3762 hugepages1Gi: 7 * gb,
3763 },
3764 },
3765 }
3766
3767 for _, tc := range testCases {
3768 t.Run(tc.description, func(t *testing.T) {
3769 actual, err := getPodRequestedResources(tc.pod)
3770 if err != nil {
3771 t.Fatalf("Unexpected error: %v", err)
3772 }
3773 if diff := cmp.Diff(actual, tc.expected); diff != "" {
3774 t.Errorf("getPodRequestedResources() mismatch (-want +got):\n%s", diff)
3775 }
3776 })
3777 }
3778 }
3779
View as plain text