github.com/google/cadvisor@v0.49.1/container/raw/handler.go (about) 1 // Copyright 2014 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 "fmt" 20 21 "github.com/google/cadvisor/container" 22 "github.com/google/cadvisor/container/common" 23 "github.com/google/cadvisor/container/libcontainer" 24 "github.com/google/cadvisor/fs" 25 info "github.com/google/cadvisor/info/v1" 26 "github.com/google/cadvisor/machine" 27 "github.com/opencontainers/runc/libcontainer/cgroups" 28 29 "k8s.io/klog/v2" 30 ) 31 32 type rawContainerHandler struct { 33 // Name of the container for this handler. 34 name string 35 machineInfoFactory info.MachineInfoFactory 36 37 // Absolute path to the cgroup hierarchies of this container. 38 // (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test") 39 cgroupPaths map[string]string 40 41 fsInfo fs.FsInfo 42 externalMounts []common.Mount 43 includedMetrics container.MetricSet 44 45 libcontainerHandler *libcontainer.Handler 46 } 47 48 func isRootCgroup(name string) bool { 49 return name == "/" 50 } 51 52 func newRawContainerHandler(name string, cgroupSubsystems map[string]string, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, watcher *common.InotifyWatcher, rootFs string, includedMetrics container.MetricSet) (container.ContainerHandler, error) { 53 cHints, err := common.GetContainerHintsFromFile(*common.ArgContainerHints) 54 if err != nil { 55 return nil, err 56 } 57 58 cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems, name) 59 60 cgroupManager, err := libcontainer.NewCgroupManager(name, cgroupPaths) 61 if err != nil { 62 return nil, err 63 } 64 65 var externalMounts []common.Mount 66 for _, container := range cHints.AllHosts { 67 if name == container.FullName { 68 externalMounts = container.Mounts 69 break 70 } 71 } 72 73 pid := 0 74 if isRootCgroup(name) { 75 pid = 1 76 77 // delete pids from cgroup paths because /sys/fs/cgroup/pids/pids.current not exist 78 delete(cgroupPaths, "pids") 79 } 80 81 handler := libcontainer.NewHandler(cgroupManager, rootFs, pid, includedMetrics) 82 83 return &rawContainerHandler{ 84 name: name, 85 machineInfoFactory: machineInfoFactory, 86 cgroupPaths: cgroupPaths, 87 fsInfo: fsInfo, 88 externalMounts: externalMounts, 89 includedMetrics: includedMetrics, 90 libcontainerHandler: handler, 91 }, nil 92 } 93 94 func (h *rawContainerHandler) ContainerReference() (info.ContainerReference, error) { 95 // We only know the container by its one name. 96 return info.ContainerReference{ 97 Name: h.name, 98 }, nil 99 } 100 101 func (h *rawContainerHandler) GetRootNetworkDevices() ([]info.NetInfo, error) { 102 nd := []info.NetInfo{} 103 if isRootCgroup(h.name) { 104 mi, err := h.machineInfoFactory.GetMachineInfo() 105 if err != nil { 106 return nd, err 107 } 108 return mi.NetworkDevices, nil 109 } 110 return nd, nil 111 } 112 113 // Nothing to start up. 114 func (h *rawContainerHandler) Start() {} 115 116 // Nothing to clean up. 117 func (h *rawContainerHandler) Cleanup() {} 118 119 func (h *rawContainerHandler) GetSpec() (info.ContainerSpec, error) { 120 const hasNetwork = false 121 hasFilesystem := isRootCgroup(h.name) || len(h.externalMounts) > 0 122 spec, err := common.GetSpec(h.cgroupPaths, h.machineInfoFactory, hasNetwork, hasFilesystem) 123 if err != nil { 124 return spec, err 125 } 126 127 if isRootCgroup(h.name) { 128 // Check physical network devices for root container. 129 nd, err := h.GetRootNetworkDevices() 130 if err != nil { 131 return spec, err 132 } 133 spec.HasNetwork = spec.HasNetwork || len(nd) != 0 134 135 // Get memory and swap limits of the running machine 136 memLimit, err := machine.GetMachineMemoryCapacity() 137 if err != nil { 138 klog.Warningf("failed to obtain memory limit for machine container") 139 spec.HasMemory = false 140 } else { 141 spec.Memory.Limit = uint64(memLimit) 142 // Spec is marked to have memory only if the memory limit is set 143 spec.HasMemory = true 144 } 145 146 swapLimit, err := machine.GetMachineSwapCapacity() 147 if err != nil { 148 klog.Warningf("failed to obtain swap limit for machine container") 149 } else { 150 spec.Memory.SwapLimit = uint64(swapLimit) 151 } 152 } 153 154 return spec, nil 155 } 156 157 func fsToFsStats(fs *fs.Fs) info.FsStats { 158 inodes := uint64(0) 159 inodesFree := uint64(0) 160 hasInodes := fs.InodesFree != nil 161 if hasInodes { 162 inodes = *fs.Inodes 163 inodesFree = *fs.InodesFree 164 } 165 return info.FsStats{ 166 Device: fs.Device, 167 Type: fs.Type.String(), 168 Limit: fs.Capacity, 169 Usage: fs.Capacity - fs.Free, 170 HasInodes: hasInodes, 171 Inodes: inodes, 172 InodesFree: inodesFree, 173 Available: fs.Available, 174 ReadsCompleted: fs.DiskStats.ReadsCompleted, 175 ReadsMerged: fs.DiskStats.ReadsMerged, 176 SectorsRead: fs.DiskStats.SectorsRead, 177 ReadTime: fs.DiskStats.ReadTime, 178 WritesCompleted: fs.DiskStats.WritesCompleted, 179 WritesMerged: fs.DiskStats.WritesMerged, 180 SectorsWritten: fs.DiskStats.SectorsWritten, 181 WriteTime: fs.DiskStats.WriteTime, 182 IoInProgress: fs.DiskStats.IoInProgress, 183 IoTime: fs.DiskStats.IoTime, 184 WeightedIoTime: fs.DiskStats.WeightedIoTime, 185 } 186 } 187 188 func (h *rawContainerHandler) getFsStats(stats *info.ContainerStats) error { 189 var filesystems []fs.Fs 190 var err error 191 // Early exist if no disk metrics are to be collected. 192 if !h.includedMetrics.Has(container.DiskUsageMetrics) && !h.includedMetrics.Has(container.DiskIOMetrics) { 193 return nil 194 } 195 196 // Get Filesystem information only for the root cgroup. 197 if isRootCgroup(h.name) { 198 filesystems, err = h.fsInfo.GetGlobalFsInfo() 199 if err != nil { 200 return err 201 } 202 } else { 203 if len(h.externalMounts) > 0 { 204 mountSet := make(map[string]struct{}) 205 for _, mount := range h.externalMounts { 206 mountSet[mount.HostDir] = struct{}{} 207 } 208 filesystems, err = h.fsInfo.GetFsInfoForPath(mountSet) 209 if err != nil { 210 return err 211 } 212 } 213 } 214 215 if h.includedMetrics.Has(container.DiskUsageMetrics) { 216 for i := range filesystems { 217 fs := filesystems[i] 218 stats.Filesystem = append(stats.Filesystem, fsToFsStats(&fs)) 219 } 220 } 221 222 if h.includedMetrics.Has(container.DiskIOMetrics) { 223 common.AssignDeviceNamesToDiskStats(&fsNamer{fs: filesystems, factory: h.machineInfoFactory}, &stats.DiskIo) 224 225 } 226 return nil 227 } 228 229 func (h *rawContainerHandler) GetStats() (*info.ContainerStats, error) { 230 if *disableRootCgroupStats && isRootCgroup(h.name) { 231 return nil, nil 232 } 233 stats, err := h.libcontainerHandler.GetStats() 234 if err != nil { 235 return stats, err 236 } 237 238 // Get filesystem stats. 239 err = h.getFsStats(stats) 240 if err != nil { 241 return stats, err 242 } 243 244 return stats, nil 245 } 246 247 func (h *rawContainerHandler) GetCgroupPath(resource string) (string, error) { 248 var res string 249 if !cgroups.IsCgroup2UnifiedMode() { 250 res = resource 251 } 252 path, ok := h.cgroupPaths[res] 253 if !ok { 254 return "", fmt.Errorf("could not find path for resource %q for container %q", resource, h.name) 255 } 256 return path, nil 257 } 258 259 func (h *rawContainerHandler) GetContainerLabels() map[string]string { 260 return map[string]string{} 261 } 262 263 func (h *rawContainerHandler) GetContainerIPAddress() string { 264 // the IP address for the raw container corresponds to the system ip address. 265 return "127.0.0.1" 266 } 267 268 func (h *rawContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { 269 return common.ListContainers(h.name, h.cgroupPaths, listType) 270 } 271 272 func (h *rawContainerHandler) ListProcesses(listType container.ListType) ([]int, error) { 273 return h.libcontainerHandler.GetProcesses() 274 } 275 276 func (h *rawContainerHandler) Exists() bool { 277 return common.CgroupExists(h.cgroupPaths) 278 } 279 280 func (h *rawContainerHandler) Type() container.ContainerType { 281 return container.ContainerTypeRaw 282 } 283 284 type fsNamer struct { 285 fs []fs.Fs 286 factory info.MachineInfoFactory 287 info common.DeviceNamer 288 } 289 290 func (n *fsNamer) DeviceName(major, minor uint64) (string, bool) { 291 for _, info := range n.fs { 292 if uint64(info.Major) == major && uint64(info.Minor) == minor { 293 return info.Device, true 294 } 295 } 296 if n.info == nil { 297 mi, err := n.factory.GetMachineInfo() 298 if err != nil { 299 return "", false 300 } 301 n.info = (*common.MachineInfoNamer)(mi) 302 } 303 return n.info.DeviceName(major, minor) 304 }