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  }