1// +build linux 2 3/* 4Copyright 2015 The Kubernetes Authors. 5 6Licensed under the Apache License, Version 2.0 (the "License"); 7you may not use this file except in compliance with the License. 8You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12Unless required by applicable law or agreed to in writing, software 13distributed under the License is distributed on an "AS IS" BASIS, 14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15See the License for the specific language governing permissions and 16limitations under the License. 17*/ 18 19package cadvisor 20 21import ( 22 "flag" 23 "fmt" 24 "net/http" 25 "os" 26 "path" 27 "time" 28 29 // Register supported container handlers. 30 _ "github.com/google/cadvisor/container/containerd/install" 31 _ "github.com/google/cadvisor/container/crio/install" 32 _ "github.com/google/cadvisor/container/systemd/install" 33 34 "github.com/google/cadvisor/cache/memory" 35 cadvisormetrics "github.com/google/cadvisor/container" 36 "github.com/google/cadvisor/events" 37 cadvisorapi "github.com/google/cadvisor/info/v1" 38 cadvisorapiv2 "github.com/google/cadvisor/info/v2" 39 "github.com/google/cadvisor/manager" 40 "github.com/google/cadvisor/utils/sysfs" 41 utilfeature "k8s.io/apiserver/pkg/util/feature" 42 "k8s.io/klog/v2" 43 kubefeatures "k8s.io/kubernetes/pkg/features" 44 "k8s.io/utils/pointer" 45) 46 47type cadvisorClient struct { 48 imageFsInfoProvider ImageFsInfoProvider 49 rootPath string 50 manager.Manager 51} 52 53var _ Interface = new(cadvisorClient) 54 55// TODO(vmarmol): Make configurable. 56// The amount of time for which to keep stats in memory. 57const statsCacheDuration = 2 * time.Minute 58const maxHousekeepingInterval = 15 * time.Second 59const defaultHousekeepingInterval = 10 * time.Second 60const allowDynamicHousekeeping = true 61 62func init() { 63 // Override cAdvisor flag defaults. 64 flagOverrides := map[string]string{ 65 // Override the default cAdvisor housekeeping interval. 66 "housekeeping_interval": defaultHousekeepingInterval.String(), 67 // Disable event storage by default. 68 "event_storage_event_limit": "default=0", 69 "event_storage_age_limit": "default=0", 70 } 71 for name, defaultValue := range flagOverrides { 72 if f := flag.Lookup(name); f != nil { 73 f.DefValue = defaultValue 74 f.Value.Set(defaultValue) 75 } else { 76 klog.ErrorS(nil, "Expected cAdvisor flag not found", "flag", name) 77 } 78 } 79} 80 81// New creates a new cAdvisor Interface for linux systems. 82func New(imageFsInfoProvider ImageFsInfoProvider, rootPath string, cgroupRoots []string, usingLegacyStats bool) (Interface, error) { 83 sysFs := sysfs.NewRealSysFs() 84 85 includedMetrics := cadvisormetrics.MetricSet{ 86 cadvisormetrics.CpuUsageMetrics: struct{}{}, 87 cadvisormetrics.MemoryUsageMetrics: struct{}{}, 88 cadvisormetrics.CpuLoadMetrics: struct{}{}, 89 cadvisormetrics.DiskIOMetrics: struct{}{}, 90 cadvisormetrics.NetworkUsageMetrics: struct{}{}, 91 cadvisormetrics.AppMetrics: struct{}{}, 92 cadvisormetrics.ProcessMetrics: struct{}{}, 93 } 94 95 // Only add the Accelerator metrics if the feature is inactive 96 if !utilfeature.DefaultFeatureGate.Enabled(kubefeatures.DisableAcceleratorUsageMetrics) { 97 includedMetrics[cadvisormetrics.AcceleratorUsageMetrics] = struct{}{} 98 } 99 100 if usingLegacyStats || utilfeature.DefaultFeatureGate.Enabled(kubefeatures.LocalStorageCapacityIsolation) { 101 includedMetrics[cadvisormetrics.DiskUsageMetrics] = struct{}{} 102 } 103 104 duration := maxHousekeepingInterval 105 housekeepingConfig := manager.HouskeepingConfig{ 106 Interval: &duration, 107 AllowDynamic: pointer.BoolPtr(allowDynamicHousekeeping), 108 } 109 110 // Create the cAdvisor container manager. 111 m, err := manager.New(memory.New(statsCacheDuration, nil), sysFs, housekeepingConfig, includedMetrics, http.DefaultClient, cgroupRoots, "") 112 if err != nil { 113 return nil, err 114 } 115 116 if _, err := os.Stat(rootPath); err != nil { 117 if os.IsNotExist(err) { 118 if err := os.MkdirAll(path.Clean(rootPath), 0750); err != nil { 119 return nil, fmt.Errorf("error creating root directory %q: %v", rootPath, err) 120 } 121 } else { 122 return nil, fmt.Errorf("failed to Stat %q: %v", rootPath, err) 123 } 124 } 125 126 return &cadvisorClient{ 127 imageFsInfoProvider: imageFsInfoProvider, 128 rootPath: rootPath, 129 Manager: m, 130 }, nil 131} 132 133func (cc *cadvisorClient) Start() error { 134 return cc.Manager.Start() 135} 136 137func (cc *cadvisorClient) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) { 138 return cc.GetContainerInfo(name, req) 139} 140 141func (cc *cadvisorClient) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) { 142 return cc.GetContainerInfoV2(name, options) 143} 144 145func (cc *cadvisorClient) VersionInfo() (*cadvisorapi.VersionInfo, error) { 146 return cc.GetVersionInfo() 147} 148 149func (cc *cadvisorClient) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) { 150 infos, err := cc.SubcontainersInfo(name, req) 151 if err != nil && len(infos) == 0 { 152 return nil, err 153 } 154 155 result := make(map[string]*cadvisorapi.ContainerInfo, len(infos)) 156 for _, info := range infos { 157 result[info.Name] = info 158 } 159 return result, err 160} 161 162func (cc *cadvisorClient) MachineInfo() (*cadvisorapi.MachineInfo, error) { 163 return cc.GetMachineInfo() 164} 165 166func (cc *cadvisorClient) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) { 167 label, err := cc.imageFsInfoProvider.ImageFsInfoLabel() 168 if err != nil { 169 return cadvisorapiv2.FsInfo{}, err 170 } 171 return cc.getFsInfo(label) 172} 173 174func (cc *cadvisorClient) RootFsInfo() (cadvisorapiv2.FsInfo, error) { 175 return cc.GetDirFsInfo(cc.rootPath) 176} 177 178func (cc *cadvisorClient) getFsInfo(label string) (cadvisorapiv2.FsInfo, error) { 179 res, err := cc.GetFsInfo(label) 180 if err != nil { 181 return cadvisorapiv2.FsInfo{}, err 182 } 183 if len(res) == 0 { 184 return cadvisorapiv2.FsInfo{}, fmt.Errorf("failed to find information for the filesystem labeled %q", label) 185 } 186 // TODO(vmarmol): Handle this better when a label has more than one image filesystem. 187 if len(res) > 1 { 188 klog.InfoS("More than one filesystem labeled. Only using the first one", "label", label, "fileSystem", res) 189 } 190 191 return res[0], nil 192} 193 194func (cc *cadvisorClient) WatchEvents(request *events.Request) (*events.EventChannel, error) { 195 return cc.WatchForEvents(request) 196} 197