...

Source file src/k8s.io/kubernetes/pkg/kubelet/apis/podresources/server_v1_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/apis/podresources

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    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