k8s.io/kubernetes@v1.29.3/pkg/kubelet/stats/cri_stats_provider_test.go (about) 1 /* 2 Copyright 2017 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 stats 18 19 import ( 20 "context" 21 "math/rand" 22 "os" 23 "path/filepath" 24 "runtime" 25 "strings" 26 "testing" 27 "time" 28 29 gomock "github.com/golang/mock/gomock" 30 cadvisorfs "github.com/google/cadvisor/fs" 31 cadvisorapiv2 "github.com/google/cadvisor/info/v2" 32 "github.com/stretchr/testify/assert" 33 "k8s.io/apimachinery/pkg/api/resource" 34 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 35 "k8s.io/apimachinery/pkg/types" 36 "k8s.io/apimachinery/pkg/util/uuid" 37 runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1" 38 critest "k8s.io/cri-api/pkg/apis/testing" 39 statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" 40 cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing" 41 "k8s.io/kubernetes/pkg/kubelet/cm" 42 kubecontainertest "k8s.io/kubernetes/pkg/kubelet/container/testing" 43 "k8s.io/kubernetes/pkg/kubelet/kuberuntime" 44 "k8s.io/kubernetes/pkg/kubelet/leaky" 45 kubepodtest "k8s.io/kubernetes/pkg/kubelet/pod/testing" 46 serverstats "k8s.io/kubernetes/pkg/kubelet/server/stats" 47 "k8s.io/kubernetes/pkg/volume" 48 ) 49 50 const ( 51 offsetInodeUsage = iota 52 offsetUsage 53 ) 54 55 const ( 56 // This offset offsetCRI is to distinguish it from Cadvisor stats 57 offsetCRI = 1000 58 ) 59 60 const ( 61 seedRoot = 0 62 seedKubelet = 200 63 seedMisc = 300 64 seedSandbox0 = 1000 65 seedContainer0 = 2000 66 seedSandbox1 = 3000 67 seedContainer1 = 4000 68 seedContainer2 = 5000 69 seedSandbox2 = 6000 70 seedContainer3 = 7000 71 seedSandbox3 = 8000 72 ) 73 74 const ( 75 pName0 = "pod0" 76 pName1 = "pod1" 77 pName2 = "pod2" 78 ) 79 80 const ( 81 cName0 = "container0-name" 82 cName1 = "container1-name" 83 cName2 = "container2-name" 84 cName3 = "container3-name" 85 cName5 = "container5-name" 86 cName6 = "container6-name" 87 cName7 = "container7-name" 88 cName8 = "container8-name" 89 cName9 = "container9-name" 90 ) 91 92 func TestCRIListPodStats(t *testing.T) { 93 ctx := context.Background() 94 var ( 95 imageFsMountpoint = "/test/mount/point" 96 unknownMountpoint = "/unknown/mount/point" 97 imageFsInfo = getTestFsInfo(2000) 98 rootFsInfo = getTestFsInfo(1000) 99 100 sandbox0 = makeFakePodSandbox("sandbox0-name", "sandbox0-uid", "sandbox0-ns", false) 101 sandbox0Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox0.PodSandboxStatus.Metadata.Uid)) 102 container0 = makeFakeContainer(sandbox0, cName0, 0, false) 103 containerStats0 = makeFakeContainerStats(container0, imageFsMountpoint) 104 containerLogStats0 = makeFakeLogStats(1000) 105 container1 = makeFakeContainer(sandbox0, cName1, 0, false) 106 containerStats1 = makeFakeContainerStats(container1, unknownMountpoint) 107 containerLogStats1 = makeFakeLogStats(2000) 108 109 sandbox1 = makeFakePodSandbox("sandbox1-name", "sandbox1-uid", "sandbox1-ns", false) 110 sandbox1Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox1.PodSandboxStatus.Metadata.Uid)) 111 container2 = makeFakeContainer(sandbox1, cName2, 0, false) 112 containerStats2 = makeFakeContainerStats(container2, imageFsMountpoint) 113 containerLogStats2 = makeFakeLogStats(3000) 114 115 sandbox2 = makeFakePodSandbox("sandbox2-name", "sandbox2-uid", "sandbox2-ns", false) 116 sandbox2Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox2.PodSandboxStatus.Metadata.Uid)) 117 container3 = makeFakeContainer(sandbox2, cName3, 0, true) 118 containerStats3 = makeFakeContainerStats(container3, imageFsMountpoint) 119 container4 = makeFakeContainer(sandbox2, cName3, 1, false) 120 containerStats4 = makeFakeContainerStats(container4, imageFsMountpoint) 121 containerLogStats4 = makeFakeLogStats(4000) 122 123 // Running pod with a terminated container and a running container 124 sandbox3 = makeFakePodSandbox("sandbox3-name", "sandbox3-uid", "sandbox3-ns", false) 125 sandbox3Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox3.PodSandboxStatus.Metadata.Uid)) 126 container5 = makeFakeContainer(sandbox3, cName5, 0, true) 127 containerStats5 = makeFakeContainerStats(container5, imageFsMountpoint) 128 containerLogStats5 = makeFakeLogStats(5000) 129 container8 = makeFakeContainer(sandbox3, cName8, 0, false) 130 containerStats8 = makeFakeContainerStats(container8, imageFsMountpoint) 131 containerLogStats8 = makeFakeLogStats(6000) 132 133 // Terminated pod sandbox 134 sandbox4 = makeFakePodSandbox("sandbox1-name", "sandbox1-uid", "sandbox1-ns", true) 135 container6 = makeFakeContainer(sandbox4, cName6, 0, true) 136 containerStats6 = makeFakeContainerStats(container6, imageFsMountpoint) 137 138 // Terminated pod 139 sandbox5 = makeFakePodSandbox("sandbox1-name", "sandbox5-uid", "sandbox1-ns", true) 140 container7 = makeFakeContainer(sandbox5, cName7, 0, true) 141 containerStats7 = makeFakeContainerStats(container7, imageFsMountpoint) 142 143 podLogName0 = "pod-log-0" 144 podLogName1 = "pod-log-1" 145 podLogStats0 = makeFakeLogStats(5000) 146 podLogStats1 = makeFakeLogStats(6000) 147 ) 148 149 mockCtrl := gomock.NewController(t) 150 defer mockCtrl.Finish() 151 152 var ( 153 mockCadvisor = cadvisortest.NewMockInterface(mockCtrl) 154 mockRuntimeCache = new(kubecontainertest.MockRuntimeCache) 155 mockPodManager = new(kubepodtest.MockManager) 156 resourceAnalyzer = new(fakeResourceAnalyzer) 157 fakeRuntimeService = critest.NewFakeRuntimeService() 158 fakeImageService = critest.NewFakeImageService() 159 ) 160 161 infos := map[string]cadvisorapiv2.ContainerInfo{ 162 "/": getTestContainerInfo(seedRoot, "", "", ""), 163 "/kubelet": getTestContainerInfo(seedKubelet, "", "", ""), 164 "/system": getTestContainerInfo(seedMisc, "", "", ""), 165 sandbox0.PodSandboxStatus.Id: getTestContainerInfo(seedSandbox0, pName0, sandbox0.PodSandboxStatus.Metadata.Namespace, leaky.PodInfraContainerName), 166 sandbox0Cgroup: getTestContainerInfo(seedSandbox0, "", "", ""), 167 container0.ContainerStatus.Id: getTestContainerInfo(seedContainer0, pName0, sandbox0.PodSandboxStatus.Metadata.Namespace, cName0), 168 container1.ContainerStatus.Id: getTestContainerInfo(seedContainer1, pName0, sandbox0.PodSandboxStatus.Metadata.Namespace, cName1), 169 sandbox1.PodSandboxStatus.Id: getTestContainerInfo(seedSandbox1, pName1, sandbox1.PodSandboxStatus.Metadata.Namespace, leaky.PodInfraContainerName), 170 sandbox1Cgroup: getTestContainerInfo(seedSandbox1, "", "", ""), 171 container2.ContainerStatus.Id: getTestContainerInfo(seedContainer2, pName1, sandbox1.PodSandboxStatus.Metadata.Namespace, cName2), 172 sandbox2.PodSandboxStatus.Id: getTestContainerInfo(seedSandbox2, pName2, sandbox2.PodSandboxStatus.Metadata.Namespace, leaky.PodInfraContainerName), 173 sandbox2Cgroup: getTestContainerInfo(seedSandbox2, "", "", ""), 174 container4.ContainerStatus.Id: getTestContainerInfo(seedContainer3, pName2, sandbox2.PodSandboxStatus.Metadata.Namespace, cName3), 175 sandbox3Cgroup: getTestContainerInfo(seedSandbox3, "", "", ""), 176 } 177 178 options := cadvisorapiv2.RequestOptions{ 179 IdType: cadvisorapiv2.TypeName, 180 Count: 2, 181 Recursive: true, 182 } 183 184 mockCadvisor.EXPECT().ContainerInfoV2("/", options).Return(infos, nil) 185 mockCadvisor.EXPECT().RootFsInfo().Return(rootFsInfo, nil) 186 mockCadvisor.EXPECT().GetDirFsInfo(imageFsMountpoint).Return(imageFsInfo, nil) 187 mockCadvisor.EXPECT().GetDirFsInfo(unknownMountpoint).Return(cadvisorapiv2.FsInfo{}, cadvisorfs.ErrNoSuchDevice) 188 189 fakeRuntimeService.SetFakeSandboxes([]*critest.FakePodSandbox{ 190 sandbox0, sandbox1, sandbox2, sandbox3, sandbox4, sandbox5, 191 }) 192 fakeRuntimeService.SetFakeContainers([]*critest.FakeContainer{ 193 container0, container1, container2, container3, container4, container5, container6, container7, container8, 194 }) 195 fakeRuntimeService.SetFakeContainerStats([]*runtimeapi.ContainerStats{ 196 containerStats0, containerStats1, containerStats2, containerStats3, containerStats4, containerStats5, containerStats6, containerStats7, containerStats8, 197 }) 198 199 ephemeralVolumes := makeFakeVolumeStats([]string{"ephVolume1, ephVolumes2"}) 200 persistentVolumes := makeFakeVolumeStats([]string{"persisVolume1, persisVolumes2"}) 201 resourceAnalyzer.podVolumeStats = serverstats.PodVolumeStats{ 202 EphemeralVolumes: ephemeralVolumes, 203 PersistentVolumes: persistentVolumes, 204 } 205 206 fakeStats := map[string]*volume.Metrics{ 207 kuberuntime.BuildContainerLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName0): containerLogStats0, 208 kuberuntime.BuildContainerLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName1): containerLogStats1, 209 kuberuntime.BuildContainerLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid"), cName2): containerLogStats2, 210 kuberuntime.BuildContainerLogsDirectory("sandbox2-ns", "sandbox2-name", types.UID("sandbox2-uid"), cName3): containerLogStats4, 211 kuberuntime.BuildContainerLogsDirectory("sandbox3-ns", "sandbox3-name", types.UID("sandbox3-uid"), cName5): containerLogStats5, 212 kuberuntime.BuildContainerLogsDirectory("sandbox3-ns", "sandbox3-name", types.UID("sandbox3-uid"), cName8): containerLogStats8, 213 filepath.Join(kuberuntime.BuildPodLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")), podLogName0): podLogStats0, 214 filepath.Join(kuberuntime.BuildPodLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")), podLogName1): podLogStats1, 215 } 216 217 ctrl := gomock.NewController(t) 218 defer ctrl.Finish() 219 220 fakeOS := &kubecontainertest.FakeOS{} 221 fakeOS.ReadDirFn = func(path string) ([]os.DirEntry, error) { 222 var dirEntries []os.DirEntry 223 mockDE := kubecontainertest.NewMockDirEntry(ctrl) 224 switch path { 225 case kuberuntime.BuildPodLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")): 226 mockDE.EXPECT().Name().Return(podLogName0) 227 case kuberuntime.BuildPodLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")): 228 mockDE.EXPECT().Name().Return(podLogName1) 229 default: 230 return nil, nil 231 } 232 mockDE.EXPECT().IsDir().Return(false) 233 dirEntries = append(dirEntries, mockDE) 234 return dirEntries, nil 235 } 236 237 provider := NewCRIStatsProvider( 238 mockCadvisor, 239 resourceAnalyzer, 240 mockPodManager, 241 mockRuntimeCache, 242 fakeRuntimeService, 243 fakeImageService, 244 NewFakeHostStatsProviderWithData(fakeStats, fakeOS), 245 false, 246 ) 247 248 stats, err := provider.ListPodStats(ctx) 249 assert := assert.New(t) 250 assert.NoError(err) 251 assert.Equal(4, len(stats)) 252 253 podStatsMap := make(map[statsapi.PodReference]statsapi.PodStats) 254 for _, s := range stats { 255 podStatsMap[s.PodRef] = s 256 } 257 258 p0 := podStatsMap[statsapi.PodReference{Name: "sandbox0-name", UID: "sandbox0-uid", Namespace: "sandbox0-ns"}] 259 assert.Equal(sandbox0.CreatedAt, p0.StartTime.UnixNano()) 260 assert.Equal(2, len(p0.Containers)) 261 262 checkEphemeralStorageStats(assert, p0, ephemeralVolumes, []*runtimeapi.ContainerStats{containerStats0, containerStats1}, 263 []*volume.Metrics{containerLogStats0, containerLogStats1}, podLogStats0) 264 265 containerStatsMap := make(map[string]statsapi.ContainerStats) 266 for _, s := range p0.Containers { 267 containerStatsMap[s.Name] = s 268 } 269 270 c0 := containerStatsMap[cName0] 271 assert.Equal(container0.CreatedAt, c0.StartTime.UnixNano()) 272 checkCRICPUAndMemoryStats(assert, c0, infos[container0.ContainerStatus.Id].Stats[0]) 273 assert.Nil(c0.Accelerators) 274 checkCRIRootfsStats(assert, c0, containerStats0, &imageFsInfo) 275 checkCRILogsStats(assert, c0, &rootFsInfo, containerLogStats0) 276 277 c1 := containerStatsMap[cName1] 278 assert.Equal(container1.CreatedAt, c1.StartTime.UnixNano()) 279 checkCRICPUAndMemoryStats(assert, c1, infos[container1.ContainerStatus.Id].Stats[0]) 280 assert.Nil(c0.Accelerators) 281 checkCRIRootfsStats(assert, c1, containerStats1, nil) 282 checkCRILogsStats(assert, c1, &rootFsInfo, containerLogStats1) 283 checkCRINetworkStats(assert, p0.Network, infos[sandbox0.PodSandboxStatus.Id].Stats[0].Network) 284 checkCRIPodCPUAndMemoryStats(assert, p0, infos[sandbox0Cgroup].Stats[0]) 285 checkCRIPodSwapStats(assert, p0, infos[sandbox0Cgroup].Stats[0]) 286 287 p1 := podStatsMap[statsapi.PodReference{Name: "sandbox1-name", UID: "sandbox1-uid", Namespace: "sandbox1-ns"}] 288 assert.Equal(sandbox1.CreatedAt, p1.StartTime.UnixNano()) 289 assert.Equal(1, len(p1.Containers)) 290 291 checkEphemeralStorageStats(assert, p1, ephemeralVolumes, []*runtimeapi.ContainerStats{containerStats2}, 292 []*volume.Metrics{containerLogStats2}, podLogStats1) 293 c2 := p1.Containers[0] 294 assert.Equal(cName2, c2.Name) 295 assert.Equal(container2.CreatedAt, c2.StartTime.UnixNano()) 296 checkCRICPUAndMemoryStats(assert, c2, infos[container2.ContainerStatus.Id].Stats[0]) 297 assert.Nil(c0.Accelerators) 298 checkCRIRootfsStats(assert, c2, containerStats2, &imageFsInfo) 299 checkCRILogsStats(assert, c2, &rootFsInfo, containerLogStats2) 300 checkCRINetworkStats(assert, p1.Network, infos[sandbox1.PodSandboxStatus.Id].Stats[0].Network) 301 checkCRIPodCPUAndMemoryStats(assert, p1, infos[sandbox1Cgroup].Stats[0]) 302 checkCRIPodSwapStats(assert, p1, infos[sandbox1Cgroup].Stats[0]) 303 304 p2 := podStatsMap[statsapi.PodReference{Name: "sandbox2-name", UID: "sandbox2-uid", Namespace: "sandbox2-ns"}] 305 assert.Equal(sandbox2.CreatedAt, p2.StartTime.UnixNano()) 306 assert.Equal(1, len(p2.Containers)) 307 308 checkEphemeralStorageStats(assert, p2, ephemeralVolumes, []*runtimeapi.ContainerStats{containerStats4}, 309 []*volume.Metrics{containerLogStats4}, nil) 310 311 c3 := p2.Containers[0] 312 assert.Equal(cName3, c3.Name) 313 assert.Equal(container4.CreatedAt, c3.StartTime.UnixNano()) 314 checkCRICPUAndMemoryStats(assert, c3, infos[container4.ContainerStatus.Id].Stats[0]) 315 assert.Nil(c0.Accelerators) 316 checkCRIRootfsStats(assert, c3, containerStats4, &imageFsInfo) 317 318 checkCRILogsStats(assert, c3, &rootFsInfo, containerLogStats4) 319 checkCRINetworkStats(assert, p2.Network, infos[sandbox2.PodSandboxStatus.Id].Stats[0].Network) 320 checkCRIPodCPUAndMemoryStats(assert, p2, infos[sandbox2Cgroup].Stats[0]) 321 checkCRIPodSwapStats(assert, p2, infos[sandbox2Cgroup].Stats[0]) 322 323 p3 := podStatsMap[statsapi.PodReference{Name: "sandbox3-name", UID: "sandbox3-uid", Namespace: "sandbox3-ns"}] 324 assert.Equal(sandbox3.CreatedAt, p3.StartTime.UnixNano()) 325 assert.Equal(1, len(p3.Containers)) 326 327 c8 := p3.Containers[0] 328 assert.Equal(cName8, c8.Name) 329 assert.Equal(container8.CreatedAt, c8.StartTime.UnixNano()) 330 assert.NotNil(c8.CPU.Time) 331 assert.NotNil(c8.Memory.Time) 332 checkCRIPodCPUAndMemoryStats(assert, p3, infos[sandbox3Cgroup].Stats[0]) 333 checkCRIPodSwapStats(assert, p3, infos[sandbox3Cgroup].Stats[0]) 334 } 335 336 func TestListPodStatsStrictlyFromCRI(t *testing.T) { 337 ctx := context.Background() 338 var ( 339 imageFsMountpoint = "/test/mount/point" 340 unknownMountpoint = "/unknown/mount/point" 341 imageFsInfo = getTestFsInfo(2000) 342 rootFsInfo = getTestFsInfo(1000) 343 344 // A pod that CRI returns stats and cadvisor returns stats 345 // The pod stats from CRI stats 346 sandbox0 = makeFakePodSandbox("sandbox0-name", "sandbox0-uid", "sandbox0-ns", false) 347 sandbox0Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox0.PodSandboxStatus.Metadata.Uid)) 348 container0 = makeFakeContainer(sandbox0, cName0, 0, false) 349 containerStats0 = makeFakeContainerStatsStrictlyFromCRI(seedContainer0, container0, imageFsMountpoint) 350 containerLogStats0 = makeFakeLogStats(1000) 351 container1 = makeFakeContainer(sandbox0, cName1, 0, false) 352 containerStats1 = makeFakeContainerStatsStrictlyFromCRI(seedContainer1, container1, unknownMountpoint) 353 containerLogStats1 = makeFakeLogStats(2000) 354 sandboxPodStats0 = makeFakePodSandboxStatsStrictlyFromCRI(seedSandbox0, sandbox0, containerStats0, containerStats1) 355 356 // A pod that CRI returns stats and cadvisor returns no stats 357 // The pod stats from CRI stats 358 sandbox1 = makeFakePodSandbox("sandbox1-name", "sandbox1-uid", "sandbox1-ns", false) 359 sandbox1Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox1.PodSandboxStatus.Metadata.Uid)) 360 container2 = makeFakeContainer(sandbox1, cName2, 0, false) 361 containerStats2 = makeFakeContainerStatsStrictlyFromCRI(seedContainer2, container2, imageFsMountpoint) 362 containerLogStats2 = makeFakeLogStats(3000) 363 sandboxPodStats1 = makeFakePodSandboxStatsStrictlyFromCRI(seedSandbox1, sandbox1, containerStats2) 364 365 podLogName0 = "pod-log-0" 366 podLogName1 = "pod-log-1" 367 podLogStats0 = makeFakeLogStats(5000) 368 podLogStats1 = makeFakeLogStats(6000) 369 ) 370 mockCtrl := gomock.NewController(t) 371 defer mockCtrl.Finish() 372 var ( 373 mockCadvisor = cadvisortest.NewMockInterface(mockCtrl) 374 mockRuntimeCache = new(kubecontainertest.MockRuntimeCache) 375 mockPodManager = new(kubepodtest.MockManager) 376 resourceAnalyzer = new(fakeResourceAnalyzer) 377 fakeRuntimeService = critest.NewFakeRuntimeService() 378 fakeImageService = critest.NewFakeImageService() 379 ) 380 infos := map[string]cadvisorapiv2.ContainerInfo{ 381 "/": getTestContainerInfo(seedRoot, "", "", ""), 382 "/kubelet": getTestContainerInfo(seedKubelet, "", "", ""), 383 "/system": getTestContainerInfo(seedMisc, "", "", ""), 384 sandbox0.PodSandboxStatus.Id: getTestContainerInfo(seedSandbox0, pName0, sandbox0.PodSandboxStatus.Metadata.Namespace, leaky.PodInfraContainerName), 385 sandbox0Cgroup: getTestContainerInfo(seedSandbox0, "", "", ""), 386 container0.ContainerStatus.Id: getTestContainerInfo(seedContainer0, pName0, sandbox0.PodSandboxStatus.Metadata.Namespace, cName0), 387 container1.ContainerStatus.Id: getTestContainerInfo(seedContainer1, pName0, sandbox0.PodSandboxStatus.Metadata.Namespace, cName1), 388 } 389 390 exceptedContainerStatsMap := map[string]statsapi.ContainerStats{ 391 cName0: getCRIContainerStatsStrictlyFromCRI(seedContainer0, cName0), 392 cName1: getCRIContainerStatsStrictlyFromCRI(seedContainer1, cName1), 393 cName2: getCRIContainerStatsStrictlyFromCRI(seedContainer2, cName2), 394 } 395 396 prf0 := statsapi.PodReference{Name: "sandbox0-name", UID: "sandbox0-uid", Namespace: "sandbox0-ns"} 397 prf1 := statsapi.PodReference{Name: "sandbox1-name", UID: "sandbox1-uid", Namespace: "sandbox1-ns"} 398 399 exceptedPodStatsMap := map[statsapi.PodReference]statsapi.PodStats{ 400 prf0: getPodSandboxStatsStrictlyFromCRI(seedSandbox0, sandbox0), 401 prf1: getPodSandboxStatsStrictlyFromCRI(seedSandbox1, sandbox1), 402 } 403 404 options := cadvisorapiv2.RequestOptions{ 405 IdType: cadvisorapiv2.TypeName, 406 Count: 2, 407 Recursive: true, 408 } 409 mockCadvisor.EXPECT().ContainerInfoV2("/", options).Return(infos, nil) 410 mockCadvisor.EXPECT().RootFsInfo().Return(rootFsInfo, nil) 411 mockCadvisor.EXPECT().GetDirFsInfo(imageFsMountpoint).Return(imageFsInfo, nil) 412 mockCadvisor.EXPECT().GetDirFsInfo(unknownMountpoint).Return(cadvisorapiv2.FsInfo{}, cadvisorfs.ErrNoSuchDevice) 413 fakeRuntimeService.SetFakeSandboxes([]*critest.FakePodSandbox{ 414 sandbox0, sandbox1, 415 }) 416 fakeRuntimeService.SetFakeContainers([]*critest.FakeContainer{ 417 container0, container1, container2, 418 }) 419 fakeRuntimeService.SetFakeContainerStats([]*runtimeapi.ContainerStats{ 420 containerStats0, containerStats1, containerStats2, 421 }) 422 423 fakeRuntimeService.SetFakePodSandboxStats([]*runtimeapi.PodSandboxStats{ 424 sandboxPodStats0, sandboxPodStats1, 425 }) 426 427 ephemeralVolumes := makeFakeVolumeStats([]string{"ephVolume1, ephVolumes2"}) 428 persistentVolumes := makeFakeVolumeStats([]string{"persisVolume1, persisVolumes2"}) 429 resourceAnalyzer.podVolumeStats = serverstats.PodVolumeStats{ 430 EphemeralVolumes: ephemeralVolumes, 431 PersistentVolumes: persistentVolumes, 432 } 433 fakeStats := map[string]*volume.Metrics{ 434 kuberuntime.BuildContainerLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName0): containerLogStats0, 435 kuberuntime.BuildContainerLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid"), cName1): containerLogStats1, 436 kuberuntime.BuildContainerLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid"), cName2): containerLogStats2, 437 filepath.Join(kuberuntime.BuildPodLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")), podLogName0): podLogStats0, 438 filepath.Join(kuberuntime.BuildPodLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")), podLogName1): podLogStats1, 439 } 440 ctrl := gomock.NewController(t) 441 defer ctrl.Finish() 442 fakeOS := &kubecontainertest.FakeOS{} 443 fakeOS.ReadDirFn = func(path string) ([]os.DirEntry, error) { 444 var dirEntries []os.DirEntry 445 mockDE := kubecontainertest.NewMockDirEntry(ctrl) 446 switch path { 447 case kuberuntime.BuildPodLogsDirectory("sandbox0-ns", "sandbox0-name", types.UID("sandbox0-uid")): 448 mockDE.EXPECT().Name().Return(podLogName0) 449 case kuberuntime.BuildPodLogsDirectory("sandbox1-ns", "sandbox1-name", types.UID("sandbox1-uid")): 450 mockDE.EXPECT().Name().Return(podLogName1) 451 default: 452 return nil, nil 453 } 454 mockDE.EXPECT().IsDir().Return(false) 455 dirEntries = append(dirEntries, mockDE) 456 return dirEntries, nil 457 } 458 provider := NewCRIStatsProvider( 459 mockCadvisor, 460 resourceAnalyzer, 461 mockPodManager, 462 mockRuntimeCache, 463 fakeRuntimeService, 464 fakeImageService, 465 NewFakeHostStatsProviderWithData(fakeStats, fakeOS), 466 true, 467 ) 468 469 cadvisorInfos, err := getCadvisorContainerInfo(mockCadvisor) 470 if err != nil { 471 t.Errorf("failed to get container info from cadvisor: %v", err) 472 } 473 stats, err := provider.ListPodStats(ctx) 474 assert := assert.New(t) 475 assert.NoError(err) 476 assert.Equal(2, len(stats)) 477 podStatsMap := make(map[statsapi.PodReference]statsapi.PodStats) 478 for _, s := range stats { 479 podStatsMap[s.PodRef] = s 480 } 481 p0 := podStatsMap[prf0] 482 assert.Equal(sandbox0.CreatedAt, p0.StartTime.UnixNano()) 483 assert.Equal(2, len(p0.Containers)) 484 485 checkEphemeralStorageStats(assert, p0, ephemeralVolumes, []*runtimeapi.ContainerStats{containerStats0, containerStats1}, 486 []*volume.Metrics{containerLogStats0, containerLogStats1}, podLogStats0) 487 488 containerStatsMap := make(map[string]statsapi.ContainerStats) 489 for _, s := range p0.Containers { 490 containerStatsMap[s.Name] = s 491 } 492 493 c0 := containerStatsMap[cName0] 494 assert.Equal(container0.CreatedAt, c0.StartTime.UnixNano()) 495 checkCRICPUAndMemoryStatsForStrictlyFromCRI(assert, c0, exceptedContainerStatsMap[cName0]) 496 assert.Nil(c0.Accelerators) 497 checkCRIRootfsStats(assert, c0, containerStats0, &imageFsInfo) 498 checkCRILogsStats(assert, c0, &rootFsInfo, containerLogStats0) 499 500 c1 := containerStatsMap[cName1] 501 assert.Equal(container1.CreatedAt, c1.StartTime.UnixNano()) 502 checkCRICPUAndMemoryStatsForStrictlyFromCRI(assert, c1, exceptedContainerStatsMap[cName1]) 503 assert.Nil(c0.Accelerators) 504 checkCRIRootfsStats(assert, c1, containerStats1, nil) 505 checkCRILogsStats(assert, c1, &rootFsInfo, containerLogStats1) 506 checkCRIPodCPUAndMemoryStatsStrictlyFromCRI(assert, p0, exceptedPodStatsMap[prf0]) 507 assert.NotNil(cadvisorInfos[sandbox0Cgroup].Stats[0].Cpu) 508 assert.NotNil(cadvisorInfos[sandbox0Cgroup].Stats[0].Memory) 509 510 p1 := podStatsMap[prf1] 511 assert.Equal(sandbox1.CreatedAt, p1.StartTime.UnixNano()) 512 assert.Equal(1, len(p1.Containers)) 513 514 checkEphemeralStorageStats(assert, p1, ephemeralVolumes, []*runtimeapi.ContainerStats{containerStats2}, 515 []*volume.Metrics{containerLogStats2}, podLogStats1) 516 c2 := p1.Containers[0] 517 assert.Equal(cName2, c2.Name) 518 assert.Equal(container2.CreatedAt, c2.StartTime.UnixNano()) 519 checkCRICPUAndMemoryStatsForStrictlyFromCRI(assert, c2, exceptedContainerStatsMap[cName2]) 520 assert.Nil(c0.Accelerators) 521 checkCRIRootfsStats(assert, c2, containerStats2, &imageFsInfo) 522 checkCRILogsStats(assert, c2, &rootFsInfo, containerLogStats2) 523 checkCRIPodCPUAndMemoryStatsStrictlyFromCRI(assert, p1, exceptedPodStatsMap[prf1]) 524 525 if runtime.GOOS == "linux" { 526 if _, ok := cadvisorInfos[sandbox1Cgroup]; ok { 527 t.Errorf("expect no cadvisor stats for pod %v", prf1) 528 } 529 } 530 } 531 func TestCRIListPodCPUAndMemoryStats(t *testing.T) { 532 ctx := context.Background() 533 534 var ( 535 imageFsMountpoint = "/test/mount/point" 536 unknownMountpoint = "/unknown/mount/point" 537 538 sandbox0 = makeFakePodSandbox("sandbox0-name", "sandbox0-uid", "sandbox0-ns", false) 539 sandbox0Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox0.PodSandboxStatus.Metadata.Uid)) 540 container0 = makeFakeContainer(sandbox0, cName0, 0, false) 541 containerStats0 = makeFakeContainerStats(container0, imageFsMountpoint) 542 container1 = makeFakeContainer(sandbox0, cName1, 0, false) 543 containerStats1 = makeFakeContainerStats(container1, unknownMountpoint) 544 545 sandbox1 = makeFakePodSandbox("sandbox1-name", "sandbox1-uid", "sandbox1-ns", false) 546 sandbox1Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox1.PodSandboxStatus.Metadata.Uid)) 547 container2 = makeFakeContainer(sandbox1, cName2, 0, false) 548 containerStats2 = makeFakeContainerStats(container2, imageFsMountpoint) 549 550 sandbox2 = makeFakePodSandbox("sandbox2-name", "sandbox2-uid", "sandbox2-ns", false) 551 sandbox2Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox2.PodSandboxStatus.Metadata.Uid)) 552 container3 = makeFakeContainer(sandbox2, cName3, 0, true) 553 containerStats3 = makeFakeContainerStats(container3, imageFsMountpoint) 554 container4 = makeFakeContainer(sandbox2, cName3, 1, false) 555 containerStats4 = makeFakeContainerStats(container4, imageFsMountpoint) 556 557 // Running pod with a terminated container and a running container 558 sandbox3 = makeFakePodSandbox("sandbox3-name", "sandbox3-uid", "sandbox3-ns", false) 559 sandbox3Cgroup = "/" + cm.GetPodCgroupNameSuffix(types.UID(sandbox3.PodSandboxStatus.Metadata.Uid)) 560 container5 = makeFakeContainer(sandbox3, cName5, 0, true) 561 containerStats5 = makeFakeContainerStats(container5, imageFsMountpoint) 562 container8 = makeFakeContainer(sandbox3, cName8, 0, false) 563 containerStats8 = makeFakeContainerStats(container8, imageFsMountpoint) 564 565 // Terminated pod sandbox 566 sandbox4 = makeFakePodSandbox("sandbox1-name", "sandbox1-uid", "sandbox1-ns", true) 567 container6 = makeFakeContainer(sandbox4, cName6, 0, true) 568 containerStats6 = makeFakeContainerStats(container6, imageFsMountpoint) 569 570 // Terminated pod 571 sandbox5 = makeFakePodSandbox("sandbox1-name", "sandbox5-uid", "sandbox1-ns", true) 572 container7 = makeFakeContainer(sandbox5, cName7, 0, true) 573 containerStats7 = makeFakeContainerStats(container7, imageFsMountpoint) 574 575 // A pod that cadvisor returns no stats 576 sandbox6 = makeFakePodSandbox("sandbox6-name", "sandbox6-uid", "sandbox6-ns", false) 577 container9 = makeFakeContainer(sandbox6, cName9, 0, false) 578 containerStats9 = makeFakeContainerStats(container9, imageFsMountpoint) 579 ) 580 581 mockCtrl := gomock.NewController(t) 582 defer mockCtrl.Finish() 583 584 var ( 585 mockCadvisor = cadvisortest.NewMockInterface(mockCtrl) 586 mockRuntimeCache = new(kubecontainertest.MockRuntimeCache) 587 mockPodManager = new(kubepodtest.MockManager) 588 resourceAnalyzer = new(fakeResourceAnalyzer) 589 fakeRuntimeService = critest.NewFakeRuntimeService() 590 ) 591 592 infos := map[string]cadvisorapiv2.ContainerInfo{ 593 "/": getTestContainerInfo(seedRoot, "", "", ""), 594 "/kubelet": getTestContainerInfo(seedKubelet, "", "", ""), 595 "/system": getTestContainerInfo(seedMisc, "", "", ""), 596 sandbox0.PodSandboxStatus.Id: getTestContainerInfo(seedSandbox0, pName0, sandbox0.PodSandboxStatus.Metadata.Namespace, leaky.PodInfraContainerName), 597 sandbox0Cgroup: getTestContainerInfo(seedSandbox0, "", "", ""), 598 container0.ContainerStatus.Id: getTestContainerInfo(seedContainer0, pName0, sandbox0.PodSandboxStatus.Metadata.Namespace, cName0), 599 container1.ContainerStatus.Id: getTestContainerInfo(seedContainer1, pName0, sandbox0.PodSandboxStatus.Metadata.Namespace, cName1), 600 sandbox1.PodSandboxStatus.Id: getTestContainerInfo(seedSandbox1, pName1, sandbox1.PodSandboxStatus.Metadata.Namespace, leaky.PodInfraContainerName), 601 sandbox1Cgroup: getTestContainerInfo(seedSandbox1, "", "", ""), 602 container2.ContainerStatus.Id: getTestContainerInfo(seedContainer2, pName1, sandbox1.PodSandboxStatus.Metadata.Namespace, cName2), 603 sandbox2.PodSandboxStatus.Id: getTestContainerInfo(seedSandbox2, pName2, sandbox2.PodSandboxStatus.Metadata.Namespace, leaky.PodInfraContainerName), 604 sandbox2Cgroup: getTestContainerInfo(seedSandbox2, "", "", ""), 605 container4.ContainerStatus.Id: getTestContainerInfo(seedContainer3, pName2, sandbox2.PodSandboxStatus.Metadata.Namespace, cName3), 606 sandbox3Cgroup: getTestContainerInfo(seedSandbox3, "", "", ""), 607 } 608 609 options := cadvisorapiv2.RequestOptions{ 610 IdType: cadvisorapiv2.TypeName, 611 Count: 2, 612 Recursive: true, 613 } 614 615 mockCadvisor.EXPECT().ContainerInfoV2("/", options).Return(infos, nil) 616 617 fakeRuntimeService.SetFakeSandboxes([]*critest.FakePodSandbox{ 618 sandbox0, sandbox1, sandbox2, sandbox3, sandbox4, sandbox5, sandbox6, 619 }) 620 fakeRuntimeService.SetFakeContainers([]*critest.FakeContainer{ 621 container0, container1, container2, container3, container4, container5, container6, container7, container8, container9, 622 }) 623 fakeRuntimeService.SetFakeContainerStats([]*runtimeapi.ContainerStats{ 624 containerStats0, containerStats1, containerStats2, containerStats3, containerStats4, containerStats5, containerStats6, containerStats7, containerStats8, containerStats9, 625 }) 626 627 ephemeralVolumes := makeFakeVolumeStats([]string{"ephVolume1, ephVolumes2"}) 628 persistentVolumes := makeFakeVolumeStats([]string{"persisVolume1, persisVolumes2"}) 629 resourceAnalyzer.podVolumeStats = serverstats.PodVolumeStats{ 630 EphemeralVolumes: ephemeralVolumes, 631 PersistentVolumes: persistentVolumes, 632 } 633 634 provider := NewCRIStatsProvider( 635 mockCadvisor, 636 resourceAnalyzer, 637 mockPodManager, 638 mockRuntimeCache, 639 fakeRuntimeService, 640 nil, 641 NewFakeHostStatsProvider(), 642 false, 643 ) 644 645 stats, err := provider.ListPodCPUAndMemoryStats(ctx) 646 assert := assert.New(t) 647 assert.NoError(err) 648 assert.Equal(5, len(stats)) 649 650 podStatsMap := make(map[statsapi.PodReference]statsapi.PodStats) 651 for _, s := range stats { 652 podStatsMap[s.PodRef] = s 653 } 654 655 p0 := podStatsMap[statsapi.PodReference{Name: "sandbox0-name", UID: "sandbox0-uid", Namespace: "sandbox0-ns"}] 656 assert.Equal(sandbox0.CreatedAt, p0.StartTime.UnixNano()) 657 assert.Equal(2, len(p0.Containers)) 658 assert.Nil(p0.EphemeralStorage) 659 assert.Nil(p0.VolumeStats) 660 assert.Nil(p0.Network) 661 checkCRIPodCPUAndMemoryStats(assert, p0, infos[sandbox0Cgroup].Stats[0]) 662 663 containerStatsMap := make(map[string]statsapi.ContainerStats) 664 for _, s := range p0.Containers { 665 containerStatsMap[s.Name] = s 666 } 667 668 c0 := containerStatsMap[cName0] 669 assert.Equal(container0.CreatedAt, c0.StartTime.UnixNano()) 670 checkCRICPUAndMemoryStats(assert, c0, infos[container0.ContainerStatus.Id].Stats[0]) 671 assert.Nil(c0.Rootfs) 672 assert.Nil(c0.Logs) 673 assert.Nil(c0.Accelerators) 674 assert.Nil(c0.UserDefinedMetrics) 675 c1 := containerStatsMap[cName1] 676 assert.Equal(container1.CreatedAt, c1.StartTime.UnixNano()) 677 checkCRICPUAndMemoryStats(assert, c1, infos[container1.ContainerStatus.Id].Stats[0]) 678 assert.Nil(c1.Rootfs) 679 assert.Nil(c1.Logs) 680 assert.Nil(c1.Accelerators) 681 assert.Nil(c1.UserDefinedMetrics) 682 683 p1 := podStatsMap[statsapi.PodReference{Name: "sandbox1-name", UID: "sandbox1-uid", Namespace: "sandbox1-ns"}] 684 assert.Equal(sandbox1.CreatedAt, p1.StartTime.UnixNano()) 685 assert.Equal(1, len(p1.Containers)) 686 assert.Nil(p1.EphemeralStorage) 687 assert.Nil(p1.VolumeStats) 688 assert.Nil(p1.Network) 689 checkCRIPodCPUAndMemoryStats(assert, p1, infos[sandbox1Cgroup].Stats[0]) 690 691 c2 := p1.Containers[0] 692 assert.Equal(cName2, c2.Name) 693 assert.Equal(container2.CreatedAt, c2.StartTime.UnixNano()) 694 checkCRICPUAndMemoryStats(assert, c2, infos[container2.ContainerStatus.Id].Stats[0]) 695 assert.Nil(c2.Rootfs) 696 assert.Nil(c2.Logs) 697 assert.Nil(c2.Accelerators) 698 assert.Nil(c2.UserDefinedMetrics) 699 700 p2 := podStatsMap[statsapi.PodReference{Name: "sandbox2-name", UID: "sandbox2-uid", Namespace: "sandbox2-ns"}] 701 assert.Equal(sandbox2.CreatedAt, p2.StartTime.UnixNano()) 702 assert.Equal(1, len(p2.Containers)) 703 assert.Nil(p2.EphemeralStorage) 704 assert.Nil(p2.VolumeStats) 705 assert.Nil(p2.Network) 706 checkCRIPodCPUAndMemoryStats(assert, p2, infos[sandbox2Cgroup].Stats[0]) 707 708 c3 := p2.Containers[0] 709 assert.Equal(cName3, c3.Name) 710 assert.Equal(container4.CreatedAt, c3.StartTime.UnixNano()) 711 checkCRICPUAndMemoryStats(assert, c3, infos[container4.ContainerStatus.Id].Stats[0]) 712 assert.Nil(c2.Rootfs) 713 assert.Nil(c2.Logs) 714 assert.Nil(c2.Accelerators) 715 assert.Nil(c2.UserDefinedMetrics) 716 717 p3 := podStatsMap[statsapi.PodReference{Name: "sandbox3-name", UID: "sandbox3-uid", Namespace: "sandbox3-ns"}] 718 assert.Equal(sandbox3.CreatedAt, p3.StartTime.UnixNano()) 719 assert.Equal(1, len(p3.Containers)) 720 721 c8 := p3.Containers[0] 722 assert.Equal(cName8, c8.Name) 723 assert.Equal(container8.CreatedAt, c8.StartTime.UnixNano()) 724 assert.NotNil(c8.CPU.Time) 725 assert.NotNil(c8.Memory.Time) 726 checkCRIPodCPUAndMemoryStats(assert, p3, infos[sandbox3Cgroup].Stats[0]) 727 728 p6 := podStatsMap[statsapi.PodReference{Name: "sandbox6-name", UID: "sandbox6-uid", Namespace: "sandbox6-ns"}] 729 assert.Equal(sandbox6.CreatedAt, p6.StartTime.UnixNano()) 730 assert.Equal(1, len(p6.Containers)) 731 732 c9 := p6.Containers[0] 733 assert.Equal(cName9, c9.Name) 734 assert.Equal(container9.CreatedAt, c9.StartTime.UnixNano()) 735 assert.NotNil(c9.CPU.Time) 736 assert.Equal(containerStats9.Cpu.Timestamp, p6.CPU.Time.UnixNano()) 737 assert.NotNil(c9.Memory.Time) 738 assert.Equal(containerStats9.Memory.Timestamp, p6.Memory.Time.UnixNano()) 739 } 740 741 func TestCRIImagesFsStats(t *testing.T) { 742 ctx := context.Background() 743 var ( 744 imageFsMountpoint = "/test/mount/point" 745 imageFsInfo = getTestFsInfo(2000) 746 imageFsUsage = makeFakeImageFsUsage(imageFsMountpoint) 747 ) 748 749 mockCtrl := gomock.NewController(t) 750 defer mockCtrl.Finish() 751 752 var ( 753 mockCadvisor = cadvisortest.NewMockInterface(mockCtrl) 754 mockRuntimeCache = new(kubecontainertest.MockRuntimeCache) 755 mockPodManager = new(kubepodtest.MockManager) 756 resourceAnalyzer = new(fakeResourceAnalyzer) 757 fakeRuntimeService = critest.NewFakeRuntimeService() 758 fakeImageService = critest.NewFakeImageService() 759 ) 760 mockCadvisor.EXPECT().GetDirFsInfo(imageFsMountpoint).Return(imageFsInfo, nil) 761 fakeImageService.SetFakeFilesystemUsage([]*runtimeapi.FilesystemUsage{ 762 imageFsUsage, 763 }) 764 765 provider := NewCRIStatsProvider( 766 mockCadvisor, 767 resourceAnalyzer, 768 mockPodManager, 769 mockRuntimeCache, 770 fakeRuntimeService, 771 fakeImageService, 772 NewFakeHostStatsProvider(), 773 false, 774 ) 775 776 stats, containerStats, err := provider.ImageFsStats(ctx) 777 assert := assert.New(t) 778 assert.NoError(err) 779 780 assert.Equal(imageFsUsage.Timestamp, stats.Time.UnixNano()) 781 assert.Equal(imageFsInfo.Available, *stats.AvailableBytes) 782 assert.Equal(imageFsInfo.Capacity, *stats.CapacityBytes) 783 assert.Equal(imageFsInfo.InodesFree, stats.InodesFree) 784 assert.Equal(imageFsInfo.Inodes, stats.Inodes) 785 assert.Equal(imageFsUsage.UsedBytes.Value, *stats.UsedBytes) 786 assert.Equal(imageFsUsage.InodesUsed.Value, *stats.InodesUsed) 787 788 assert.Equal(imageFsUsage.Timestamp, containerStats.Time.UnixNano()) 789 assert.Equal(imageFsInfo.Available, *containerStats.AvailableBytes) 790 assert.Equal(imageFsInfo.Capacity, *containerStats.CapacityBytes) 791 assert.Equal(imageFsInfo.InodesFree, containerStats.InodesFree) 792 assert.Equal(imageFsInfo.Inodes, containerStats.Inodes) 793 assert.Equal(imageFsUsage.UsedBytes.Value, *containerStats.UsedBytes) 794 assert.Equal(imageFsUsage.InodesUsed.Value, *containerStats.InodesUsed) 795 796 } 797 798 func makeFakePodSandbox(name, uid, namespace string, terminated bool) *critest.FakePodSandbox { 799 p := &critest.FakePodSandbox{ 800 PodSandboxStatus: runtimeapi.PodSandboxStatus{ 801 Metadata: &runtimeapi.PodSandboxMetadata{ 802 Name: name, 803 Uid: uid, 804 Namespace: namespace, 805 }, 806 State: runtimeapi.PodSandboxState_SANDBOX_READY, 807 CreatedAt: time.Now().UnixNano(), 808 }, 809 } 810 if terminated { 811 p.PodSandboxStatus.State = runtimeapi.PodSandboxState_SANDBOX_NOTREADY 812 } 813 p.PodSandboxStatus.Id = strings.ReplaceAll(string(uuid.NewUUID()), "-", "") 814 return p 815 } 816 817 func makeFakeContainer(sandbox *critest.FakePodSandbox, name string, attempt uint32, terminated bool) *critest.FakeContainer { 818 sandboxID := sandbox.PodSandboxStatus.Id 819 c := &critest.FakeContainer{ 820 SandboxID: sandboxID, 821 ContainerStatus: runtimeapi.ContainerStatus{ 822 Metadata: &runtimeapi.ContainerMetadata{Name: name, Attempt: attempt}, 823 Image: &runtimeapi.ImageSpec{}, 824 ImageRef: "fake-image-ref", 825 CreatedAt: time.Now().UnixNano(), 826 }, 827 } 828 c.ContainerStatus.Labels = map[string]string{ 829 "io.kubernetes.pod.name": sandbox.Metadata.Name, 830 "io.kubernetes.pod.uid": sandbox.Metadata.Uid, 831 "io.kubernetes.pod.namespace": sandbox.Metadata.Namespace, 832 "io.kubernetes.container.name": name, 833 } 834 if terminated { 835 c.ContainerStatus.State = runtimeapi.ContainerState_CONTAINER_EXITED 836 } else { 837 c.ContainerStatus.State = runtimeapi.ContainerState_CONTAINER_RUNNING 838 } 839 c.ContainerStatus.Id = strings.ReplaceAll(string(uuid.NewUUID()), "-", "") 840 return c 841 } 842 843 func makeFakeContainerStats(container *critest.FakeContainer, imageFsMountpoint string) *runtimeapi.ContainerStats { 844 containerStats := &runtimeapi.ContainerStats{ 845 Attributes: &runtimeapi.ContainerAttributes{ 846 Id: container.ContainerStatus.Id, 847 Metadata: container.ContainerStatus.Metadata, 848 }, 849 WritableLayer: &runtimeapi.FilesystemUsage{ 850 Timestamp: time.Now().UnixNano(), 851 FsId: &runtimeapi.FilesystemIdentifier{Mountpoint: imageFsMountpoint}, 852 UsedBytes: &runtimeapi.UInt64Value{Value: rand.Uint64() / 100}, 853 InodesUsed: &runtimeapi.UInt64Value{Value: rand.Uint64() / 100}, 854 }, 855 } 856 if container.State == runtimeapi.ContainerState_CONTAINER_EXITED { 857 containerStats.Cpu = nil 858 containerStats.Memory = nil 859 } else { 860 containerStats.Cpu = &runtimeapi.CpuUsage{ 861 Timestamp: time.Now().UnixNano(), 862 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{Value: rand.Uint64()}, 863 } 864 containerStats.Memory = &runtimeapi.MemoryUsage{ 865 Timestamp: time.Now().UnixNano(), 866 WorkingSetBytes: &runtimeapi.UInt64Value{Value: rand.Uint64()}, 867 } 868 } 869 return containerStats 870 } 871 872 // makeFakeContainerStatsStrictlyFromCRI use CRI offset to fake CRI container stats to distinguish cadvisor stats. 873 func makeFakeContainerStatsStrictlyFromCRI(seed int, container *critest.FakeContainer, imageFsMountpoint string) *runtimeapi.ContainerStats { 874 containerStats := &runtimeapi.ContainerStats{ 875 Attributes: &runtimeapi.ContainerAttributes{ 876 Id: container.ContainerStatus.Id, 877 Metadata: container.ContainerStatus.Metadata, 878 }, 879 WritableLayer: &runtimeapi.FilesystemUsage{ 880 Timestamp: timestamp.UnixNano(), 881 FsId: &runtimeapi.FilesystemIdentifier{Mountpoint: imageFsMountpoint}, 882 UsedBytes: &runtimeapi.UInt64Value{Value: uint64(seed + offsetCRI + offsetFsUsage)}, 883 InodesUsed: &runtimeapi.UInt64Value{Value: uint64(seed + offsetCRI + offsetFsInodeUsage)}, 884 }, 885 } 886 if container.State == runtimeapi.ContainerState_CONTAINER_EXITED { 887 containerStats.Cpu = nil 888 containerStats.Memory = nil 889 } else { 890 containerStats.Cpu = &runtimeapi.CpuUsage{ 891 Timestamp: timestamp.UnixNano(), 892 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{Value: uint64(seed + offsetCRI + offsetCPUUsageCoreSeconds)}, 893 } 894 containerStats.Memory = &runtimeapi.MemoryUsage{ 895 Timestamp: timestamp.UnixNano(), 896 WorkingSetBytes: &runtimeapi.UInt64Value{Value: uint64(seed + offsetCRI + offsetMemWorkingSetBytes)}, 897 } 898 } 899 return containerStats 900 } 901 902 func makeFakePodSandboxStatsStrictlyFromCRI(seed int, podSandbox *critest.FakePodSandbox, podContainerStats ...*runtimeapi.ContainerStats) *runtimeapi.PodSandboxStats { 903 podSandboxStats := &runtimeapi.PodSandboxStats{ 904 Attributes: &runtimeapi.PodSandboxAttributes{ 905 Id: podSandbox.Id, 906 Metadata: podSandbox.Metadata, 907 }, 908 Linux: &runtimeapi.LinuxPodSandboxStats{}, 909 } 910 podSandboxStats.Linux.Containers = append(podSandboxStats.Linux.Containers, podContainerStats...) 911 if podSandbox.State == runtimeapi.PodSandboxState_SANDBOX_NOTREADY { 912 podSandboxStats.Linux.Cpu = nil 913 podSandboxStats.Linux.Memory = nil 914 } else { 915 podSandboxStats.Linux.Cpu = &runtimeapi.CpuUsage{ 916 Timestamp: timestamp.UnixNano(), 917 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{Value: uint64(seed + offsetCRI + offsetCPUUsageCoreSeconds)}, 918 } 919 podSandboxStats.Linux.Memory = &runtimeapi.MemoryUsage{ 920 Timestamp: timestamp.UnixNano(), 921 WorkingSetBytes: &runtimeapi.UInt64Value{Value: uint64(seed + offsetCRI + offsetMemWorkingSetBytes)}, 922 } 923 } 924 return podSandboxStats 925 } 926 func getPodSandboxStatsStrictlyFromCRI(seed int, podSandbox *critest.FakePodSandbox) statsapi.PodStats { 927 podStats := statsapi.PodStats{ 928 PodRef: statsapi.PodReference{ 929 Name: podSandbox.Metadata.Name, 930 UID: podSandbox.Metadata.Uid, 931 Namespace: podSandbox.Metadata.Namespace, 932 }, 933 // The StartTime in the summary API is the pod creation time. 934 StartTime: metav1.NewTime(time.Unix(0, podSandbox.CreatedAt)), 935 } 936 if podSandbox.State == runtimeapi.PodSandboxState_SANDBOX_NOTREADY { 937 podStats.CPU = nil 938 podStats.Memory = nil 939 } else { 940 usageCoreNanoSeconds := uint64(seed + offsetCRI + offsetCPUUsageCoreSeconds) 941 workingSetBytes := uint64(seed + offsetCRI + offsetMemWorkingSetBytes) 942 podStats.CPU = &statsapi.CPUStats{ 943 Time: metav1.NewTime(timestamp), 944 UsageCoreNanoSeconds: &usageCoreNanoSeconds, 945 } 946 podStats.Memory = &statsapi.MemoryStats{ 947 Time: metav1.NewTime(timestamp), 948 WorkingSetBytes: &workingSetBytes, 949 } 950 } 951 952 return podStats 953 } 954 955 func makeFakeImageFsUsage(fsMountpoint string) *runtimeapi.FilesystemUsage { 956 return &runtimeapi.FilesystemUsage{ 957 Timestamp: time.Now().UnixNano(), 958 FsId: &runtimeapi.FilesystemIdentifier{Mountpoint: fsMountpoint}, 959 UsedBytes: &runtimeapi.UInt64Value{Value: rand.Uint64()}, 960 InodesUsed: &runtimeapi.UInt64Value{Value: rand.Uint64()}, 961 } 962 } 963 964 func makeFakeVolumeStats(volumeNames []string) []statsapi.VolumeStats { 965 volumes := make([]statsapi.VolumeStats, len(volumeNames)) 966 availableBytes := rand.Uint64() 967 capacityBytes := rand.Uint64() 968 usedBytes := rand.Uint64() / 100 969 inodes := rand.Uint64() 970 inodesFree := rand.Uint64() 971 inodesUsed := rand.Uint64() / 100 972 for i, name := range volumeNames { 973 fsStats := statsapi.FsStats{ 974 Time: metav1.NewTime(time.Now()), 975 AvailableBytes: &availableBytes, 976 CapacityBytes: &capacityBytes, 977 UsedBytes: &usedBytes, 978 Inodes: &inodes, 979 InodesFree: &inodesFree, 980 InodesUsed: &inodesUsed, 981 } 982 volumes[i] = statsapi.VolumeStats{ 983 FsStats: fsStats, 984 Name: name, 985 } 986 } 987 return volumes 988 } 989 990 func checkCRICPUAndMemoryStats(assert *assert.Assertions, actual statsapi.ContainerStats, cs *cadvisorapiv2.ContainerStats) { 991 assert.Equal(cs.Timestamp.UnixNano(), actual.CPU.Time.UnixNano()) 992 assert.Equal(cs.Cpu.Usage.Total, *actual.CPU.UsageCoreNanoSeconds) 993 assert.Equal(cs.CpuInst.Usage.Total, *actual.CPU.UsageNanoCores) 994 995 assert.Equal(cs.Memory.Usage, *actual.Memory.UsageBytes) 996 assert.Equal(cs.Memory.WorkingSet, *actual.Memory.WorkingSetBytes) 997 assert.Equal(cs.Memory.RSS, *actual.Memory.RSSBytes) 998 assert.Equal(cs.Memory.ContainerData.Pgfault, *actual.Memory.PageFaults) 999 assert.Equal(cs.Memory.ContainerData.Pgmajfault, *actual.Memory.MajorPageFaults) 1000 } 1001 1002 func checkCRICPUAndMemoryStatsForStrictlyFromCRI(assert *assert.Assertions, actual statsapi.ContainerStats, excepted statsapi.ContainerStats) { 1003 assert.Equal(excepted.CPU.Time.UnixNano(), actual.CPU.Time.UnixNano()) 1004 assert.Equal(*excepted.CPU.UsageCoreNanoSeconds, *actual.CPU.UsageCoreNanoSeconds) 1005 assert.Equal(*excepted.Memory.WorkingSetBytes, *actual.Memory.WorkingSetBytes) 1006 } 1007 1008 func checkCRIRootfsStats(assert *assert.Assertions, actual statsapi.ContainerStats, cs *runtimeapi.ContainerStats, imageFsInfo *cadvisorapiv2.FsInfo) { 1009 assert.Equal(cs.WritableLayer.Timestamp, actual.Rootfs.Time.UnixNano()) 1010 if imageFsInfo != nil { 1011 assert.Equal(imageFsInfo.Available, *actual.Rootfs.AvailableBytes) 1012 assert.Equal(imageFsInfo.Capacity, *actual.Rootfs.CapacityBytes) 1013 assert.Equal(*imageFsInfo.InodesFree, *actual.Rootfs.InodesFree) 1014 assert.Equal(*imageFsInfo.Inodes, *actual.Rootfs.Inodes) 1015 } else { 1016 assert.Nil(actual.Rootfs.AvailableBytes) 1017 assert.Nil(actual.Rootfs.CapacityBytes) 1018 assert.Nil(actual.Rootfs.InodesFree) 1019 assert.Nil(actual.Rootfs.Inodes) 1020 } 1021 assert.Equal(cs.WritableLayer.UsedBytes.Value, *actual.Rootfs.UsedBytes) 1022 assert.Equal(cs.WritableLayer.InodesUsed.Value, *actual.Rootfs.InodesUsed) 1023 } 1024 1025 func checkCRILogsStats(assert *assert.Assertions, actual statsapi.ContainerStats, rootFsInfo *cadvisorapiv2.FsInfo, logStats *volume.Metrics) { 1026 assert.Equal(rootFsInfo.Timestamp, actual.Logs.Time.Time) 1027 assert.Equal(rootFsInfo.Available, *actual.Logs.AvailableBytes) 1028 assert.Equal(rootFsInfo.Capacity, *actual.Logs.CapacityBytes) 1029 assert.Equal(*rootFsInfo.InodesFree, *actual.Logs.InodesFree) 1030 assert.Equal(*rootFsInfo.Inodes, *actual.Logs.Inodes) 1031 assert.Equal(uint64(logStats.Used.Value()), *actual.Logs.UsedBytes) 1032 assert.Equal(uint64(logStats.InodesUsed.Value()), *actual.Logs.InodesUsed) 1033 } 1034 1035 func checkEphemeralStorageStats(assert *assert.Assertions, 1036 actual statsapi.PodStats, 1037 volumes []statsapi.VolumeStats, 1038 containers []*runtimeapi.ContainerStats, 1039 containerLogStats []*volume.Metrics, 1040 podLogStats *volume.Metrics) { 1041 var totalUsed, inodesUsed uint64 1042 for _, container := range containers { 1043 totalUsed = totalUsed + container.WritableLayer.UsedBytes.Value 1044 inodesUsed = inodesUsed + container.WritableLayer.InodesUsed.Value 1045 } 1046 1047 for _, volume := range volumes { 1048 totalUsed = totalUsed + *volume.FsStats.UsedBytes 1049 inodesUsed = inodesUsed + *volume.FsStats.InodesUsed 1050 } 1051 1052 for _, logStats := range containerLogStats { 1053 totalUsed = totalUsed + uint64(logStats.Used.Value()) 1054 inodesUsed = inodesUsed + uint64(logStats.InodesUsed.Value()) 1055 } 1056 1057 if podLogStats != nil { 1058 totalUsed = totalUsed + uint64(podLogStats.Used.Value()) 1059 inodesUsed = inodesUsed + uint64(podLogStats.InodesUsed.Value()) 1060 } 1061 1062 assert.Equal(int(totalUsed), int(*actual.EphemeralStorage.UsedBytes)) 1063 assert.Equal(int(inodesUsed), int(*actual.EphemeralStorage.InodesUsed)) 1064 } 1065 1066 func checkCRINetworkStats(assert *assert.Assertions, actual *statsapi.NetworkStats, expected *cadvisorapiv2.NetworkStats) { 1067 assert.Equal(expected.Interfaces[0].RxBytes, *actual.RxBytes) 1068 assert.Equal(expected.Interfaces[0].RxErrors, *actual.RxErrors) 1069 assert.Equal(expected.Interfaces[0].TxBytes, *actual.TxBytes) 1070 assert.Equal(expected.Interfaces[0].TxErrors, *actual.TxErrors) 1071 } 1072 1073 func checkCRIPodCPUAndMemoryStats(assert *assert.Assertions, actual statsapi.PodStats, cs *cadvisorapiv2.ContainerStats) { 1074 if runtime.GOOS != "linux" { 1075 return 1076 } 1077 assert.Equal(cs.Timestamp.UnixNano(), actual.CPU.Time.UnixNano()) 1078 assert.Equal(cs.Cpu.Usage.Total, *actual.CPU.UsageCoreNanoSeconds) 1079 assert.Equal(cs.CpuInst.Usage.Total, *actual.CPU.UsageNanoCores) 1080 1081 assert.Equal(cs.Memory.Usage, *actual.Memory.UsageBytes) 1082 assert.Equal(cs.Memory.WorkingSet, *actual.Memory.WorkingSetBytes) 1083 assert.Equal(cs.Memory.RSS, *actual.Memory.RSSBytes) 1084 assert.Equal(cs.Memory.ContainerData.Pgfault, *actual.Memory.PageFaults) 1085 assert.Equal(cs.Memory.ContainerData.Pgmajfault, *actual.Memory.MajorPageFaults) 1086 } 1087 1088 func checkCRIPodSwapStats(assert *assert.Assertions, actual statsapi.PodStats, cs *cadvisorapiv2.ContainerStats) { 1089 if runtime.GOOS != "linux" { 1090 return 1091 } 1092 1093 assert.Equal(cs.Timestamp.UnixNano(), actual.Swap.Time.UnixNano()) 1094 assert.Equal(cs.Memory.Swap, *actual.Swap.SwapUsageBytes) 1095 } 1096 1097 func checkCRIPodCPUAndMemoryStatsStrictlyFromCRI(assert *assert.Assertions, actual statsapi.PodStats, excepted statsapi.PodStats) { 1098 if runtime.GOOS != "linux" { 1099 return 1100 } 1101 assert.Equal(excepted.CPU.Time.UnixNano(), actual.CPU.Time.UnixNano()) 1102 assert.Equal(*excepted.CPU.UsageCoreNanoSeconds, *actual.CPU.UsageCoreNanoSeconds) 1103 assert.Equal(*excepted.Memory.WorkingSetBytes, *actual.Memory.WorkingSetBytes) 1104 } 1105 1106 func makeFakeLogStats(seed int) *volume.Metrics { 1107 m := &volume.Metrics{} 1108 m.Used = resource.NewQuantity(int64(seed+offsetUsage), resource.BinarySI) 1109 m.InodesUsed = resource.NewQuantity(int64(seed+offsetInodeUsage), resource.BinarySI) 1110 return m 1111 } 1112 1113 func TestGetContainerUsageNanoCores(t *testing.T) { 1114 var value0 uint64 1115 var value1 uint64 = 10000000000 1116 1117 // Test with a large container of 100+ CPUs 1118 var value2 uint64 = 188427786383 1119 1120 tests := []struct { 1121 desc string 1122 cpuUsageCache map[string]*cpuUsageRecord 1123 stats *runtimeapi.ContainerStats 1124 expected *uint64 1125 }{ 1126 { 1127 desc: "should return nil if stats is nil", 1128 cpuUsageCache: map[string]*cpuUsageRecord{}, 1129 }, 1130 { 1131 desc: "should return nil if cpu stats is nil", 1132 cpuUsageCache: map[string]*cpuUsageRecord{}, 1133 stats: &runtimeapi.ContainerStats{ 1134 Attributes: &runtimeapi.ContainerAttributes{ 1135 Id: "1", 1136 }, 1137 Cpu: nil, 1138 }, 1139 }, 1140 { 1141 desc: "should return nil if usageCoreNanoSeconds is nil", 1142 cpuUsageCache: map[string]*cpuUsageRecord{}, 1143 stats: &runtimeapi.ContainerStats{ 1144 Attributes: &runtimeapi.ContainerAttributes{ 1145 Id: "1", 1146 }, 1147 Cpu: &runtimeapi.CpuUsage{ 1148 Timestamp: 1, 1149 UsageCoreNanoSeconds: nil, 1150 }, 1151 }, 1152 }, 1153 { 1154 desc: "should return nil if cpu stats is not cached yet", 1155 cpuUsageCache: map[string]*cpuUsageRecord{}, 1156 stats: &runtimeapi.ContainerStats{ 1157 Attributes: &runtimeapi.ContainerAttributes{ 1158 Id: "1", 1159 }, 1160 Cpu: &runtimeapi.CpuUsage{ 1161 Timestamp: 1, 1162 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{ 1163 Value: 10000000000, 1164 }, 1165 }, 1166 }, 1167 }, 1168 { 1169 desc: "should return zero value if cached cpu stats is equal to current value", 1170 stats: &runtimeapi.ContainerStats{ 1171 Attributes: &runtimeapi.ContainerAttributes{ 1172 Id: "1", 1173 }, 1174 Cpu: &runtimeapi.CpuUsage{ 1175 Timestamp: 1, 1176 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{ 1177 Value: 10000000000, 1178 }, 1179 }, 1180 }, 1181 cpuUsageCache: map[string]*cpuUsageRecord{ 1182 "1": { 1183 stats: &runtimeapi.CpuUsage{ 1184 Timestamp: 0, 1185 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{ 1186 Value: 10000000000, 1187 }, 1188 }, 1189 }, 1190 }, 1191 expected: &value0, 1192 }, 1193 { 1194 desc: "should return correct value if cached cpu stats is not equal to current value", 1195 stats: &runtimeapi.ContainerStats{ 1196 Attributes: &runtimeapi.ContainerAttributes{ 1197 Id: "1", 1198 }, 1199 Cpu: &runtimeapi.CpuUsage{ 1200 Timestamp: int64(time.Second / time.Nanosecond), 1201 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{ 1202 Value: 20000000000, 1203 }, 1204 }, 1205 }, 1206 cpuUsageCache: map[string]*cpuUsageRecord{ 1207 "1": { 1208 stats: &runtimeapi.CpuUsage{ 1209 Timestamp: 0, 1210 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{ 1211 Value: 10000000000, 1212 }, 1213 }, 1214 }, 1215 }, 1216 expected: &value1, 1217 }, 1218 { 1219 desc: "should return correct value if elapsed UsageCoreNanoSeconds exceeds 18446744073", 1220 stats: &runtimeapi.ContainerStats{ 1221 Attributes: &runtimeapi.ContainerAttributes{ 1222 Id: "1", 1223 }, 1224 Cpu: &runtimeapi.CpuUsage{ 1225 Timestamp: int64(time.Second / time.Nanosecond), 1226 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{ 1227 Value: 68172016162105, 1228 }, 1229 }, 1230 }, 1231 cpuUsageCache: map[string]*cpuUsageRecord{ 1232 "1": { 1233 stats: &runtimeapi.CpuUsage{ 1234 Timestamp: 0, 1235 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{ 1236 Value: 67983588375722, 1237 }, 1238 }, 1239 }, 1240 }, 1241 expected: &value2, 1242 }, 1243 { 1244 desc: "should return nil if cpuacct is reset to 0 in a live container", 1245 stats: &runtimeapi.ContainerStats{ 1246 Attributes: &runtimeapi.ContainerAttributes{ 1247 Id: "1", 1248 }, 1249 Cpu: &runtimeapi.CpuUsage{ 1250 Timestamp: 2, 1251 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{ 1252 Value: 0, 1253 }, 1254 }, 1255 }, 1256 cpuUsageCache: map[string]*cpuUsageRecord{ 1257 "1": { 1258 stats: &runtimeapi.CpuUsage{ 1259 Timestamp: 1, 1260 UsageCoreNanoSeconds: &runtimeapi.UInt64Value{ 1261 Value: 10000000000, 1262 }, 1263 }, 1264 }, 1265 }, 1266 expected: nil, 1267 }, 1268 } 1269 for _, test := range tests { 1270 provider := &criStatsProvider{cpuUsageCache: test.cpuUsageCache} 1271 // Before the update, the cached value should be nil 1272 cached := provider.getContainerUsageNanoCores(test.stats) 1273 assert.Nil(t, cached) 1274 1275 // Update the cache and get the latest value. 1276 real := provider.getAndUpdateContainerUsageNanoCores(test.stats) 1277 assert.Equal(t, test.expected, real, test.desc) 1278 1279 // After the update, the cached value should be up-to-date 1280 cached = provider.getContainerUsageNanoCores(test.stats) 1281 assert.Equal(t, test.expected, cached, test.desc) 1282 } 1283 } 1284 1285 func TestExtractIDFromCgroupPath(t *testing.T) { 1286 tests := []struct { 1287 cgroupPath string 1288 expected string 1289 }{ 1290 { 1291 cgroupPath: "/kubepods/burstable/pod2fc932ce-fdcc-454b-97bd-aadfdeb4c340/9be25294016e2dc0340dd605ce1f57b492039b267a6a618a7ad2a7a58a740f32", 1292 expected: "9be25294016e2dc0340dd605ce1f57b492039b267a6a618a7ad2a7a58a740f32", 1293 }, 1294 { 1295 cgroupPath: "/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod2fc932ce_fdcc_454b_97bd_aadfdeb4c340.slice/cri-containerd-aaefb9d8feed2d453b543f6d928cede7a4dbefa6a0ae7c9b990dd234c56e93b9.scope", 1296 expected: "aaefb9d8feed2d453b543f6d928cede7a4dbefa6a0ae7c9b990dd234c56e93b9", 1297 }, 1298 { 1299 cgroupPath: "/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod2fc932ce_fdcc_454b_97bd_aadfdeb4c340.slice/cri-o-aaefb9d8feed2d453b543f6d928cede7a4dbefa6a0ae7c9b990dd234c56e93b9.scope", 1300 expected: "aaefb9d8feed2d453b543f6d928cede7a4dbefa6a0ae7c9b990dd234c56e93b9", 1301 }, 1302 } 1303 1304 for _, test := range tests { 1305 id := extractIDFromCgroupPath(test.cgroupPath) 1306 assert.Equal(t, test.expected, id) 1307 } 1308 } 1309 1310 func getCRIContainerStatsStrictlyFromCRI(seed int, containerName string) statsapi.ContainerStats { 1311 result := statsapi.ContainerStats{ 1312 Name: containerName, 1313 StartTime: metav1.NewTime(timestamp), 1314 CPU: &statsapi.CPUStats{}, 1315 Memory: &statsapi.MemoryStats{}, 1316 // UserDefinedMetrics is not supported by CRI. 1317 Rootfs: &statsapi.FsStats{}, 1318 } 1319 1320 result.CPU.Time = metav1.NewTime(timestamp) 1321 usageCoreNanoSeconds := uint64(seed + offsetCRI + offsetCPUUsageCoreSeconds) 1322 result.CPU.UsageCoreNanoSeconds = &usageCoreNanoSeconds 1323 1324 result.Memory.Time = metav1.NewTime(timestamp) 1325 workingSetBytes := uint64(seed + offsetCRI + offsetMemWorkingSetBytes) 1326 result.Memory.WorkingSetBytes = &workingSetBytes 1327 1328 result.Rootfs.Time = metav1.NewTime(timestamp) 1329 usedBytes := uint64(seed + offsetCRI + offsetFsUsage) 1330 result.Rootfs.UsedBytes = &usedBytes 1331 1332 inodesUsed := uint64(seed + offsetCRI + offsetFsInodeUsage) 1333 result.Rootfs.InodesUsed = &inodesUsed 1334 1335 return result 1336 }