handler.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. }
  67. handler := libcontainer.NewHandler(cgroupManager, rootFs, pid, includedMetrics)
  68. return &rawContainerHandler{
  69. name: name,
  70. machineInfoFactory: machineInfoFactory,
  71. cgroupPaths: cgroupPaths,
  72. fsInfo: fsInfo,
  73. externalMounts: externalMounts,
  74. includedMetrics: includedMetrics,
  75. libcontainerHandler: handler,
  76. }, nil
  77. }
  78. func (self *rawContainerHandler) ContainerReference() (info.ContainerReference, error) {
  79. // We only know the container by its one name.
  80. return info.ContainerReference{
  81. Name: self.name,
  82. }, nil
  83. }
  84. func (self *rawContainerHandler) GetRootNetworkDevices() ([]info.NetInfo, error) {
  85. nd := []info.NetInfo{}
  86. if isRootCgroup(self.name) {
  87. mi, err := self.machineInfoFactory.GetMachineInfo()
  88. if err != nil {
  89. return nd, err
  90. }
  91. return mi.NetworkDevices, nil
  92. }
  93. return nd, nil
  94. }
  95. // Nothing to start up.
  96. func (self *rawContainerHandler) Start() {}
  97. // Nothing to clean up.
  98. func (self *rawContainerHandler) Cleanup() {}
  99. func (self *rawContainerHandler) GetSpec() (info.ContainerSpec, error) {
  100. const hasNetwork = false
  101. hasFilesystem := isRootCgroup(self.name) || len(self.externalMounts) > 0
  102. spec, err := common.GetSpec(self.cgroupPaths, self.machineInfoFactory, hasNetwork, hasFilesystem)
  103. if err != nil {
  104. return spec, err
  105. }
  106. if isRootCgroup(self.name) {
  107. // Check physical network devices for root container.
  108. nd, err := self.GetRootNetworkDevices()
  109. if err != nil {
  110. return spec, err
  111. }
  112. spec.HasNetwork = spec.HasNetwork || len(nd) != 0
  113. // Get memory and swap limits of the running machine
  114. memLimit, err := machine.GetMachineMemoryCapacity()
  115. if err != nil {
  116. klog.Warningf("failed to obtain memory limit for machine container")
  117. spec.HasMemory = false
  118. } else {
  119. spec.Memory.Limit = uint64(memLimit)
  120. // Spec is marked to have memory only if the memory limit is set
  121. spec.HasMemory = true
  122. }
  123. swapLimit, err := machine.GetMachineSwapCapacity()
  124. if err != nil {
  125. klog.Warningf("failed to obtain swap limit for machine container")
  126. } else {
  127. spec.Memory.SwapLimit = uint64(swapLimit)
  128. }
  129. }
  130. return spec, nil
  131. }
  132. func fsToFsStats(fs *fs.Fs) info.FsStats {
  133. inodes := uint64(0)
  134. inodesFree := uint64(0)
  135. hasInodes := fs.InodesFree != nil
  136. if hasInodes {
  137. inodes = *fs.Inodes
  138. inodesFree = *fs.InodesFree
  139. }
  140. return info.FsStats{
  141. Device: fs.Device,
  142. Type: fs.Type.String(),
  143. Limit: fs.Capacity,
  144. Usage: fs.Capacity - fs.Free,
  145. HasInodes: hasInodes,
  146. Inodes: inodes,
  147. InodesFree: inodesFree,
  148. Available: fs.Available,
  149. ReadsCompleted: fs.DiskStats.ReadsCompleted,
  150. ReadsMerged: fs.DiskStats.ReadsMerged,
  151. SectorsRead: fs.DiskStats.SectorsRead,
  152. ReadTime: fs.DiskStats.ReadTime,
  153. WritesCompleted: fs.DiskStats.WritesCompleted,
  154. WritesMerged: fs.DiskStats.WritesMerged,
  155. SectorsWritten: fs.DiskStats.SectorsWritten,
  156. WriteTime: fs.DiskStats.WriteTime,
  157. IoInProgress: fs.DiskStats.IoInProgress,
  158. IoTime: fs.DiskStats.IoTime,
  159. WeightedIoTime: fs.DiskStats.WeightedIoTime,
  160. }
  161. }
  162. func (self *rawContainerHandler) getFsStats(stats *info.ContainerStats) error {
  163. var filesystems []fs.Fs
  164. var err error
  165. // Get Filesystem information only for the root cgroup.
  166. if isRootCgroup(self.name) {
  167. filesystems, err = self.fsInfo.GetGlobalFsInfo()
  168. if err != nil {
  169. return err
  170. }
  171. } else if self.includedMetrics.Has(container.DiskUsageMetrics) || self.includedMetrics.Has(container.DiskIOMetrics) {
  172. if len(self.externalMounts) > 0 {
  173. var mountSet map[string]struct{}
  174. mountSet = make(map[string]struct{})
  175. for _, mount := range self.externalMounts {
  176. mountSet[mount.HostDir] = struct{}{}
  177. }
  178. filesystems, err = self.fsInfo.GetFsInfoForPath(mountSet)
  179. if err != nil {
  180. return err
  181. }
  182. }
  183. }
  184. if isRootCgroup(self.name) || self.includedMetrics.Has(container.DiskUsageMetrics) {
  185. for i := range filesystems {
  186. fs := filesystems[i]
  187. stats.Filesystem = append(stats.Filesystem, fsToFsStats(&fs))
  188. }
  189. }
  190. if isRootCgroup(self.name) || self.includedMetrics.Has(container.DiskIOMetrics) {
  191. common.AssignDeviceNamesToDiskStats(&fsNamer{fs: filesystems, factory: self.machineInfoFactory}, &stats.DiskIo)
  192. }
  193. return nil
  194. }
  195. func (self *rawContainerHandler) GetStats() (*info.ContainerStats, error) {
  196. stats, err := self.libcontainerHandler.GetStats()
  197. if err != nil {
  198. return stats, err
  199. }
  200. // Get filesystem stats.
  201. err = self.getFsStats(stats)
  202. if err != nil {
  203. return stats, err
  204. }
  205. return stats, nil
  206. }
  207. func (self *rawContainerHandler) GetCgroupPath(resource string) (string, error) {
  208. path, ok := self.cgroupPaths[resource]
  209. if !ok {
  210. return "", fmt.Errorf("could not find path for resource %q for container %q\n", resource, self.name)
  211. }
  212. return path, nil
  213. }
  214. func (self *rawContainerHandler) GetContainerLabels() map[string]string {
  215. return map[string]string{}
  216. }
  217. func (self *rawContainerHandler) GetContainerIPAddress() string {
  218. // the IP address for the raw container corresponds to the system ip address.
  219. return "127.0.0.1"
  220. }
  221. func (self *rawContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
  222. return common.ListContainers(self.name, self.cgroupPaths, listType)
  223. }
  224. func (self *rawContainerHandler) ListProcesses(listType container.ListType) ([]int, error) {
  225. return self.libcontainerHandler.GetProcesses()
  226. }
  227. func (self *rawContainerHandler) Exists() bool {
  228. return common.CgroupExists(self.cgroupPaths)
  229. }
  230. func (self *rawContainerHandler) Type() container.ContainerType {
  231. return container.ContainerTypeRaw
  232. }
  233. type fsNamer struct {
  234. fs []fs.Fs
  235. factory info.MachineInfoFactory
  236. info common.DeviceNamer
  237. }
  238. func (n *fsNamer) DeviceName(major, minor uint64) (string, bool) {
  239. for _, info := range n.fs {
  240. if uint64(info.Major) == major && uint64(info.Minor) == minor {
  241. return info.Device, true
  242. }
  243. }
  244. if n.info == nil {
  245. mi, err := n.factory.GetMachineInfo()
  246. if err != nil {
  247. return "", false
  248. }
  249. n.info = (*common.MachineInfoNamer)(mi)
  250. }
  251. return n.info.DeviceName(major, minor)
  252. }