github.com/google/cadvisor@v0.49.1/container/common/fsHandler.go (about) 1 // Copyright 2015 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 Docker containers. 16 package common 17 18 import ( 19 "fmt" 20 "sync" 21 "time" 22 23 "github.com/google/cadvisor/fs" 24 25 "k8s.io/klog/v2" 26 ) 27 28 type FsHandler interface { 29 Start() 30 Usage() FsUsage 31 Stop() 32 } 33 34 type FsUsage struct { 35 BaseUsageBytes uint64 36 TotalUsageBytes uint64 37 InodeUsage uint64 38 } 39 40 type realFsHandler struct { 41 sync.RWMutex 42 lastUpdate time.Time 43 usage FsUsage 44 period time.Duration 45 minPeriod time.Duration 46 rootfs string 47 extraDir string 48 fsInfo fs.FsInfo 49 // Tells the container to stop. 50 stopChan chan struct{} 51 } 52 53 const ( 54 maxBackoffFactor = 20 55 ) 56 57 const DefaultPeriod = time.Minute 58 59 var _ FsHandler = &realFsHandler{} 60 61 func NewFsHandler(period time.Duration, rootfs, extraDir string, fsInfo fs.FsInfo) FsHandler { 62 return &realFsHandler{ 63 lastUpdate: time.Time{}, 64 usage: FsUsage{}, 65 period: period, 66 minPeriod: period, 67 rootfs: rootfs, 68 extraDir: extraDir, 69 fsInfo: fsInfo, 70 stopChan: make(chan struct{}, 1), 71 } 72 } 73 74 func (fh *realFsHandler) update() error { 75 var ( 76 rootUsage, extraUsage fs.UsageInfo 77 rootErr, extraErr error 78 ) 79 // TODO(vishh): Add support for external mounts. 80 if fh.rootfs != "" { 81 rootUsage, rootErr = fh.fsInfo.GetDirUsage(fh.rootfs) 82 } 83 84 if fh.extraDir != "" { 85 extraUsage, extraErr = fh.fsInfo.GetDirUsage(fh.extraDir) 86 } 87 88 // Wait to handle errors until after all operartions are run. 89 // An error in one will not cause an early return, skipping others 90 fh.Lock() 91 defer fh.Unlock() 92 fh.lastUpdate = time.Now() 93 if fh.rootfs != "" && rootErr == nil { 94 fh.usage.InodeUsage = rootUsage.Inodes 95 fh.usage.BaseUsageBytes = rootUsage.Bytes 96 fh.usage.TotalUsageBytes = rootUsage.Bytes 97 } 98 if fh.extraDir != "" && extraErr == nil { 99 if fh.rootfs != "" { 100 fh.usage.TotalUsageBytes += extraUsage.Bytes 101 } else { 102 // rootfs is empty, totalUsageBytes use extra usage bytes 103 fh.usage.TotalUsageBytes = extraUsage.Bytes 104 } 105 } 106 107 // Combine errors into a single error to return 108 if rootErr != nil || extraErr != nil { 109 return fmt.Errorf("rootDiskErr: %v, extraDiskErr: %v", rootErr, extraErr) 110 } 111 return nil 112 } 113 114 func (fh *realFsHandler) trackUsage() { 115 longOp := time.Second 116 for { 117 start := time.Now() 118 if err := fh.update(); err != nil { 119 klog.Errorf("failed to collect filesystem stats - %v", err) 120 fh.period = fh.period * 2 121 if fh.period > maxBackoffFactor*fh.minPeriod { 122 fh.period = maxBackoffFactor * fh.minPeriod 123 } 124 } else { 125 fh.period = fh.minPeriod 126 } 127 duration := time.Since(start) 128 if duration > longOp { 129 // adapt longOp time so that message doesn't continue to print 130 // if the long duration is persistent either because of slow 131 // disk or lots of containers. 132 longOp = longOp + time.Second 133 klog.V(2).Infof("fs: disk usage and inodes count on following dirs took %v: %v; will not log again for this container unless duration exceeds %v", duration, []string{fh.rootfs, fh.extraDir}, longOp) 134 } 135 select { 136 case <-fh.stopChan: 137 return 138 case <-time.After(fh.period): 139 } 140 } 141 } 142 143 func (fh *realFsHandler) Start() { 144 go fh.trackUsage() 145 } 146 147 func (fh *realFsHandler) Stop() { 148 close(fh.stopChan) 149 } 150 151 func (fh *realFsHandler) Usage() FsUsage { 152 fh.RLock() 153 defer fh.RUnlock() 154 return fh.usage 155 }