1
16
17 package podresources
18
19 import (
20 "context"
21 "fmt"
22 "reflect"
23 "sort"
24 "testing"
25
26 "github.com/golang/mock/gomock"
27 v1 "k8s.io/api/core/v1"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/apimachinery/pkg/types"
30 utilfeature "k8s.io/apiserver/pkg/util/feature"
31 featuregatetesting "k8s.io/component-base/featuregate/testing"
32 podresourcesapi "k8s.io/kubelet/pkg/apis/podresources/v1"
33 pkgfeatures "k8s.io/kubernetes/pkg/features"
34 podresourcetest "k8s.io/kubernetes/pkg/kubelet/apis/podresources/testing"
35 )
36
37 func TestListPodResourcesV1(t *testing.T) {
38 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.KubeletPodResourcesDynamicResources, true)()
39
40 podName := "pod-name"
41 podNamespace := "pod-namespace"
42 podUID := types.UID("pod-uid")
43 containerName := "container-name"
44 numaID := int64(1)
45
46 mockCtrl := gomock.NewController(t)
47 defer mockCtrl.Finish()
48
49 devs := []*podresourcesapi.ContainerDevices{
50 {
51 ResourceName: "resource",
52 DeviceIds: []string{"dev0", "dev1"},
53 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
54 },
55 }
56
57 cpus := []int64{12, 23, 30}
58
59 memory := []*podresourcesapi.ContainerMemory{
60 {
61 MemoryType: "memory",
62 Size_: 1073741824,
63 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
64 },
65 {
66 MemoryType: "hugepages-1Gi",
67 Size_: 1073741824,
68 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
69 },
70 }
71
72 containers := []v1.Container{
73 {
74 Name: containerName,
75 },
76 }
77 pods := []*v1.Pod{
78 {
79 ObjectMeta: metav1.ObjectMeta{
80 Name: podName,
81 Namespace: podNamespace,
82 UID: podUID,
83 },
84 Spec: v1.PodSpec{
85 Containers: containers,
86 },
87 },
88 }
89
90 pluginCDIDevices := []*podresourcesapi.CDIDevice{{Name: "dra-dev0"}, {Name: "dra-dev1"}}
91 draDevs := []*podresourcesapi.DynamicResource{
92 {
93 ClassName: "resource-class",
94 ClaimName: "claim-name",
95 ClaimNamespace: "default",
96 ClaimResources: []*podresourcesapi.ClaimResource{{CDIDevices: pluginCDIDevices}},
97 },
98 }
99
100 for _, tc := range []struct {
101 desc string
102 pods []*v1.Pod
103 devices []*podresourcesapi.ContainerDevices
104 cpus []int64
105 memory []*podresourcesapi.ContainerMemory
106 dynamicResources []*podresourcesapi.DynamicResource
107 expectedResponse *podresourcesapi.ListPodResourcesResponse
108 }{
109 {
110 desc: "no pods",
111 pods: []*v1.Pod{},
112 devices: []*podresourcesapi.ContainerDevices{},
113 cpus: []int64{},
114 memory: []*podresourcesapi.ContainerMemory{},
115 dynamicResources: []*podresourcesapi.DynamicResource{},
116 expectedResponse: &podresourcesapi.ListPodResourcesResponse{},
117 },
118 {
119 desc: "pod without devices",
120 pods: pods,
121 devices: []*podresourcesapi.ContainerDevices{},
122 cpus: []int64{},
123 memory: []*podresourcesapi.ContainerMemory{},
124 dynamicResources: []*podresourcesapi.DynamicResource{},
125 expectedResponse: &podresourcesapi.ListPodResourcesResponse{
126 PodResources: []*podresourcesapi.PodResources{
127 {
128 Name: podName,
129 Namespace: podNamespace,
130 Containers: []*podresourcesapi.ContainerResources{
131 {
132 Name: containerName,
133 Devices: []*podresourcesapi.ContainerDevices{},
134 DynamicResources: []*podresourcesapi.DynamicResource{},
135 },
136 },
137 },
138 },
139 },
140 },
141 {
142 desc: "pod with devices",
143 pods: pods,
144 devices: devs,
145 cpus: cpus,
146 memory: memory,
147 dynamicResources: []*podresourcesapi.DynamicResource{},
148 expectedResponse: &podresourcesapi.ListPodResourcesResponse{
149 PodResources: []*podresourcesapi.PodResources{
150 {
151 Name: podName,
152 Namespace: podNamespace,
153 Containers: []*podresourcesapi.ContainerResources{
154 {
155 Name: containerName,
156 Devices: devs,
157 CpuIds: cpus,
158 Memory: memory,
159 DynamicResources: []*podresourcesapi.DynamicResource{},
160 },
161 },
162 },
163 },
164 },
165 },
166 {
167 desc: "pod with dynamic resources",
168 pods: pods,
169 devices: []*podresourcesapi.ContainerDevices{},
170 cpus: cpus,
171 memory: memory,
172 dynamicResources: draDevs,
173 expectedResponse: &podresourcesapi.ListPodResourcesResponse{
174 PodResources: []*podresourcesapi.PodResources{
175 {
176 Name: podName,
177 Namespace: podNamespace,
178 Containers: []*podresourcesapi.ContainerResources{
179 {
180 Name: containerName,
181 Devices: []*podresourcesapi.ContainerDevices{},
182 CpuIds: cpus,
183 Memory: memory,
184 DynamicResources: draDevs,
185 },
186 },
187 },
188 },
189 },
190 },
191 {
192 desc: "pod with dynamic resources and devices",
193 pods: pods,
194 devices: devs,
195 cpus: cpus,
196 memory: memory,
197 dynamicResources: draDevs,
198 expectedResponse: &podresourcesapi.ListPodResourcesResponse{
199 PodResources: []*podresourcesapi.PodResources{
200 {
201 Name: podName,
202 Namespace: podNamespace,
203 Containers: []*podresourcesapi.ContainerResources{
204 {
205 Name: containerName,
206 Devices: devs,
207 CpuIds: cpus,
208 Memory: memory,
209 DynamicResources: draDevs,
210 },
211 },
212 },
213 },
214 },
215 },
216 } {
217 t.Run(tc.desc, func(t *testing.T) {
218 mockDevicesProvider := podresourcetest.NewMockDevicesProvider(mockCtrl)
219 mockPodsProvider := podresourcetest.NewMockPodsProvider(mockCtrl)
220 mockCPUsProvider := podresourcetest.NewMockCPUsProvider(mockCtrl)
221 mockMemoryProvider := podresourcetest.NewMockMemoryProvider(mockCtrl)
222 mockDynamicResourcesProvider := podresourcetest.NewMockDynamicResourcesProvider(mockCtrl)
223
224 mockPodsProvider.EXPECT().GetPods().Return(tc.pods).AnyTimes()
225 mockDevicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(tc.devices).AnyTimes()
226 mockCPUsProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(tc.cpus).AnyTimes()
227 mockMemoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(tc.memory).AnyTimes()
228 mockDynamicResourcesProvider.EXPECT().GetDynamicResources(pods[0], &containers[0]).Return(tc.dynamicResources).AnyTimes()
229 mockDevicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
230 mockCPUsProvider.EXPECT().GetAllocatableCPUs().Return([]int64{}).AnyTimes()
231 mockDevicesProvider.EXPECT().GetAllocatableDevices().Return([]*podresourcesapi.ContainerDevices{}).AnyTimes()
232 mockMemoryProvider.EXPECT().GetAllocatableMemory().Return([]*podresourcesapi.ContainerMemory{}).AnyTimes()
233
234 providers := PodResourcesProviders{
235 Pods: mockPodsProvider,
236 Devices: mockDevicesProvider,
237 Cpus: mockCPUsProvider,
238 Memory: mockMemoryProvider,
239 DynamicResources: mockDynamicResourcesProvider,
240 }
241 server := NewV1PodResourcesServer(providers)
242 resp, err := server.List(context.TODO(), &podresourcesapi.ListPodResourcesRequest{})
243 if err != nil {
244 t.Errorf("want err = %v, got %q", nil, err)
245 }
246 if !equalListResponse(tc.expectedResponse, resp) {
247 t.Errorf("want resp = %s, got %s", tc.expectedResponse.String(), resp.String())
248 }
249 })
250 }
251 }
252
253 func TestListPodResourcesWithInitContainersV1(t *testing.T) {
254 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.KubeletPodResourcesDynamicResources, true)()
255
256 podName := "pod-name"
257 podNamespace := "pod-namespace"
258 podUID := types.UID("pod-uid")
259 initContainerName := "init-container-name"
260 containerName := "container-name"
261 numaID := int64(1)
262 containerRestartPolicyAlways := v1.ContainerRestartPolicyAlways
263
264 devs := []*podresourcesapi.ContainerDevices{
265 {
266 ResourceName: "resource",
267 DeviceIds: []string{"dev0", "dev1"},
268 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
269 },
270 }
271
272 cpus := []int64{12, 23, 30}
273
274 memory := []*podresourcesapi.ContainerMemory{
275 {
276 MemoryType: "memory",
277 Size_: 1073741824,
278 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
279 },
280 {
281 MemoryType: "hugepages-1Gi",
282 Size_: 1073741824,
283 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
284 },
285 }
286
287 containers := []v1.Container{
288 {
289 Name: containerName,
290 },
291 }
292
293 for _, tc := range []struct {
294 desc string
295 pods []*v1.Pod
296 mockFunc func(
297 []*v1.Pod,
298 *podresourcetest.MockDevicesProvider,
299 *podresourcetest.MockCPUsProvider,
300 *podresourcetest.MockMemoryProvider,
301 *podresourcetest.MockDynamicResourcesProvider)
302 sidecarContainersEnabled bool
303 expectedResponse *podresourcesapi.ListPodResourcesResponse
304 }{
305 {
306 desc: "pod having an init container",
307 pods: []*v1.Pod{
308 {
309 ObjectMeta: metav1.ObjectMeta{
310 Name: podName,
311 Namespace: podNamespace,
312 UID: podUID,
313 },
314 Spec: v1.PodSpec{
315 InitContainers: []v1.Container{
316 {
317 Name: initContainerName,
318 },
319 },
320 Containers: containers,
321 },
322 },
323 },
324 mockFunc: func(
325 pods []*v1.Pod,
326 devicesProvider *podresourcetest.MockDevicesProvider,
327 cpusProvider *podresourcetest.MockCPUsProvider,
328 memoryProvider *podresourcetest.MockMemoryProvider,
329 dynamicResourcesProvider *podresourcetest.MockDynamicResourcesProvider) {
330 devicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
331 devicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(devs).AnyTimes()
332 cpusProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(cpus).AnyTimes()
333 memoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(memory).AnyTimes()
334 dynamicResourcesProvider.EXPECT().GetDynamicResources(pods[0], &pods[0].Spec.Containers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
335
336 },
337 expectedResponse: &podresourcesapi.ListPodResourcesResponse{
338 PodResources: []*podresourcesapi.PodResources{
339 {
340 Name: podName,
341 Namespace: podNamespace,
342 Containers: []*podresourcesapi.ContainerResources{
343 {
344 Name: containerName,
345 Devices: devs,
346 CpuIds: cpus,
347 Memory: memory,
348 DynamicResources: []*podresourcesapi.DynamicResource{},
349 },
350 },
351 },
352 },
353 },
354 },
355 {
356 desc: "pod having an init container with SidecarContainers enabled",
357 pods: []*v1.Pod{
358 {
359 ObjectMeta: metav1.ObjectMeta{
360 Name: podName,
361 Namespace: podNamespace,
362 UID: podUID,
363 },
364 Spec: v1.PodSpec{
365 InitContainers: []v1.Container{
366 {
367 Name: initContainerName,
368 },
369 },
370 Containers: containers,
371 },
372 },
373 },
374 mockFunc: func(
375 pods []*v1.Pod,
376 devicesProvider *podresourcetest.MockDevicesProvider,
377 cpusProvider *podresourcetest.MockCPUsProvider,
378 memoryProvider *podresourcetest.MockMemoryProvider,
379 dynamicResourcesProvider *podresourcetest.MockDynamicResourcesProvider) {
380 devicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
381 devicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(devs).AnyTimes()
382 cpusProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(cpus).AnyTimes()
383 memoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(memory).AnyTimes()
384 dynamicResourcesProvider.EXPECT().GetDynamicResources(pods[0], &pods[0].Spec.Containers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
385
386 },
387 sidecarContainersEnabled: true,
388 expectedResponse: &podresourcesapi.ListPodResourcesResponse{
389 PodResources: []*podresourcesapi.PodResources{
390 {
391 Name: podName,
392 Namespace: podNamespace,
393 Containers: []*podresourcesapi.ContainerResources{
394 {
395 Name: containerName,
396 Devices: devs,
397 CpuIds: cpus,
398 Memory: memory,
399 DynamicResources: []*podresourcesapi.DynamicResource{},
400 },
401 },
402 },
403 },
404 },
405 },
406 {
407 desc: "pod having a restartable init container with SidecarContainers disabled",
408 pods: []*v1.Pod{
409 {
410 ObjectMeta: metav1.ObjectMeta{
411 Name: podName,
412 Namespace: podNamespace,
413 UID: podUID,
414 },
415 Spec: v1.PodSpec{
416 InitContainers: []v1.Container{
417 {
418 Name: initContainerName,
419 RestartPolicy: &containerRestartPolicyAlways,
420 },
421 },
422 Containers: containers,
423 },
424 },
425 },
426 mockFunc: func(
427 pods []*v1.Pod,
428 devicesProvider *podresourcetest.MockDevicesProvider,
429 cpusProvider *podresourcetest.MockCPUsProvider,
430 memoryProvider *podresourcetest.MockMemoryProvider,
431 dynamicResourcesProvider *podresourcetest.MockDynamicResourcesProvider) {
432 devicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
433
434 devicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(devs).AnyTimes()
435 cpusProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(cpus).AnyTimes()
436 memoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(memory).AnyTimes()
437 dynamicResourcesProvider.EXPECT().GetDynamicResources(pods[0], &pods[0].Spec.Containers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
438
439 },
440 expectedResponse: &podresourcesapi.ListPodResourcesResponse{
441 PodResources: []*podresourcesapi.PodResources{
442 {
443 Name: podName,
444 Namespace: podNamespace,
445 Containers: []*podresourcesapi.ContainerResources{
446 {
447 Name: containerName,
448 Devices: devs,
449 CpuIds: cpus,
450 Memory: memory,
451 DynamicResources: []*podresourcesapi.DynamicResource{},
452 },
453 },
454 },
455 },
456 },
457 },
458 {
459 desc: "pod having an init container with SidecarContainers enabled",
460 pods: []*v1.Pod{
461 {
462 ObjectMeta: metav1.ObjectMeta{
463 Name: podName,
464 Namespace: podNamespace,
465 UID: podUID,
466 },
467 Spec: v1.PodSpec{
468 InitContainers: []v1.Container{
469 {
470 Name: initContainerName,
471 RestartPolicy: &containerRestartPolicyAlways,
472 },
473 },
474 Containers: containers,
475 },
476 },
477 },
478 mockFunc: func(
479 pods []*v1.Pod,
480 devicesProvider *podresourcetest.MockDevicesProvider,
481 cpusProvider *podresourcetest.MockCPUsProvider,
482 memoryProvider *podresourcetest.MockMemoryProvider,
483 dynamicResourcesProvider *podresourcetest.MockDynamicResourcesProvider) {
484 devicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
485
486 devicesProvider.EXPECT().GetDevices(string(podUID), initContainerName).Return(devs).AnyTimes()
487 cpusProvider.EXPECT().GetCPUs(string(podUID), initContainerName).Return(cpus).AnyTimes()
488 memoryProvider.EXPECT().GetMemory(string(podUID), initContainerName).Return(memory).AnyTimes()
489 dynamicResourcesProvider.EXPECT().GetDynamicResources(pods[0], &pods[0].Spec.InitContainers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
490
491 devicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(devs).AnyTimes()
492 cpusProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(cpus).AnyTimes()
493 memoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(memory).AnyTimes()
494 dynamicResourcesProvider.EXPECT().GetDynamicResources(pods[0], &pods[0].Spec.Containers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
495
496 },
497 sidecarContainersEnabled: true,
498 expectedResponse: &podresourcesapi.ListPodResourcesResponse{
499 PodResources: []*podresourcesapi.PodResources{
500 {
501 Name: podName,
502 Namespace: podNamespace,
503 Containers: []*podresourcesapi.ContainerResources{
504 {
505 Name: initContainerName,
506 Devices: devs,
507 CpuIds: cpus,
508 Memory: memory,
509 DynamicResources: []*podresourcesapi.DynamicResource{},
510 },
511 {
512 Name: containerName,
513 Devices: devs,
514 CpuIds: cpus,
515 Memory: memory,
516 DynamicResources: []*podresourcesapi.DynamicResource{},
517 },
518 },
519 },
520 },
521 },
522 },
523 } {
524 t.Run(tc.desc, func(t *testing.T) {
525 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.SidecarContainers, tc.sidecarContainersEnabled)()
526
527 mockCtrl := gomock.NewController(t)
528 defer mockCtrl.Finish()
529
530 mockDevicesProvider := podresourcetest.NewMockDevicesProvider(mockCtrl)
531 mockPodsProvider := podresourcetest.NewMockPodsProvider(mockCtrl)
532 mockCPUsProvider := podresourcetest.NewMockCPUsProvider(mockCtrl)
533 mockMemoryProvider := podresourcetest.NewMockMemoryProvider(mockCtrl)
534 mockDynamicResourcesProvider := podresourcetest.NewMockDynamicResourcesProvider(mockCtrl)
535
536 mockPodsProvider.EXPECT().GetPods().Return(tc.pods).AnyTimes()
537 tc.mockFunc(tc.pods, mockDevicesProvider, mockCPUsProvider, mockMemoryProvider, mockDynamicResourcesProvider)
538
539 providers := PodResourcesProviders{
540 Pods: mockPodsProvider,
541 Devices: mockDevicesProvider,
542 Cpus: mockCPUsProvider,
543 Memory: mockMemoryProvider,
544 DynamicResources: mockDynamicResourcesProvider,
545 }
546 server := NewV1PodResourcesServer(providers)
547 resp, err := server.List(context.TODO(), &podresourcesapi.ListPodResourcesRequest{})
548 if err != nil {
549 t.Errorf("want err = %v, got %q", nil, err)
550 }
551 if !equalListResponse(tc.expectedResponse, resp) {
552 t.Errorf("want resp = %s, got %s", tc.expectedResponse.String(), resp.String())
553 }
554 })
555 }
556 }
557
558 func TestAllocatableResources(t *testing.T) {
559 mockCtrl := gomock.NewController(t)
560 defer mockCtrl.Finish()
561
562 allDevs := []*podresourcesapi.ContainerDevices{
563 {
564 ResourceName: "resource",
565 DeviceIds: []string{"dev0"},
566 Topology: &podresourcesapi.TopologyInfo{
567 Nodes: []*podresourcesapi.NUMANode{
568 {
569 ID: 0,
570 },
571 },
572 },
573 },
574 {
575 ResourceName: "resource",
576 DeviceIds: []string{"dev1"},
577 Topology: &podresourcesapi.TopologyInfo{
578 Nodes: []*podresourcesapi.NUMANode{
579 {
580 ID: 1,
581 },
582 },
583 },
584 },
585 {
586 ResourceName: "resource-nt",
587 DeviceIds: []string{"devA"},
588 },
589 {
590 ResourceName: "resource-mm",
591 DeviceIds: []string{"devM0"},
592 Topology: &podresourcesapi.TopologyInfo{
593 Nodes: []*podresourcesapi.NUMANode{
594 {
595 ID: 0,
596 },
597 },
598 },
599 },
600 {
601 ResourceName: "resource-mm",
602 DeviceIds: []string{"devMM"},
603 Topology: &podresourcesapi.TopologyInfo{
604 Nodes: []*podresourcesapi.NUMANode{
605 {
606 ID: 0,
607 },
608 {
609 ID: 1,
610 },
611 },
612 },
613 },
614 }
615
616 allCPUs := []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
617
618 allMemory := []*podresourcesapi.ContainerMemory{
619 {
620 MemoryType: "memory",
621 Size_: 5368709120,
622 Topology: &podresourcesapi.TopologyInfo{
623 Nodes: []*podresourcesapi.NUMANode{
624 {
625 ID: 0,
626 },
627 },
628 },
629 },
630 {
631 MemoryType: "hugepages-2Mi",
632 Size_: 1073741824,
633 Topology: &podresourcesapi.TopologyInfo{
634 Nodes: []*podresourcesapi.NUMANode{
635 {
636 ID: 0,
637 },
638 },
639 },
640 },
641 {
642 MemoryType: "memory",
643 Size_: 5368709120,
644 Topology: &podresourcesapi.TopologyInfo{
645 Nodes: []*podresourcesapi.NUMANode{
646 {
647 ID: 1,
648 },
649 },
650 },
651 },
652 {
653 MemoryType: "hugepages-2Mi",
654 Size_: 1073741824,
655 Topology: &podresourcesapi.TopologyInfo{
656 Nodes: []*podresourcesapi.NUMANode{
657 {
658 ID: 1,
659 },
660 },
661 },
662 },
663 }
664
665 for _, tc := range []struct {
666 desc string
667 allCPUs []int64
668 allDevices []*podresourcesapi.ContainerDevices
669 allMemory []*podresourcesapi.ContainerMemory
670 expectedAllocatableResourcesResponse *podresourcesapi.AllocatableResourcesResponse
671 }{
672 {
673 desc: "no devices, no CPUs",
674 allCPUs: []int64{},
675 allDevices: []*podresourcesapi.ContainerDevices{},
676 allMemory: []*podresourcesapi.ContainerMemory{},
677 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{},
678 },
679 {
680 desc: "no devices, all CPUs",
681 allCPUs: allCPUs,
682 allDevices: []*podresourcesapi.ContainerDevices{},
683 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{
684 CpuIds: allCPUs,
685 },
686 },
687 {
688 desc: "no devices, no CPUs, all memory",
689 allCPUs: []int64{},
690 allDevices: []*podresourcesapi.ContainerDevices{},
691 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{
692 Memory: allMemory,
693 },
694 },
695 {
696 desc: "with devices, all CPUs",
697 allCPUs: allCPUs,
698 allDevices: allDevs,
699 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{
700 CpuIds: allCPUs,
701 Devices: []*podresourcesapi.ContainerDevices{
702 {
703 ResourceName: "resource",
704 DeviceIds: []string{"dev0"},
705 Topology: &podresourcesapi.TopologyInfo{
706 Nodes: []*podresourcesapi.NUMANode{
707 {
708 ID: 0,
709 },
710 },
711 },
712 },
713 {
714 ResourceName: "resource",
715 DeviceIds: []string{"dev1"},
716 Topology: &podresourcesapi.TopologyInfo{
717 Nodes: []*podresourcesapi.NUMANode{
718 {
719 ID: 1,
720 },
721 },
722 },
723 },
724 {
725 ResourceName: "resource-nt",
726 DeviceIds: []string{"devA"},
727 },
728 {
729 ResourceName: "resource-mm",
730 DeviceIds: []string{"devM0"},
731 Topology: &podresourcesapi.TopologyInfo{
732 Nodes: []*podresourcesapi.NUMANode{
733 {
734 ID: 0,
735 },
736 },
737 },
738 },
739 {
740 ResourceName: "resource-mm",
741 DeviceIds: []string{"devMM"},
742 Topology: &podresourcesapi.TopologyInfo{
743 Nodes: []*podresourcesapi.NUMANode{
744 {
745 ID: 0,
746 },
747 {
748 ID: 1,
749 },
750 },
751 },
752 },
753 },
754 },
755 },
756 {
757 desc: "with devices, no CPUs",
758 allCPUs: []int64{},
759 allDevices: allDevs,
760 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{
761 Devices: []*podresourcesapi.ContainerDevices{
762 {
763 ResourceName: "resource",
764 DeviceIds: []string{"dev0"},
765 Topology: &podresourcesapi.TopologyInfo{
766 Nodes: []*podresourcesapi.NUMANode{
767 {
768 ID: 0,
769 },
770 },
771 },
772 },
773 {
774 ResourceName: "resource",
775 DeviceIds: []string{"dev1"},
776 Topology: &podresourcesapi.TopologyInfo{
777 Nodes: []*podresourcesapi.NUMANode{
778 {
779 ID: 1,
780 },
781 },
782 },
783 },
784 {
785 ResourceName: "resource-nt",
786 DeviceIds: []string{"devA"},
787 },
788 {
789 ResourceName: "resource-mm",
790 DeviceIds: []string{"devM0"},
791 Topology: &podresourcesapi.TopologyInfo{
792 Nodes: []*podresourcesapi.NUMANode{
793 {
794 ID: 0,
795 },
796 },
797 },
798 },
799 {
800 ResourceName: "resource-mm",
801 DeviceIds: []string{"devMM"},
802 Topology: &podresourcesapi.TopologyInfo{
803 Nodes: []*podresourcesapi.NUMANode{
804 {
805 ID: 0,
806 },
807 {
808 ID: 1,
809 },
810 },
811 },
812 },
813 },
814 },
815 },
816 } {
817 t.Run(tc.desc, func(t *testing.T) {
818 mockDevicesProvider := podresourcetest.NewMockDevicesProvider(mockCtrl)
819 mockPodsProvider := podresourcetest.NewMockPodsProvider(mockCtrl)
820 mockCPUsProvider := podresourcetest.NewMockCPUsProvider(mockCtrl)
821 mockMemoryProvider := podresourcetest.NewMockMemoryProvider(mockCtrl)
822
823 mockDevicesProvider.EXPECT().GetDevices("", "").Return([]*podresourcesapi.ContainerDevices{}).AnyTimes()
824 mockCPUsProvider.EXPECT().GetCPUs("", "").Return([]int64{}).AnyTimes()
825 mockMemoryProvider.EXPECT().GetMemory("", "").Return([]*podresourcesapi.ContainerMemory{}).AnyTimes()
826 mockDevicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
827 mockDevicesProvider.EXPECT().GetAllocatableDevices().Return(tc.allDevices).AnyTimes()
828 mockCPUsProvider.EXPECT().GetAllocatableCPUs().Return(tc.allCPUs).AnyTimes()
829 mockMemoryProvider.EXPECT().GetAllocatableMemory().Return(tc.allMemory).AnyTimes()
830
831 providers := PodResourcesProviders{
832 Pods: mockPodsProvider,
833 Devices: mockDevicesProvider,
834 Cpus: mockCPUsProvider,
835 Memory: mockMemoryProvider,
836 }
837 server := NewV1PodResourcesServer(providers)
838
839 resp, err := server.GetAllocatableResources(context.TODO(), &podresourcesapi.AllocatableResourcesRequest{})
840 if err != nil {
841 t.Errorf("want err = %v, got %q", nil, err)
842 }
843
844 if !equalAllocatableResourcesResponse(tc.expectedAllocatableResourcesResponse, resp) {
845 t.Errorf("want resp = %s, got %s", tc.expectedAllocatableResourcesResponse.String(), resp.String())
846 }
847 })
848 }
849 }
850
851 func TestGetPodResourcesV1(t *testing.T) {
852 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.KubeletPodResourcesGet, true)()
853 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.KubeletPodResourcesDynamicResources, true)()
854
855 podName := "pod-name"
856 podNamespace := "pod-namespace"
857 podUID := types.UID("pod-uid")
858 containerName := "container-name"
859 numaID := int64(1)
860
861 mockCtrl := gomock.NewController(t)
862 defer mockCtrl.Finish()
863
864 devs := []*podresourcesapi.ContainerDevices{
865 {
866 ResourceName: "resource",
867 DeviceIds: []string{"dev0", "dev1"},
868 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
869 },
870 }
871
872 cpus := []int64{12, 23, 30}
873
874 memory := []*podresourcesapi.ContainerMemory{
875 {
876 MemoryType: "memory",
877 Size_: 1073741824,
878 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
879 },
880 {
881 MemoryType: "hugepages-1Gi",
882 Size_: 1073741824,
883 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
884 },
885 }
886
887 containers := []v1.Container{
888 {
889 Name: containerName,
890 },
891 }
892
893 pod := &v1.Pod{
894 ObjectMeta: metav1.ObjectMeta{
895 Name: podName,
896 Namespace: podNamespace,
897 UID: podUID,
898 },
899 Spec: v1.PodSpec{
900 Containers: containers,
901 },
902 }
903
904 pluginCDIDevices := []*podresourcesapi.CDIDevice{{Name: "dra-dev0"}, {Name: "dra-dev1"}}
905 draDevs := []*podresourcesapi.DynamicResource{
906 {
907 ClassName: "resource-class",
908 ClaimName: "claim-name",
909 ClaimNamespace: "default",
910 ClaimResources: []*podresourcesapi.ClaimResource{{CDIDevices: pluginCDIDevices}},
911 },
912 }
913
914 for _, tc := range []struct {
915 desc string
916 err error
917 exist bool
918 pod *v1.Pod
919 devices []*podresourcesapi.ContainerDevices
920 cpus []int64
921 memory []*podresourcesapi.ContainerMemory
922 dynamicResources []*podresourcesapi.DynamicResource
923 expectedResponse *podresourcesapi.GetPodResourcesResponse
924 }{
925 {
926 desc: "pod not exist",
927 err: fmt.Errorf("pod %s in namespace %s not found", podName, podNamespace),
928 exist: false,
929 pod: nil,
930 devices: []*podresourcesapi.ContainerDevices{},
931 cpus: []int64{},
932 memory: []*podresourcesapi.ContainerMemory{},
933 dynamicResources: []*podresourcesapi.DynamicResource{},
934
935 expectedResponse: &podresourcesapi.GetPodResourcesResponse{},
936 },
937 {
938 desc: "pod without devices",
939 err: nil,
940 exist: true,
941 pod: pod,
942 devices: []*podresourcesapi.ContainerDevices{},
943 cpus: []int64{},
944 memory: []*podresourcesapi.ContainerMemory{},
945 dynamicResources: []*podresourcesapi.DynamicResource{},
946 expectedResponse: &podresourcesapi.GetPodResourcesResponse{
947 PodResources: &podresourcesapi.PodResources{
948 Name: podName,
949 Namespace: podNamespace,
950 Containers: []*podresourcesapi.ContainerResources{
951 {
952 Name: containerName,
953 Devices: []*podresourcesapi.ContainerDevices{},
954 DynamicResources: []*podresourcesapi.DynamicResource{},
955 },
956 },
957 },
958 },
959 },
960 {
961 desc: "pod with devices",
962 err: nil,
963 exist: true,
964 pod: pod,
965 devices: devs,
966 cpus: cpus,
967 memory: memory,
968 dynamicResources: draDevs,
969 expectedResponse: &podresourcesapi.GetPodResourcesResponse{
970 PodResources: &podresourcesapi.PodResources{
971 Name: podName,
972 Namespace: podNamespace,
973 Containers: []*podresourcesapi.ContainerResources{
974 {
975 Name: containerName,
976 Devices: devs,
977 CpuIds: cpus,
978 Memory: memory,
979 DynamicResources: draDevs,
980 },
981 },
982 },
983 },
984 },
985 } {
986 t.Run(tc.desc, func(t *testing.T) {
987 mockDevicesProvider := podresourcetest.NewMockDevicesProvider(mockCtrl)
988 mockPodsProvider := podresourcetest.NewMockPodsProvider(mockCtrl)
989 mockCPUsProvider := podresourcetest.NewMockCPUsProvider(mockCtrl)
990 mockMemoryProvider := podresourcetest.NewMockMemoryProvider(mockCtrl)
991 mockDynamicResourcesProvider := podresourcetest.NewMockDynamicResourcesProvider(mockCtrl)
992
993 mockPodsProvider.EXPECT().GetPodByName(podNamespace, podName).Return(tc.pod, tc.exist).AnyTimes()
994 mockDevicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(tc.devices).AnyTimes()
995 mockCPUsProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(tc.cpus).AnyTimes()
996 mockMemoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(tc.memory).AnyTimes()
997 mockDynamicResourcesProvider.EXPECT().GetDynamicResources(pod, &containers[0]).Return(tc.dynamicResources).AnyTimes()
998 mockDevicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
999 mockCPUsProvider.EXPECT().GetAllocatableCPUs().Return([]int64{}).AnyTimes()
1000 mockDevicesProvider.EXPECT().GetAllocatableDevices().Return([]*podresourcesapi.ContainerDevices{}).AnyTimes()
1001 mockMemoryProvider.EXPECT().GetAllocatableMemory().Return([]*podresourcesapi.ContainerMemory{}).AnyTimes()
1002
1003 providers := PodResourcesProviders{
1004 Pods: mockPodsProvider,
1005 Devices: mockDevicesProvider,
1006 Cpus: mockCPUsProvider,
1007 Memory: mockMemoryProvider,
1008 DynamicResources: mockDynamicResourcesProvider,
1009 }
1010 server := NewV1PodResourcesServer(providers)
1011 podReq := &podresourcesapi.GetPodResourcesRequest{PodName: podName, PodNamespace: podNamespace}
1012 resp, err := server.Get(context.TODO(), podReq)
1013
1014 if err != nil {
1015 if err.Error() != tc.err.Error() {
1016 t.Errorf("want exit = %v, got %v", tc.err, err)
1017 }
1018 } else {
1019 if err != tc.err {
1020 t.Errorf("want exit = %v, got %v", tc.err, err)
1021 } else {
1022 if !equalGetResponse(tc.expectedResponse, resp) {
1023 t.Errorf("want resp = %s, got %s", tc.expectedResponse.String(), resp.String())
1024 }
1025 }
1026 }
1027 })
1028 }
1029
1030 }
1031
1032 func TestGetPodResourcesWithInitContainersV1(t *testing.T) {
1033 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.KubeletPodResourcesGet, true)()
1034 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.KubeletPodResourcesDynamicResources, true)()
1035
1036 podName := "pod-name"
1037 podNamespace := "pod-namespace"
1038 podUID := types.UID("pod-uid")
1039 initContainerName := "init-container-name"
1040 containerName := "container-name"
1041 numaID := int64(1)
1042 containerRestartPolicyAlways := v1.ContainerRestartPolicyAlways
1043
1044 devs := []*podresourcesapi.ContainerDevices{
1045 {
1046 ResourceName: "resource",
1047 DeviceIds: []string{"dev0", "dev1"},
1048 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
1049 },
1050 }
1051
1052 cpus := []int64{12, 23, 30}
1053
1054 memory := []*podresourcesapi.ContainerMemory{
1055 {
1056 MemoryType: "memory",
1057 Size_: 1073741824,
1058 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
1059 },
1060 {
1061 MemoryType: "hugepages-1Gi",
1062 Size_: 1073741824,
1063 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}},
1064 },
1065 }
1066
1067 containers := []v1.Container{
1068 {
1069 Name: containerName,
1070 },
1071 }
1072
1073 for _, tc := range []struct {
1074 desc string
1075 pod *v1.Pod
1076 mockFunc func(
1077 *v1.Pod,
1078 *podresourcetest.MockDevicesProvider,
1079 *podresourcetest.MockCPUsProvider,
1080 *podresourcetest.MockMemoryProvider,
1081 *podresourcetest.MockDynamicResourcesProvider)
1082 sidecarContainersEnabled bool
1083 expectedResponse *podresourcesapi.GetPodResourcesResponse
1084 }{
1085 {
1086 desc: "pod having an init container",
1087 pod: &v1.Pod{
1088 ObjectMeta: metav1.ObjectMeta{
1089 Name: podName,
1090 Namespace: podNamespace,
1091 UID: podUID,
1092 },
1093 Spec: v1.PodSpec{
1094 InitContainers: []v1.Container{
1095 {
1096 Name: initContainerName,
1097 },
1098 },
1099 Containers: containers,
1100 },
1101 },
1102 mockFunc: func(
1103 pod *v1.Pod,
1104 devicesProvider *podresourcetest.MockDevicesProvider,
1105 cpusProvider *podresourcetest.MockCPUsProvider,
1106 memoryProvider *podresourcetest.MockMemoryProvider,
1107 dynamicResourcesProvider *podresourcetest.MockDynamicResourcesProvider) {
1108 devicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
1109 devicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(devs).AnyTimes()
1110 cpusProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(cpus).AnyTimes()
1111 memoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(memory).AnyTimes()
1112 dynamicResourcesProvider.EXPECT().GetDynamicResources(pod, &pod.Spec.Containers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
1113
1114 },
1115 expectedResponse: &podresourcesapi.GetPodResourcesResponse{
1116 PodResources: &podresourcesapi.PodResources{
1117 Name: podName,
1118 Namespace: podNamespace,
1119 Containers: []*podresourcesapi.ContainerResources{
1120 {
1121 Name: containerName,
1122 Devices: devs,
1123 CpuIds: cpus,
1124 Memory: memory,
1125 DynamicResources: []*podresourcesapi.DynamicResource{},
1126 },
1127 },
1128 },
1129 },
1130 },
1131 {
1132 desc: "pod having an init container with SidecarContainers enabled",
1133 pod: &v1.Pod{
1134 ObjectMeta: metav1.ObjectMeta{
1135 Name: podName,
1136 Namespace: podNamespace,
1137 UID: podUID,
1138 },
1139 Spec: v1.PodSpec{
1140 InitContainers: []v1.Container{
1141 {
1142 Name: initContainerName,
1143 },
1144 },
1145 Containers: containers,
1146 },
1147 },
1148 mockFunc: func(
1149 pod *v1.Pod,
1150 devicesProvider *podresourcetest.MockDevicesProvider,
1151 cpusProvider *podresourcetest.MockCPUsProvider,
1152 memoryProvider *podresourcetest.MockMemoryProvider,
1153 dynamicResourcesProvider *podresourcetest.MockDynamicResourcesProvider) {
1154 devicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
1155 devicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(devs).AnyTimes()
1156 cpusProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(cpus).AnyTimes()
1157 memoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(memory).AnyTimes()
1158 dynamicResourcesProvider.EXPECT().GetDynamicResources(pod, &pod.Spec.Containers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
1159
1160 },
1161 sidecarContainersEnabled: true,
1162 expectedResponse: &podresourcesapi.GetPodResourcesResponse{
1163 PodResources: &podresourcesapi.PodResources{
1164 Name: podName,
1165 Namespace: podNamespace,
1166 Containers: []*podresourcesapi.ContainerResources{
1167 {
1168 Name: containerName,
1169 Devices: devs,
1170 CpuIds: cpus,
1171 Memory: memory,
1172 DynamicResources: []*podresourcesapi.DynamicResource{},
1173 },
1174 },
1175 },
1176 },
1177 },
1178 {
1179 desc: "pod having a restartable init container with SidecarContainers disabled",
1180 pod: &v1.Pod{
1181 ObjectMeta: metav1.ObjectMeta{
1182 Name: podName,
1183 Namespace: podNamespace,
1184 UID: podUID,
1185 },
1186 Spec: v1.PodSpec{
1187 InitContainers: []v1.Container{
1188 {
1189 Name: initContainerName,
1190 RestartPolicy: &containerRestartPolicyAlways,
1191 },
1192 },
1193 Containers: containers,
1194 },
1195 },
1196 mockFunc: func(
1197 pod *v1.Pod,
1198 devicesProvider *podresourcetest.MockDevicesProvider,
1199 cpusProvider *podresourcetest.MockCPUsProvider,
1200 memoryProvider *podresourcetest.MockMemoryProvider,
1201 dynamicResourcesProvider *podresourcetest.MockDynamicResourcesProvider) {
1202 devicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
1203
1204 devicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(devs).AnyTimes()
1205 cpusProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(cpus).AnyTimes()
1206 memoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(memory).AnyTimes()
1207 dynamicResourcesProvider.EXPECT().GetDynamicResources(pod, &pod.Spec.Containers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
1208
1209 },
1210 expectedResponse: &podresourcesapi.GetPodResourcesResponse{
1211 PodResources: &podresourcesapi.PodResources{
1212 Name: podName,
1213 Namespace: podNamespace,
1214 Containers: []*podresourcesapi.ContainerResources{
1215 {
1216 Name: containerName,
1217 Devices: devs,
1218 CpuIds: cpus,
1219 Memory: memory,
1220 DynamicResources: []*podresourcesapi.DynamicResource{},
1221 },
1222 },
1223 },
1224 },
1225 },
1226 {
1227 desc: "pod having an init container with SidecarContainers enabled",
1228 pod: &v1.Pod{
1229 ObjectMeta: metav1.ObjectMeta{
1230 Name: podName,
1231 Namespace: podNamespace,
1232 UID: podUID,
1233 },
1234 Spec: v1.PodSpec{
1235 InitContainers: []v1.Container{
1236 {
1237 Name: initContainerName,
1238 RestartPolicy: &containerRestartPolicyAlways,
1239 },
1240 },
1241 Containers: containers,
1242 },
1243 },
1244 mockFunc: func(
1245 pod *v1.Pod,
1246 devicesProvider *podresourcetest.MockDevicesProvider,
1247 cpusProvider *podresourcetest.MockCPUsProvider,
1248 memoryProvider *podresourcetest.MockMemoryProvider,
1249 dynamicResourcesProvider *podresourcetest.MockDynamicResourcesProvider) {
1250 devicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes()
1251
1252 devicesProvider.EXPECT().GetDevices(string(podUID), initContainerName).Return(devs).AnyTimes()
1253 cpusProvider.EXPECT().GetCPUs(string(podUID), initContainerName).Return(cpus).AnyTimes()
1254 memoryProvider.EXPECT().GetMemory(string(podUID), initContainerName).Return(memory).AnyTimes()
1255 dynamicResourcesProvider.EXPECT().GetDynamicResources(pod, &pod.Spec.InitContainers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
1256
1257 devicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(devs).AnyTimes()
1258 cpusProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(cpus).AnyTimes()
1259 memoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(memory).AnyTimes()
1260 dynamicResourcesProvider.EXPECT().GetDynamicResources(pod, &pod.Spec.Containers[0]).Return([]*podresourcesapi.DynamicResource{}).AnyTimes()
1261
1262 },
1263 sidecarContainersEnabled: true,
1264 expectedResponse: &podresourcesapi.GetPodResourcesResponse{
1265 PodResources: &podresourcesapi.PodResources{
1266 Name: podName,
1267 Namespace: podNamespace,
1268 Containers: []*podresourcesapi.ContainerResources{
1269 {
1270 Name: initContainerName,
1271 Devices: devs,
1272 CpuIds: cpus,
1273 Memory: memory,
1274 DynamicResources: []*podresourcesapi.DynamicResource{},
1275 },
1276 {
1277 Name: containerName,
1278 Devices: devs,
1279 CpuIds: cpus,
1280 Memory: memory,
1281 DynamicResources: []*podresourcesapi.DynamicResource{},
1282 },
1283 },
1284 },
1285 },
1286 },
1287 } {
1288 t.Run(tc.desc, func(t *testing.T) {
1289 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.SidecarContainers, tc.sidecarContainersEnabled)()
1290
1291 mockCtrl := gomock.NewController(t)
1292 defer mockCtrl.Finish()
1293
1294 mockDevicesProvider := podresourcetest.NewMockDevicesProvider(mockCtrl)
1295 mockPodsProvider := podresourcetest.NewMockPodsProvider(mockCtrl)
1296 mockCPUsProvider := podresourcetest.NewMockCPUsProvider(mockCtrl)
1297 mockMemoryProvider := podresourcetest.NewMockMemoryProvider(mockCtrl)
1298 mockDynamicResourcesProvider := podresourcetest.NewMockDynamicResourcesProvider(mockCtrl)
1299
1300 mockPodsProvider.EXPECT().GetPodByName(podNamespace, podName).Return(tc.pod, true).AnyTimes()
1301 tc.mockFunc(tc.pod, mockDevicesProvider, mockCPUsProvider, mockMemoryProvider, mockDynamicResourcesProvider)
1302
1303 providers := PodResourcesProviders{
1304 Pods: mockPodsProvider,
1305 Devices: mockDevicesProvider,
1306 Cpus: mockCPUsProvider,
1307 Memory: mockMemoryProvider,
1308 DynamicResources: mockDynamicResourcesProvider,
1309 }
1310 server := NewV1PodResourcesServer(providers)
1311 podReq := &podresourcesapi.GetPodResourcesRequest{PodName: podName, PodNamespace: podNamespace}
1312 resp, err := server.Get(context.TODO(), podReq)
1313 if err != nil {
1314 t.Errorf("want err = %v, got %q", nil, err)
1315 }
1316 if !equalGetResponse(tc.expectedResponse, resp) {
1317 t.Errorf("want resp = %s, got %s", tc.expectedResponse.String(), resp.String())
1318 }
1319 })
1320 }
1321 }
1322
1323 func equalListResponse(respA, respB *podresourcesapi.ListPodResourcesResponse) bool {
1324 if len(respA.PodResources) != len(respB.PodResources) {
1325 return false
1326 }
1327 for idx := 0; idx < len(respA.PodResources); idx++ {
1328 podResA := respA.PodResources[idx]
1329 podResB := respB.PodResources[idx]
1330 if podResA.Name != podResB.Name {
1331 return false
1332 }
1333 if podResA.Namespace != podResB.Namespace {
1334 return false
1335 }
1336 if len(podResA.Containers) != len(podResB.Containers) {
1337 return false
1338 }
1339 for jdx := 0; jdx < len(podResA.Containers); jdx++ {
1340 cntA := podResA.Containers[jdx]
1341 cntB := podResB.Containers[jdx]
1342
1343 if cntA.Name != cntB.Name {
1344 return false
1345 }
1346 if !equalInt64s(cntA.CpuIds, cntB.CpuIds) {
1347 return false
1348 }
1349
1350 if !equalContainerDevices(cntA.Devices, cntB.Devices) {
1351 return false
1352 }
1353
1354 if !equalDynamicResources(cntA.DynamicResources, cntB.DynamicResources) {
1355 return false
1356 }
1357 }
1358 }
1359 return true
1360 }
1361
1362 func equalDynamicResources(draResA, draResB []*podresourcesapi.DynamicResource) bool {
1363 if len(draResA) != len(draResB) {
1364 return false
1365 }
1366
1367 for idx := 0; idx < len(draResA); idx++ {
1368 cntDraResA := draResA[idx]
1369 cntDraResB := draResB[idx]
1370
1371 if cntDraResA.ClassName != cntDraResB.ClassName {
1372 return false
1373 }
1374 if cntDraResA.ClaimName != cntDraResB.ClaimName {
1375 return false
1376 }
1377 if cntDraResA.ClaimNamespace != cntDraResB.ClaimNamespace {
1378 return false
1379 }
1380 if len(cntDraResA.ClaimResources) != len(cntDraResB.ClaimResources) {
1381 return false
1382 }
1383 for i := 0; i < len(cntDraResA.ClaimResources); i++ {
1384 claimResA := cntDraResA.ClaimResources[i]
1385 claimResB := cntDraResB.ClaimResources[i]
1386 if len(claimResA.CDIDevices) != len(claimResB.CDIDevices) {
1387 return false
1388 }
1389 for y := 0; y < len(claimResA.CDIDevices); y++ {
1390 cdiDeviceA := claimResA.CDIDevices[y]
1391 cdiDeviceB := claimResB.CDIDevices[y]
1392 if cdiDeviceA.Name != cdiDeviceB.Name {
1393 return false
1394 }
1395 }
1396 }
1397 }
1398
1399 return true
1400 }
1401
1402 func equalContainerDevices(devA, devB []*podresourcesapi.ContainerDevices) bool {
1403 if len(devA) != len(devB) {
1404 return false
1405 }
1406
1407 for idx := 0; idx < len(devA); idx++ {
1408 cntDevA := devA[idx]
1409 cntDevB := devB[idx]
1410
1411 if cntDevA.ResourceName != cntDevB.ResourceName {
1412 return false
1413 }
1414 if !equalTopology(cntDevA.Topology, cntDevB.Topology) {
1415 return false
1416 }
1417 if !equalStrings(cntDevA.DeviceIds, cntDevB.DeviceIds) {
1418 return false
1419 }
1420 }
1421
1422 return true
1423 }
1424
1425 func equalInt64s(a, b []int64) bool {
1426 if len(a) != len(b) {
1427 return false
1428 }
1429 aCopy := append([]int64{}, a...)
1430 sort.Slice(aCopy, func(i, j int) bool { return aCopy[i] < aCopy[j] })
1431 bCopy := append([]int64{}, b...)
1432 sort.Slice(bCopy, func(i, j int) bool { return bCopy[i] < bCopy[j] })
1433 return reflect.DeepEqual(aCopy, bCopy)
1434 }
1435
1436 func equalStrings(a, b []string) bool {
1437 if len(a) != len(b) {
1438 return false
1439 }
1440 aCopy := append([]string{}, a...)
1441 sort.Strings(aCopy)
1442 bCopy := append([]string{}, b...)
1443 sort.Strings(bCopy)
1444 return reflect.DeepEqual(aCopy, bCopy)
1445 }
1446
1447 func equalTopology(a, b *podresourcesapi.TopologyInfo) bool {
1448 if a == nil && b != nil {
1449 return false
1450 }
1451 if a != nil && b == nil {
1452 return false
1453 }
1454 return reflect.DeepEqual(a, b)
1455 }
1456
1457 func equalAllocatableResourcesResponse(respA, respB *podresourcesapi.AllocatableResourcesResponse) bool {
1458 if !equalInt64s(respA.CpuIds, respB.CpuIds) {
1459 return false
1460 }
1461 return equalContainerDevices(respA.Devices, respB.Devices)
1462 }
1463
1464 func equalGetResponse(ResA, ResB *podresourcesapi.GetPodResourcesResponse) bool {
1465 podResA := ResA.PodResources
1466 podResB := ResB.PodResources
1467 if podResA.Name != podResB.Name {
1468 return false
1469 }
1470 if podResA.Namespace != podResB.Namespace {
1471 return false
1472 }
1473 if len(podResA.Containers) != len(podResB.Containers) {
1474 return false
1475 }
1476 for jdx := 0; jdx < len(podResA.Containers); jdx++ {
1477 cntA := podResA.Containers[jdx]
1478 cntB := podResB.Containers[jdx]
1479
1480 if cntA.Name != cntB.Name {
1481 return false
1482 }
1483 if !equalInt64s(cntA.CpuIds, cntB.CpuIds) {
1484 return false
1485 }
1486
1487 if !equalContainerDevices(cntA.Devices, cntB.Devices) {
1488 return false
1489 }
1490
1491 if !equalDynamicResources(cntA.DynamicResources, cntB.DynamicResources) {
1492 return false
1493 }
1494
1495 }
1496 return true
1497 }
1498
View as plain text