handler.go 8.3 KB

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