github.com/google/cadvisor@v0.49.1/container/docker/fs.go (about) 1 // Copyright 2022 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 package docker 16 17 import ( 18 "fmt" 19 20 "k8s.io/klog/v2" 21 22 "github.com/google/cadvisor/container" 23 "github.com/google/cadvisor/container/common" 24 "github.com/google/cadvisor/devicemapper" 25 "github.com/google/cadvisor/fs" 26 info "github.com/google/cadvisor/info/v1" 27 "github.com/google/cadvisor/zfs" 28 ) 29 30 func FsStats( 31 stats *info.ContainerStats, 32 machineInfoFactory info.MachineInfoFactory, 33 metrics container.MetricSet, 34 storageDriver StorageDriver, 35 fsHandler common.FsHandler, 36 globalFsInfo fs.FsInfo, 37 poolName string, 38 rootfsStorageDir string, 39 zfsParent string, 40 ) error { 41 mi, err := machineInfoFactory.GetMachineInfo() 42 if err != nil { 43 return err 44 } 45 46 if metrics.Has(container.DiskIOMetrics) { 47 common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo) 48 } 49 50 if metrics.Has(container.DiskUsageMetrics) { 51 var device string 52 switch storageDriver { 53 case DevicemapperStorageDriver: 54 device = poolName 55 case AufsStorageDriver, OverlayStorageDriver, Overlay2StorageDriver, VfsStorageDriver: 56 deviceInfo, err := globalFsInfo.GetDirFsDevice(rootfsStorageDir) 57 if err != nil { 58 return fmt.Errorf("unable to determine device info for dir: %v: %v", rootfsStorageDir, err) 59 } 60 device = deviceInfo.Device 61 case ZfsStorageDriver: 62 device = zfsParent 63 default: 64 return nil 65 } 66 67 for _, fs := range mi.Filesystems { 68 if fs.Device == device { 69 usage := fsHandler.Usage() 70 fsStat := info.FsStats{ 71 Device: device, 72 Type: fs.Type, 73 Limit: fs.Capacity, 74 BaseUsage: usage.BaseUsageBytes, 75 Usage: usage.TotalUsageBytes, 76 Inodes: usage.InodeUsage, 77 } 78 fileSystems, err := globalFsInfo.GetGlobalFsInfo() 79 if err != nil { 80 return fmt.Errorf("unable to obtain diskstats for filesystem %s: %v", fsStat.Device, err) 81 } 82 addDiskStats(fileSystems, &fs, &fsStat) 83 stats.Filesystem = append(stats.Filesystem, fsStat) 84 break 85 } 86 } 87 } 88 89 return nil 90 } 91 92 func addDiskStats(fileSystems []fs.Fs, fsInfo *info.FsInfo, fsStats *info.FsStats) { 93 if fsInfo == nil { 94 return 95 } 96 97 for _, fileSys := range fileSystems { 98 if fsInfo.DeviceMajor == fileSys.DiskStats.Major && 99 fsInfo.DeviceMinor == fileSys.DiskStats.Minor { 100 fsStats.ReadsCompleted = fileSys.DiskStats.ReadsCompleted 101 fsStats.ReadsMerged = fileSys.DiskStats.ReadsMerged 102 fsStats.SectorsRead = fileSys.DiskStats.SectorsRead 103 fsStats.ReadTime = fileSys.DiskStats.ReadTime 104 fsStats.WritesCompleted = fileSys.DiskStats.WritesCompleted 105 fsStats.WritesMerged = fileSys.DiskStats.WritesMerged 106 fsStats.SectorsWritten = fileSys.DiskStats.SectorsWritten 107 fsStats.WriteTime = fileSys.DiskStats.WriteTime 108 fsStats.IoInProgress = fileSys.DiskStats.IoInProgress 109 fsStats.IoTime = fileSys.DiskStats.IoTime 110 fsStats.WeightedIoTime = fileSys.DiskStats.WeightedIoTime 111 break 112 } 113 } 114 } 115 116 // FsHandler is a composite FsHandler implementation the incorporates 117 // the common fs handler, a devicemapper ThinPoolWatcher, and a zfsWatcher 118 type FsHandler struct { 119 FsHandler common.FsHandler 120 121 // thinPoolWatcher is the devicemapper thin pool watcher 122 ThinPoolWatcher *devicemapper.ThinPoolWatcher 123 // deviceID is the id of the container's fs device 124 DeviceID string 125 126 // zfsWatcher is the zfs filesystem watcher 127 ZfsWatcher *zfs.ZfsWatcher 128 // zfsFilesystem is the docker zfs filesystem 129 ZfsFilesystem string 130 } 131 132 var _ common.FsHandler = &FsHandler{} 133 134 func (h *FsHandler) Start() { 135 h.FsHandler.Start() 136 } 137 138 func (h *FsHandler) Stop() { 139 h.FsHandler.Stop() 140 } 141 142 func (h *FsHandler) Usage() common.FsUsage { 143 usage := h.FsHandler.Usage() 144 145 // When devicemapper is the storage driver, the base usage of the container comes from the thin pool. 146 // We still need the result of the fsHandler for any extra storage associated with the container. 147 // To correctly factor in the thin pool usage, we should: 148 // * Usage the thin pool usage as the base usage 149 // * Calculate the overall usage by adding the overall usage from the fs handler to the thin pool usage 150 if h.ThinPoolWatcher != nil { 151 thinPoolUsage, err := h.ThinPoolWatcher.GetUsage(h.DeviceID) 152 if err != nil { 153 // TODO: ideally we should keep track of how many times we failed to get the usage for this 154 // device vs how many refreshes of the cache there have been, and display an error e.g. if we've 155 // had at least 1 refresh and we still can't find the device. 156 klog.V(5).Infof("unable to get fs usage from thin pool for device %s: %v", h.DeviceID, err) 157 } else { 158 usage.BaseUsageBytes = thinPoolUsage 159 usage.TotalUsageBytes += thinPoolUsage 160 } 161 } 162 163 if h.ZfsWatcher != nil { 164 zfsUsage, err := h.ZfsWatcher.GetUsage(h.ZfsFilesystem) 165 if err != nil { 166 klog.V(5).Infof("unable to get fs usage from zfs for filesystem %s: %v", h.ZfsFilesystem, err) 167 } else { 168 usage.BaseUsageBytes = zfsUsage 169 usage.TotalUsageBytes += zfsUsage 170 } 171 } 172 return usage 173 }