handler.go 8.5 KB

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