github.com/google/cadvisor@v0.49.1/container/raw/handler_test.go (about) 1 // Copyright 2016 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Handler for "raw" containers. 16 package raw 17 18 import ( 19 "reflect" 20 "testing" 21 22 "github.com/stretchr/testify/assert" 23 24 "github.com/google/cadvisor/container" 25 "github.com/google/cadvisor/container/common" 26 "github.com/google/cadvisor/fs" 27 info "github.com/google/cadvisor/info/v1" 28 ) 29 30 func TestFsToFsStats(t *testing.T) { 31 inodes := uint64(100) 32 inodesFree := uint64(50) 33 testCases := map[string]struct { 34 fs *fs.Fs 35 expected info.FsStats 36 }{ 37 "has_inodes": { 38 fs: &fs.Fs{ 39 DeviceInfo: fs.DeviceInfo{Device: "123"}, 40 Type: fs.VFS, 41 Capacity: uint64(1024 * 1024), 42 Free: uint64(1024), 43 Available: uint64(1024), 44 Inodes: &inodes, 45 InodesFree: &inodesFree, 46 DiskStats: fs.DiskStats{ 47 ReadsCompleted: uint64(100), 48 ReadsMerged: uint64(100), 49 SectorsRead: uint64(100), 50 ReadTime: uint64(100), 51 WritesCompleted: uint64(100), 52 WritesMerged: uint64(100), 53 SectorsWritten: uint64(100), 54 WriteTime: uint64(100), 55 IoInProgress: uint64(100), 56 IoTime: uint64(100), 57 WeightedIoTime: uint64(100), 58 }, 59 }, 60 expected: info.FsStats{ 61 Device: "123", 62 Type: fs.VFS.String(), 63 Limit: uint64(1024 * 1024), 64 Usage: uint64(1024*1024) - uint64(1024), 65 HasInodes: true, 66 Inodes: inodes, 67 InodesFree: inodesFree, 68 Available: uint64(1024), 69 ReadsCompleted: uint64(100), 70 ReadsMerged: uint64(100), 71 SectorsRead: uint64(100), 72 ReadTime: uint64(100), 73 WritesCompleted: uint64(100), 74 WritesMerged: uint64(100), 75 SectorsWritten: uint64(100), 76 WriteTime: uint64(100), 77 IoInProgress: uint64(100), 78 IoTime: uint64(100), 79 WeightedIoTime: uint64(100), 80 }, 81 }, 82 "has_no_inodes": { 83 fs: &fs.Fs{ 84 DeviceInfo: fs.DeviceInfo{Device: "123"}, 85 Type: fs.DeviceMapper, 86 Capacity: uint64(1024 * 1024), 87 Free: uint64(1024), 88 Available: uint64(1024), 89 DiskStats: fs.DiskStats{ 90 ReadsCompleted: uint64(100), 91 ReadsMerged: uint64(100), 92 SectorsRead: uint64(100), 93 ReadTime: uint64(100), 94 WritesCompleted: uint64(100), 95 WritesMerged: uint64(100), 96 SectorsWritten: uint64(100), 97 WriteTime: uint64(100), 98 IoInProgress: uint64(100), 99 IoTime: uint64(100), 100 WeightedIoTime: uint64(100), 101 }, 102 }, 103 expected: info.FsStats{ 104 Device: "123", 105 Type: fs.DeviceMapper.String(), 106 Limit: uint64(1024 * 1024), 107 Usage: uint64(1024*1024) - uint64(1024), 108 HasInodes: false, 109 Available: uint64(1024), 110 ReadsCompleted: uint64(100), 111 ReadsMerged: uint64(100), 112 SectorsRead: uint64(100), 113 ReadTime: uint64(100), 114 WritesCompleted: uint64(100), 115 WritesMerged: uint64(100), 116 SectorsWritten: uint64(100), 117 WriteTime: uint64(100), 118 IoInProgress: uint64(100), 119 IoTime: uint64(100), 120 WeightedIoTime: uint64(100), 121 }, 122 }, 123 } 124 for testName, testCase := range testCases { 125 actual := fsToFsStats(testCase.fs) 126 if !reflect.DeepEqual(testCase.expected, actual) { 127 t.Errorf("test case=%v, expected=%v, actual=%v", testName, testCase.expected, actual) 128 } 129 } 130 } 131 132 func TestGetFsStats(t *testing.T) { 133 inodes := uint64(2000) 134 inodesFree := uint64(1000) 135 136 cases := map[string]struct { 137 name string 138 includedMetrics container.MetricSet 139 externalMounts []common.Mount 140 globalFsInfo func() ([]fs.Fs, error) 141 getFsInfoForPath func(mountSet map[string]struct{}) ([]fs.Fs, error) 142 diskIO info.DiskIoStats 143 expectedFilesystems []info.FsStats 144 expectedDiskIO info.DiskIoStats 145 }{ 146 "root with disk metrics enabled": { 147 name: "/", 148 includedMetrics: container.MetricSet{container.DiskUsageMetrics: struct{}{}, container.DiskIOMetrics: struct{}{}}, 149 externalMounts: []common.Mount{}, 150 globalFsInfo: func() ([]fs.Fs, error) { 151 return []fs.Fs{{ 152 DeviceInfo: fs.DeviceInfo{ 153 Device: "123", 154 Major: 1, 155 Minor: 2, 156 }, 157 Type: "devicemapper", 158 Capacity: 1000, 159 Free: 500, 160 Available: 450, 161 Inodes: &inodes, 162 InodesFree: &inodesFree, 163 DiskStats: fs.DiskStats{ 164 ReadsCompleted: 1, 165 ReadsMerged: 2, 166 SectorsRead: 3, 167 ReadTime: 3, 168 WritesCompleted: 4, 169 WritesMerged: 6, 170 SectorsWritten: 7, 171 WriteTime: 8, 172 IoInProgress: 9, 173 IoTime: 10, 174 WeightedIoTime: 11, 175 }, 176 }}, nil 177 }, 178 expectedFilesystems: []info.FsStats{ 179 { 180 Device: "123", 181 Type: "devicemapper", 182 Limit: 1000, 183 Usage: 500, 184 BaseUsage: 0, 185 Available: 450, 186 HasInodes: true, 187 Inodes: 2000, 188 InodesFree: 1000, 189 ReadsCompleted: 1, 190 ReadsMerged: 2, 191 SectorsRead: 3, 192 ReadTime: 3, 193 WritesCompleted: 4, 194 WritesMerged: 6, 195 SectorsWritten: 7, 196 WriteTime: 8, 197 IoInProgress: 9, 198 IoTime: 10, 199 WeightedIoTime: 11, 200 }, 201 }, 202 expectedDiskIO: info.DiskIoStats{ 203 IoServiceBytes: []info.PerDiskStats{ 204 { 205 Device: "123", 206 Major: 1, 207 Minor: 2, 208 Stats: map[string]uint64{"a": 1}, 209 }, 210 }, 211 }, 212 diskIO: info.DiskIoStats{ 213 IoServiceBytes: []info.PerDiskStats{ 214 { 215 Device: "", 216 Major: 1, 217 Minor: 2, 218 Stats: map[string]uint64{"a": 1}, 219 }, 220 }, 221 }, 222 }, 223 "root with disk usage metrics enabled": { 224 name: "/", 225 includedMetrics: container.MetricSet{container.DiskUsageMetrics: struct{}{}}, 226 externalMounts: []common.Mount{}, 227 globalFsInfo: func() ([]fs.Fs, error) { 228 return []fs.Fs{{ 229 DeviceInfo: fs.DeviceInfo{ 230 Device: "123", 231 Major: 1, 232 Minor: 2, 233 }, 234 Type: "devicemapper", 235 Capacity: 1000, 236 Free: 500, 237 Available: 450, 238 Inodes: &inodes, 239 InodesFree: &inodesFree, 240 DiskStats: fs.DiskStats{ 241 ReadsCompleted: 1, 242 ReadsMerged: 2, 243 SectorsRead: 3, 244 ReadTime: 3, 245 WritesCompleted: 4, 246 WritesMerged: 6, 247 SectorsWritten: 7, 248 WriteTime: 8, 249 IoInProgress: 9, 250 IoTime: 10, 251 WeightedIoTime: 11, 252 }, 253 }}, nil 254 }, 255 expectedFilesystems: []info.FsStats{ 256 { 257 Device: "123", 258 Type: "devicemapper", 259 Limit: 1000, 260 Usage: 500, 261 BaseUsage: 0, 262 Available: 450, 263 HasInodes: true, 264 Inodes: 2000, 265 InodesFree: 1000, 266 ReadsCompleted: 1, 267 ReadsMerged: 2, 268 SectorsRead: 3, 269 ReadTime: 3, 270 WritesCompleted: 4, 271 WritesMerged: 6, 272 SectorsWritten: 7, 273 WriteTime: 8, 274 IoInProgress: 9, 275 IoTime: 10, 276 WeightedIoTime: 11, 277 }, 278 }, 279 // DiskIoStats must not be enriched with device name. 280 // This is imperfect check but I can't find any other. 281 expectedDiskIO: info.DiskIoStats{ 282 IoServiceBytes: []info.PerDiskStats{ 283 { 284 Device: "", 285 Major: 1, 286 Minor: 2, 287 Stats: map[string]uint64{"a": 1}, 288 }, 289 }, 290 }, 291 diskIO: info.DiskIoStats{ 292 IoServiceBytes: []info.PerDiskStats{ 293 { 294 Device: "", 295 Major: 1, 296 Minor: 2, 297 Stats: map[string]uint64{"a": 1}, 298 }, 299 }, 300 }, 301 }, 302 "root with disk I/O metrics enabled": { 303 name: "/", 304 includedMetrics: container.MetricSet{container.DiskIOMetrics: struct{}{}}, 305 externalMounts: []common.Mount{}, 306 globalFsInfo: func() ([]fs.Fs, error) { 307 return []fs.Fs{{ 308 DeviceInfo: fs.DeviceInfo{ 309 Device: "123", 310 Major: 1, 311 Minor: 2, 312 }, 313 Type: "devicemapper", 314 Capacity: 1000, 315 Free: 500, 316 Available: 450, 317 Inodes: &inodes, 318 InodesFree: &inodesFree, 319 DiskStats: fs.DiskStats{ 320 ReadsCompleted: 1, 321 ReadsMerged: 2, 322 SectorsRead: 3, 323 ReadTime: 3, 324 WritesCompleted: 4, 325 WritesMerged: 6, 326 SectorsWritten: 7, 327 WriteTime: 8, 328 IoInProgress: 9, 329 IoTime: 10, 330 WeightedIoTime: 11, 331 }, 332 }}, nil 333 }, 334 expectedDiskIO: info.DiskIoStats{ 335 IoServiceBytes: []info.PerDiskStats{ 336 { 337 Device: "123", 338 Major: 1, 339 Minor: 2, 340 Stats: map[string]uint64{"a": 1}, 341 }, 342 }, 343 }, 344 diskIO: info.DiskIoStats{ 345 IoServiceBytes: []info.PerDiskStats{ 346 { 347 Device: "", 348 Major: 1, 349 Minor: 2, 350 Stats: map[string]uint64{"a": 1}, 351 }, 352 }, 353 }, 354 }, 355 "root with disk metrics disabled": { 356 name: "/", 357 includedMetrics: container.MetricSet{}, 358 externalMounts: []common.Mount{}, 359 // DiskIoStats must not be enriched with device name. 360 // This is imperfect check but I can't find any other. 361 expectedDiskIO: info.DiskIoStats{ 362 IoServiceBytes: []info.PerDiskStats{ 363 { 364 Device: "", 365 Major: 1, 366 Minor: 2, 367 Stats: map[string]uint64{"a": 1}, 368 }, 369 }, 370 }, 371 diskIO: info.DiskIoStats{ 372 IoServiceBytes: []info.PerDiskStats{ 373 { 374 Device: "", 375 Major: 1, 376 Minor: 2, 377 Stats: map[string]uint64{"a": 1}, 378 }, 379 }, 380 }, 381 }, 382 "random container with disk metrics enabled": { 383 name: "/random/container", 384 includedMetrics: container.MetricSet{container.DiskUsageMetrics: struct{}{}, container.DiskIOMetrics: struct{}{}}, 385 externalMounts: []common.Mount{ 386 {HostDir: "/", ContainerDir: "/"}, 387 {HostDir: "/random", ContainerDir: "/completely/random"}, 388 }, 389 getFsInfoForPath: func(mountSet map[string]struct{}) ([]fs.Fs, error) { 390 return []fs.Fs{ 391 { 392 DeviceInfo: fs.DeviceInfo{ 393 Device: "123", 394 Major: 1, 395 Minor: 2, 396 }, 397 Type: "devicemapper", 398 Capacity: 1000, 399 Free: 500, 400 Available: 450, 401 Inodes: &inodes, 402 InodesFree: &inodesFree, 403 DiskStats: fs.DiskStats{ 404 ReadsCompleted: 1, 405 ReadsMerged: 2, 406 SectorsRead: 3, 407 ReadTime: 3, 408 WritesCompleted: 4, 409 WritesMerged: 6, 410 SectorsWritten: 7, 411 WriteTime: 8, 412 IoInProgress: 9, 413 IoTime: 10, 414 WeightedIoTime: 11, 415 }, 416 }, 417 { 418 DeviceInfo: fs.DeviceInfo{ 419 Device: "246", 420 Major: 3, 421 Minor: 4, 422 }, 423 Type: "devicemapper", 424 Capacity: 2000, 425 Free: 1000, 426 Available: 900, 427 Inodes: &inodes, 428 InodesFree: &inodesFree, 429 DiskStats: fs.DiskStats{ 430 ReadsCompleted: 10, 431 ReadsMerged: 20, 432 SectorsRead: 25, 433 ReadTime: 30, 434 WritesCompleted: 40, 435 WritesMerged: 60, 436 SectorsWritten: 70, 437 WriteTime: 80, 438 IoInProgress: 90, 439 IoTime: 100, 440 WeightedIoTime: 110, 441 }, 442 }, 443 }, nil 444 }, 445 expectedFilesystems: []info.FsStats{ 446 { 447 Device: "123", 448 Type: "devicemapper", 449 Limit: 1000, 450 Usage: 500, 451 BaseUsage: 0, 452 Available: 450, 453 HasInodes: true, 454 Inodes: 2000, 455 InodesFree: 1000, 456 ReadsCompleted: 1, 457 ReadsMerged: 2, 458 SectorsRead: 3, 459 ReadTime: 3, 460 WritesCompleted: 4, 461 WritesMerged: 6, 462 SectorsWritten: 7, 463 WriteTime: 8, 464 IoInProgress: 9, 465 IoTime: 10, 466 WeightedIoTime: 11, 467 }, 468 { 469 Device: "246", 470 Type: "devicemapper", 471 Limit: 2000, 472 Usage: 1000, 473 BaseUsage: 0, 474 Available: 900, 475 HasInodes: true, 476 Inodes: 2000, 477 InodesFree: 1000, 478 ReadsCompleted: 10, 479 ReadsMerged: 20, 480 SectorsRead: 25, 481 ReadTime: 30, 482 WritesCompleted: 40, 483 WritesMerged: 60, 484 SectorsWritten: 70, 485 WriteTime: 80, 486 IoInProgress: 90, 487 IoTime: 100, 488 WeightedIoTime: 110, 489 }, 490 }, 491 expectedDiskIO: info.DiskIoStats{ 492 IoServiceBytes: []info.PerDiskStats{ 493 { 494 Device: "123", 495 Major: 1, 496 Minor: 2, 497 Stats: map[string]uint64{"a": 1}, 498 }, 499 { 500 Device: "246", 501 Major: 3, 502 Minor: 4, 503 Stats: map[string]uint64{"b": 2}, 504 }, 505 }, 506 }, 507 diskIO: info.DiskIoStats{ 508 IoServiceBytes: []info.PerDiskStats{ 509 { 510 Device: "", 511 Major: 1, 512 Minor: 2, 513 Stats: map[string]uint64{"a": 1}, 514 }, 515 { 516 Device: "", 517 Major: 3, 518 Minor: 4, 519 Stats: map[string]uint64{"b": 2}, 520 }, 521 }, 522 }, 523 }, 524 } 525 526 for name, c := range cases { 527 t.Run(name, func(t *testing.T) { 528 handler := rawContainerHandler{ 529 name: c.name, 530 includedMetrics: c.includedMetrics, 531 fsInfo: fsInfo{c.globalFsInfo, c.getFsInfoForPath}, 532 externalMounts: c.externalMounts, 533 machineInfoFactory: machineInfo{}, 534 } 535 stats := &info.ContainerStats{DiskIo: c.diskIO} 536 err := handler.getFsStats(stats) 537 538 assert.NoError(t, err) 539 assert.Len(t, stats.Filesystem, len(c.expectedFilesystems)) 540 assert.Equal(t, c.expectedFilesystems, stats.Filesystem) 541 assert.Equal(t, c.expectedDiskIO, stats.DiskIo) 542 }) 543 } 544 } 545 546 type fsInfo struct { 547 globalFsInfo func() ([]fs.Fs, error) 548 getFsInfoForPath func(mountSet map[string]struct{}) ([]fs.Fs, error) 549 } 550 551 func (f fsInfo) GetGlobalFsInfo() ([]fs.Fs, error) { 552 return f.globalFsInfo() 553 } 554 555 func (f fsInfo) GetFsInfoForPath(mountSet map[string]struct{}) ([]fs.Fs, error) { 556 return f.getFsInfoForPath(mountSet) 557 } 558 559 func (f fsInfo) GetDirUsage(_ string) (fs.UsageInfo, error) { 560 panic("unsupported") 561 } 562 563 func (f fsInfo) GetDeviceInfoByFsUUID(_ string) (*fs.DeviceInfo, error) { 564 panic("unsupported") 565 } 566 567 func (f fsInfo) GetDirFsDevice(_ string) (*fs.DeviceInfo, error) { 568 panic("unsupported") 569 } 570 571 func (f fsInfo) GetDeviceForLabel(_ string) (string, error) { 572 panic("unsupported") 573 } 574 575 func (f fsInfo) GetLabelsForDevice(_ string) ([]string, error) { 576 panic("unsupported") 577 } 578 579 func (f fsInfo) GetMountpointForDevice(_ string) (string, error) { 580 panic("unsupported") 581 } 582 583 type machineInfo struct{} 584 585 func (m machineInfo) GetMachineInfo() (*info.MachineInfo, error) { 586 return &info.MachineInfo{ 587 DiskMap: map[string]info.DiskInfo{ 588 "1:2": { 589 Name: "sda", 590 Size: 1234, 591 Scheduler: "none", 592 }, 593 "3:4": { 594 Name: "sdb", 595 Size: 5678, 596 Scheduler: "none", 597 }, 598 }, 599 }, nil 600 } 601 602 func (m machineInfo) GetVersionInfo() (*info.VersionInfo, error) { 603 panic("unsupported") 604 }