k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/kubelet/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 "fmt" 22 "testing" 23 "time" 24 25 cadvisorapiv1 "github.com/google/cadvisor/info/v1" 26 cadvisorapiv2 "github.com/google/cadvisor/info/v2" 27 fuzz "github.com/google/gofuzz" 28 "github.com/stretchr/testify/assert" 29 "github.com/stretchr/testify/require" 30 "go.uber.org/mock/gomock" 31 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 "k8s.io/apimachinery/pkg/types" 34 statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" 35 cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing" 36 kubecontainertest "k8s.io/kubernetes/pkg/kubelet/container/testing" 37 kubepodtest "k8s.io/kubernetes/pkg/kubelet/pod/testing" 38 serverstats "k8s.io/kubernetes/pkg/kubelet/server/stats" 39 "k8s.io/kubernetes/pkg/volume" 40 ) 41 42 const ( 43 // Offsets from seed value in generated container stats. 44 offsetCPUUsageCores = iota 45 offsetCPUUsageCoreSeconds 46 offsetMemPageFaults 47 offsetMemMajorPageFaults 48 offsetMemUsageBytes 49 offsetMemRSSBytes 50 offsetMemWorkingSetBytes 51 offsetNetRxBytes 52 offsetNetRxErrors 53 offsetNetTxBytes 54 offsetNetTxErrors 55 offsetFsCapacity 56 offsetFsAvailable 57 offsetFsUsage 58 offsetFsInodes 59 offsetFsInodesFree 60 offsetFsTotalUsageBytes 61 offsetFsBaseUsageBytes 62 offsetFsInodeUsage 63 offsetAcceleratorDutyCycle 64 offsetMemSwapUsageBytes 65 ) 66 67 var ( 68 timestamp = time.Now() 69 creationTime = timestamp.Add(-5 * time.Minute) 70 ) 71 72 func TestGetCgroupStats(t *testing.T) { 73 const ( 74 cgroupName = "test-cgroup-name" 75 containerInfoSeed = 1000 76 updateStats = false 77 ) 78 79 mockCtrl := gomock.NewController(t) 80 defer mockCtrl.Finish() 81 82 var ( 83 mockCadvisor = cadvisortest.NewMockInterface(mockCtrl) 84 mockPodManager = new(kubepodtest.MockManager) 85 mockRuntimeCache = new(kubecontainertest.MockRuntimeCache) 86 87 assert = assert.New(t) 88 options = cadvisorapiv2.RequestOptions{IdType: cadvisorapiv2.TypeName, Count: 2, Recursive: false} 89 90 containerInfo = getTestContainerInfo(containerInfoSeed, "test-pod", "test-ns", "test-container") 91 containerInfoMap = map[string]cadvisorapiv2.ContainerInfo{cgroupName: containerInfo} 92 ) 93 94 mockCadvisor.EXPECT().ContainerInfoV2(cgroupName, options).Return(containerInfoMap, nil) 95 96 provider := newStatsProvider(mockCadvisor, mockPodManager, mockRuntimeCache, fakeContainerStatsProvider{}) 97 cs, ns, err := provider.GetCgroupStats(cgroupName, updateStats) 98 assert.NoError(err) 99 100 checkCPUStats(t, "", containerInfoSeed, cs.CPU) 101 checkMemoryStats(t, "", containerInfoSeed, containerInfo, cs.Memory) 102 checkNetworkStats(t, "", containerInfoSeed, ns) 103 checkSwapStats(t, "", containerInfoSeed, containerInfo, cs.Swap) 104 105 assert.Equal(cgroupName, cs.Name) 106 assert.Equal(metav1.NewTime(containerInfo.Spec.CreationTime), cs.StartTime) 107 } 108 109 func TestGetCgroupCPUAndMemoryStats(t *testing.T) { 110 const ( 111 cgroupName = "test-cgroup-name" 112 containerInfoSeed = 1000 113 updateStats = false 114 ) 115 116 mockCtrl := gomock.NewController(t) 117 defer mockCtrl.Finish() 118 119 var ( 120 mockCadvisor = cadvisortest.NewMockInterface(mockCtrl) 121 mockPodManager = new(kubepodtest.MockManager) 122 mockRuntimeCache = new(kubecontainertest.MockRuntimeCache) 123 124 assert = assert.New(t) 125 options = cadvisorapiv2.RequestOptions{IdType: cadvisorapiv2.TypeName, Count: 2, Recursive: false} 126 127 containerInfo = getTestContainerInfo(containerInfoSeed, "test-pod", "test-ns", "test-container") 128 containerInfoMap = map[string]cadvisorapiv2.ContainerInfo{cgroupName: containerInfo} 129 ) 130 131 mockCadvisor.EXPECT().ContainerInfoV2(cgroupName, options).Return(containerInfoMap, nil) 132 133 provider := newStatsProvider(mockCadvisor, mockPodManager, mockRuntimeCache, fakeContainerStatsProvider{}) 134 cs, err := provider.GetCgroupCPUAndMemoryStats(cgroupName, updateStats) 135 assert.NoError(err) 136 137 checkCPUStats(t, "", containerInfoSeed, cs.CPU) 138 checkMemoryStats(t, "", containerInfoSeed, containerInfo, cs.Memory) 139 140 assert.Equal(cgroupName, cs.Name) 141 assert.Equal(metav1.NewTime(containerInfo.Spec.CreationTime), cs.StartTime) 142 } 143 144 func TestRootFsStats(t *testing.T) { 145 const ( 146 rootFsInfoSeed = 1000 147 containerInfoSeed = 2000 148 ) 149 150 mockCtrl := gomock.NewController(t) 151 defer mockCtrl.Finish() 152 153 var ( 154 mockCadvisor = cadvisortest.NewMockInterface(mockCtrl) 155 mockPodManager = new(kubepodtest.MockManager) 156 mockRuntimeCache = new(kubecontainertest.MockRuntimeCache) 157 158 assert = assert.New(t) 159 options = cadvisorapiv2.RequestOptions{IdType: cadvisorapiv2.TypeName, Count: 2, Recursive: false} 160 161 rootFsInfo = getTestFsInfo(rootFsInfoSeed) 162 containerInfo = getTestContainerInfo(containerInfoSeed, "test-pod", "test-ns", "test-container") 163 containerInfoMap = map[string]cadvisorapiv2.ContainerInfo{"/": containerInfo} 164 ) 165 166 mockCadvisor.EXPECT().RootFsInfo().Return(rootFsInfo, nil) 167 mockCadvisor.EXPECT().ContainerInfoV2("/", options).Return(containerInfoMap, nil) 168 169 provider := newStatsProvider(mockCadvisor, mockPodManager, mockRuntimeCache, fakeContainerStatsProvider{}) 170 stats, err := provider.RootFsStats() 171 assert.NoError(err) 172 173 checkFsStats(t, "", rootFsInfoSeed, stats) 174 175 assert.Equal(metav1.NewTime(containerInfo.Stats[0].Timestamp), stats.Time) 176 assert.Equal(rootFsInfo.Usage, *stats.UsedBytes) 177 assert.Equal(*rootFsInfo.Inodes-*rootFsInfo.InodesFree, *stats.InodesUsed) 178 } 179 180 func TestHasDedicatedImageFs(t *testing.T) { 181 ctx := context.Background() 182 mockCtrl := gomock.NewController(t) 183 defer mockCtrl.Finish() 184 imageStatsExpected := &statsapi.FsStats{AvailableBytes: uint64Ptr(1)} 185 186 for desc, test := range map[string]struct { 187 rootfsDevice string 188 imagefsDevice string 189 dedicated bool 190 imageFsStats *statsapi.FsStats 191 containerFsStats *statsapi.FsStats 192 }{ 193 "dedicated device for image filesystem": { 194 rootfsDevice: "root/device", 195 imagefsDevice: "image/device", 196 dedicated: true, 197 imageFsStats: imageStatsExpected, 198 }, 199 "shared device for image filesystem": { 200 rootfsDevice: "share/device", 201 imagefsDevice: "share/device", 202 dedicated: false, 203 imageFsStats: imageStatsExpected, 204 containerFsStats: imageStatsExpected, 205 }, 206 "split filesystem for images": { 207 rootfsDevice: "root/device", 208 imagefsDevice: "root/device", 209 dedicated: true, 210 imageFsStats: &statsapi.FsStats{AvailableBytes: uint64Ptr(1)}, 211 containerFsStats: &statsapi.FsStats{AvailableBytes: uint64Ptr(2)}, 212 }, 213 } { 214 t.Logf("TestCase %q", desc) 215 var ( 216 mockCadvisor = cadvisortest.NewMockInterface(mockCtrl) 217 mockPodManager = new(kubepodtest.MockManager) 218 mockRuntimeCache = new(kubecontainertest.MockRuntimeCache) 219 ) 220 mockCadvisor.EXPECT().RootFsInfo().Return(cadvisorapiv2.FsInfo{Device: test.rootfsDevice}, nil) 221 provider := newStatsProvider(mockCadvisor, mockPodManager, mockRuntimeCache, fakeContainerStatsProvider{ 222 device: test.imagefsDevice, 223 imageFs: test.imageFsStats, 224 containerFs: test.containerFsStats, 225 }) 226 227 dedicated, err := provider.HasDedicatedImageFs(ctx) 228 assert.NoError(t, err) 229 assert.Equal(t, test.dedicated, dedicated) 230 } 231 } 232 233 func getTerminatedContainerInfo(seed int, podName string, podNamespace string, containerName string) cadvisorapiv2.ContainerInfo { 234 cinfo := getTestContainerInfo(seed, podName, podNamespace, containerName) 235 cinfo.Stats[0].Memory.RSS = 0 236 cinfo.Stats[0].CpuInst.Usage.Total = 0 237 cinfo.Stats[0].Network = &cadvisorapiv2.NetworkStats{ 238 Interfaces: []cadvisorapiv1.InterfaceStats{{ 239 Name: "eth0", 240 RxBytes: 0, 241 RxErrors: 0, 242 TxBytes: 0, 243 TxErrors: 0, 244 }, { 245 Name: "cbr0", 246 RxBytes: 0, 247 RxErrors: 0, 248 TxBytes: 0, 249 TxErrors: 0, 250 }}, 251 } 252 return cinfo 253 } 254 255 func getContainerInfoWithZeroCpuMem(seed int, podName string, podNamespace string, containerName string) cadvisorapiv2.ContainerInfo { 256 cinfo := getTestContainerInfo(seed, podName, podNamespace, containerName) 257 cinfo.Stats[0].Memory.RSS = 0 258 cinfo.Stats[0].CpuInst.Usage.Total = 0 259 return cinfo 260 } 261 262 func getTestContainerInfo(seed int, podName string, podNamespace string, containerName string) cadvisorapiv2.ContainerInfo { 263 labels := map[string]string{} 264 if podName != "" { 265 labels = map[string]string{ 266 "io.kubernetes.pod.name": podName, 267 "io.kubernetes.pod.uid": "UID" + podName, 268 "io.kubernetes.pod.namespace": podNamespace, 269 "io.kubernetes.container.name": containerName, 270 } 271 } 272 // by default, kernel will set memory.limit_in_bytes to 1 << 63 if not bounded 273 unlimitedMemory := uint64(1 << 63) 274 spec := cadvisorapiv2.ContainerSpec{ 275 CreationTime: testTime(creationTime, seed), 276 HasCpu: true, 277 HasMemory: true, 278 HasNetwork: true, 279 Labels: labels, 280 Memory: cadvisorapiv2.MemorySpec{ 281 Limit: unlimitedMemory, 282 SwapLimit: unlimitedMemory, 283 }, 284 CustomMetrics: generateCustomMetricSpec(), 285 } 286 287 totalUsageBytes := uint64(seed + offsetFsTotalUsageBytes) 288 baseUsageBytes := uint64(seed + offsetFsBaseUsageBytes) 289 inodeUsage := uint64(seed + offsetFsInodeUsage) 290 291 stats := cadvisorapiv2.ContainerStats{ 292 Timestamp: testTime(timestamp, seed), 293 Cpu: &cadvisorapiv1.CpuStats{}, 294 CpuInst: &cadvisorapiv2.CpuInstStats{}, 295 Memory: &cadvisorapiv1.MemoryStats{ 296 Usage: uint64(seed + offsetMemUsageBytes), 297 WorkingSet: uint64(seed + offsetMemWorkingSetBytes), 298 RSS: uint64(seed + offsetMemRSSBytes), 299 ContainerData: cadvisorapiv1.MemoryStatsMemoryData{ 300 Pgfault: uint64(seed + offsetMemPageFaults), 301 Pgmajfault: uint64(seed + offsetMemMajorPageFaults), 302 }, 303 Swap: uint64(seed + offsetMemSwapUsageBytes), 304 }, 305 Network: &cadvisorapiv2.NetworkStats{ 306 Interfaces: []cadvisorapiv1.InterfaceStats{{ 307 Name: "eth0", 308 RxBytes: uint64(seed + offsetNetRxBytes), 309 RxErrors: uint64(seed + offsetNetRxErrors), 310 TxBytes: uint64(seed + offsetNetTxBytes), 311 TxErrors: uint64(seed + offsetNetTxErrors), 312 }, { 313 Name: "cbr0", 314 RxBytes: 100, 315 RxErrors: 100, 316 TxBytes: 100, 317 TxErrors: 100, 318 }}, 319 }, 320 CustomMetrics: generateCustomMetrics(spec.CustomMetrics), 321 Filesystem: &cadvisorapiv2.FilesystemStats{ 322 TotalUsageBytes: &totalUsageBytes, 323 BaseUsageBytes: &baseUsageBytes, 324 InodeUsage: &inodeUsage, 325 }, 326 Accelerators: []cadvisorapiv1.AcceleratorStats{ 327 { 328 Make: "nvidia", 329 Model: "Tesla K80", 330 ID: "foobar", 331 MemoryTotal: uint64(seed + offsetMemUsageBytes), 332 MemoryUsed: uint64(seed + offsetMemUsageBytes), 333 DutyCycle: uint64(seed + offsetAcceleratorDutyCycle), 334 }, 335 }, 336 } 337 stats.Cpu.Usage.Total = uint64(seed + offsetCPUUsageCoreSeconds) 338 stats.CpuInst.Usage.Total = uint64(seed + offsetCPUUsageCores) 339 return cadvisorapiv2.ContainerInfo{ 340 Spec: spec, 341 Stats: []*cadvisorapiv2.ContainerStats{&stats}, 342 } 343 } 344 345 func getTestFsInfo(seed int) cadvisorapiv2.FsInfo { 346 var ( 347 inodes = uint64(seed + offsetFsInodes) 348 inodesFree = uint64(seed + offsetFsInodesFree) 349 ) 350 return cadvisorapiv2.FsInfo{ 351 Timestamp: time.Now(), 352 Device: "test-device", 353 Mountpoint: "test-mount-point", 354 Capacity: uint64(seed + offsetFsCapacity), 355 Available: uint64(seed + offsetFsAvailable), 356 Usage: uint64(seed + offsetFsUsage), 357 Inodes: &inodes, 358 InodesFree: &inodesFree, 359 } 360 } 361 362 func getPodVolumeStats(seed int, volumeName string) statsapi.VolumeStats { 363 availableBytes := uint64(seed + offsetFsAvailable) 364 capacityBytes := uint64(seed + offsetFsCapacity) 365 usedBytes := uint64(seed + offsetFsUsage) 366 inodes := uint64(seed + offsetFsInodes) 367 inodesFree := uint64(seed + offsetFsInodesFree) 368 inodesUsed := uint64(seed + offsetFsInodeUsage) 369 fsStats := statsapi.FsStats{ 370 Time: metav1.NewTime(time.Now()), 371 AvailableBytes: &availableBytes, 372 CapacityBytes: &capacityBytes, 373 UsedBytes: &usedBytes, 374 Inodes: &inodes, 375 InodesFree: &inodesFree, 376 InodesUsed: &inodesUsed, 377 } 378 return statsapi.VolumeStats{ 379 FsStats: fsStats, 380 Name: volumeName, 381 } 382 } 383 384 func generateCustomMetricSpec() []cadvisorapiv1.MetricSpec { 385 f := fuzz.New().NilChance(0).Funcs( 386 func(e *cadvisorapiv1.MetricSpec, c fuzz.Continue) { 387 c.Fuzz(&e.Name) 388 switch c.Intn(3) { 389 case 0: 390 e.Type = cadvisorapiv1.MetricGauge 391 case 1: 392 e.Type = cadvisorapiv1.MetricCumulative 393 case 2: 394 e.Type = cadvisorapiv1.MetricType("delta") 395 } 396 switch c.Intn(2) { 397 case 0: 398 e.Format = cadvisorapiv1.IntType 399 case 1: 400 e.Format = cadvisorapiv1.FloatType 401 } 402 c.Fuzz(&e.Units) 403 }) 404 var ret []cadvisorapiv1.MetricSpec 405 f.Fuzz(&ret) 406 return ret 407 } 408 409 func generateCustomMetrics(spec []cadvisorapiv1.MetricSpec) map[string][]cadvisorapiv1.MetricVal { 410 ret := map[string][]cadvisorapiv1.MetricVal{} 411 for _, metricSpec := range spec { 412 f := fuzz.New().NilChance(0).Funcs( 413 func(e *cadvisorapiv1.MetricVal, c fuzz.Continue) { 414 switch metricSpec.Format { 415 case cadvisorapiv1.IntType: 416 c.Fuzz(&e.IntValue) 417 case cadvisorapiv1.FloatType: 418 c.Fuzz(&e.FloatValue) 419 } 420 }) 421 422 var metrics []cadvisorapiv1.MetricVal 423 f.Fuzz(&metrics) 424 ret[metricSpec.Name] = metrics 425 } 426 return ret 427 } 428 429 func testTime(base time.Time, seed int) time.Time { 430 return base.Add(time.Duration(seed) * time.Second) 431 } 432 433 func checkNetworkStats(t *testing.T, label string, seed int, stats *statsapi.NetworkStats) { 434 assert.NotNil(t, stats) 435 assert.EqualValues(t, testTime(timestamp, seed).Unix(), stats.Time.Time.Unix(), label+".Net.Time") 436 assert.EqualValues(t, "eth0", stats.Name, "default interface name is not eth0") 437 assert.EqualValues(t, seed+offsetNetRxBytes, *stats.RxBytes, label+".Net.RxBytes") 438 assert.EqualValues(t, seed+offsetNetRxErrors, *stats.RxErrors, label+".Net.RxErrors") 439 assert.EqualValues(t, seed+offsetNetTxBytes, *stats.TxBytes, label+".Net.TxBytes") 440 assert.EqualValues(t, seed+offsetNetTxErrors, *stats.TxErrors, label+".Net.TxErrors") 441 442 assert.EqualValues(t, 2, len(stats.Interfaces), "network interfaces should contain 2 elements") 443 444 assert.EqualValues(t, "eth0", stats.Interfaces[0].Name, "default interface name is not eth0") 445 assert.EqualValues(t, seed+offsetNetRxBytes, *stats.Interfaces[0].RxBytes, label+".Net.TxErrors") 446 assert.EqualValues(t, seed+offsetNetRxErrors, *stats.Interfaces[0].RxErrors, label+".Net.TxErrors") 447 assert.EqualValues(t, seed+offsetNetTxBytes, *stats.Interfaces[0].TxBytes, label+".Net.TxErrors") 448 assert.EqualValues(t, seed+offsetNetTxErrors, *stats.Interfaces[0].TxErrors, label+".Net.TxErrors") 449 450 assert.EqualValues(t, "cbr0", stats.Interfaces[1].Name, "cbr0 interface name is not cbr0") 451 assert.EqualValues(t, 100, *stats.Interfaces[1].RxBytes, label+".Net.TxErrors") 452 assert.EqualValues(t, 100, *stats.Interfaces[1].RxErrors, label+".Net.TxErrors") 453 assert.EqualValues(t, 100, *stats.Interfaces[1].TxBytes, label+".Net.TxErrors") 454 assert.EqualValues(t, 100, *stats.Interfaces[1].TxErrors, label+".Net.TxErrors") 455 456 } 457 458 func checkCPUStats(t *testing.T, label string, seed int, stats *statsapi.CPUStats) { 459 require.NotNil(t, stats.Time, label+".CPU.Time") 460 require.NotNil(t, stats.UsageNanoCores, label+".CPU.UsageNanoCores") 461 require.NotNil(t, stats.UsageNanoCores, label+".CPU.UsageCoreSeconds") 462 assert.EqualValues(t, testTime(timestamp, seed).Unix(), stats.Time.Time.Unix(), label+".CPU.Time") 463 assert.EqualValues(t, seed+offsetCPUUsageCores, *stats.UsageNanoCores, label+".CPU.UsageCores") 464 assert.EqualValues(t, seed+offsetCPUUsageCoreSeconds, *stats.UsageCoreNanoSeconds, label+".CPU.UsageCoreSeconds") 465 } 466 467 func checkMemoryStats(t *testing.T, label string, seed int, info cadvisorapiv2.ContainerInfo, stats *statsapi.MemoryStats) { 468 assert.EqualValues(t, testTime(timestamp, seed).Unix(), stats.Time.Time.Unix(), label+".Mem.Time") 469 assert.EqualValues(t, seed+offsetMemUsageBytes, *stats.UsageBytes, label+".Mem.UsageBytes") 470 assert.EqualValues(t, seed+offsetMemWorkingSetBytes, *stats.WorkingSetBytes, label+".Mem.WorkingSetBytes") 471 assert.EqualValues(t, seed+offsetMemRSSBytes, *stats.RSSBytes, label+".Mem.RSSBytes") 472 assert.EqualValues(t, seed+offsetMemPageFaults, *stats.PageFaults, label+".Mem.PageFaults") 473 assert.EqualValues(t, seed+offsetMemMajorPageFaults, *stats.MajorPageFaults, label+".Mem.MajorPageFaults") 474 if !info.Spec.HasMemory || isMemoryUnlimited(info.Spec.Memory.Limit) { 475 assert.Nil(t, stats.AvailableBytes, label+".Mem.AvailableBytes") 476 } else { 477 expected := info.Spec.Memory.Limit - *stats.WorkingSetBytes 478 assert.EqualValues(t, expected, *stats.AvailableBytes, label+".Mem.AvailableBytes") 479 } 480 } 481 482 func checkSwapStats(t *testing.T, label string, seed int, info cadvisorapiv2.ContainerInfo, stats *statsapi.SwapStats) { 483 label += ".Swap" 484 485 assert.EqualValues(t, testTime(timestamp, seed).Unix(), stats.Time.Time.Unix(), label+".Time") 486 assert.EqualValues(t, seed+offsetMemSwapUsageBytes, *stats.SwapUsageBytes, label+".SwapUsageBytes") 487 488 if !info.Spec.HasMemory || isMemoryUnlimited(info.Spec.Memory.SwapLimit) { 489 assert.Nil(t, stats.SwapAvailableBytes, label+".SwapAvailableBytes") 490 } else { 491 expected := info.Spec.Memory.Limit - *stats.SwapUsageBytes 492 assert.EqualValues(t, expected, *stats.SwapAvailableBytes, label+".AvailableBytes") 493 } 494 } 495 496 func checkFsStats(t *testing.T, label string, seed int, stats *statsapi.FsStats) { 497 assert.EqualValues(t, seed+offsetFsCapacity, *stats.CapacityBytes, label+".CapacityBytes") 498 assert.EqualValues(t, seed+offsetFsAvailable, *stats.AvailableBytes, label+".AvailableBytes") 499 assert.EqualValues(t, seed+offsetFsInodes, *stats.Inodes, label+".Inodes") 500 assert.EqualValues(t, seed+offsetFsInodesFree, *stats.InodesFree, label+".InodesFree") 501 } 502 503 func checkEphemeralStats(t *testing.T, label string, containerSeeds []int, volumeSeeds []int, containerLogStats []*volume.Metrics, stats *statsapi.FsStats) { 504 var usedBytes, inodeUsage int 505 for _, cseed := range containerSeeds { 506 usedBytes += cseed + offsetFsBaseUsageBytes 507 inodeUsage += cseed + offsetFsInodeUsage 508 // If containerLogStats is nil, then the log stats calculated from cAdvisor 509 // information is used. Since it's Total - Base, and these values are 510 // set to the offset, we can use the calculated difference in the offset 511 // to account for this. 512 if containerLogStats == nil { 513 usedBytes += offsetFsTotalUsageBytes - offsetFsBaseUsageBytes 514 } 515 } 516 for _, vseed := range volumeSeeds { 517 usedBytes += vseed + offsetFsUsage 518 inodeUsage += vseed + offsetFsInodeUsage 519 } 520 for _, logStats := range containerLogStats { 521 usedBytes += int(logStats.Used.Value()) 522 inodeUsage += int(logStats.InodesUsed.Value()) 523 } 524 assert.EqualValues(t, usedBytes, int(*stats.UsedBytes), label+".UsedBytes") 525 assert.EqualValues(t, inodeUsage, int(*stats.InodesUsed), label+".InodesUsed") 526 } 527 528 type fakeResourceAnalyzer struct { 529 podVolumeStats serverstats.PodVolumeStats 530 } 531 532 func (o *fakeResourceAnalyzer) Start() {} 533 func (o *fakeResourceAnalyzer) Get(context.Context, bool) (*statsapi.Summary, error) { return nil, nil } 534 func (o *fakeResourceAnalyzer) GetCPUAndMemoryStats(context.Context) (*statsapi.Summary, error) { 535 return nil, nil 536 } 537 func (o *fakeResourceAnalyzer) GetPodVolumeStats(uid types.UID) (serverstats.PodVolumeStats, bool) { 538 return o.podVolumeStats, true 539 } 540 541 type fakeContainerStatsProvider struct { 542 device string 543 imageFs *statsapi.FsStats 544 containerFs *statsapi.FsStats 545 } 546 547 func (p fakeContainerStatsProvider) ListPodStats(context.Context) ([]statsapi.PodStats, error) { 548 return nil, fmt.Errorf("not implemented") 549 } 550 551 func (p fakeContainerStatsProvider) ListPodStatsAndUpdateCPUNanoCoreUsage(context.Context) ([]statsapi.PodStats, error) { 552 return nil, fmt.Errorf("not implemented") 553 } 554 555 func (p fakeContainerStatsProvider) ListPodCPUAndMemoryStats(context.Context) ([]statsapi.PodStats, error) { 556 return nil, fmt.Errorf("not implemented") 557 } 558 559 func (p fakeContainerStatsProvider) ImageFsStats(context.Context) (*statsapi.FsStats, *statsapi.FsStats, error) { 560 return p.imageFs, p.containerFs, nil 561 } 562 563 func (p fakeContainerStatsProvider) ImageFsDevice(context.Context) (string, error) { 564 return p.device, nil 565 }