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