cgroup_manager_linux.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package cm
  14. import (
  15. "fmt"
  16. "path"
  17. libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups"
  18. cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
  19. libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs"
  20. )
  21. // CgroupSubsystems holds information about the mounted cgroup subsytems
  22. type CgroupSubsystems struct {
  23. // Cgroup subsystem mounts.
  24. // e.g.: "/sys/fs/cgroup/cpu" -> ["cpu", "cpuacct"]
  25. Mounts []libcontainercgroups.Mount
  26. // Cgroup subsystem to their mount location.
  27. // e.g.: "cpu" -> "/sys/fs/cgroup/cpu"
  28. MountPoints map[string]string
  29. }
  30. // cgroupManagerImpl implements the CgroupManager interface.
  31. // Its a stateless object which can be used to
  32. // update,create or delete any number of cgroups
  33. // It uses the Libcontainer raw fs cgroup manager for cgroup management.
  34. type cgroupManagerImpl struct {
  35. // subsystems holds information about all the
  36. // mounted cgroup subsytems on the node
  37. subsystems *CgroupSubsystems
  38. }
  39. // Make sure that cgroupManagerImpl implements the CgroupManager interface
  40. var _ CgroupManager = &cgroupManagerImpl{}
  41. // NewCgroupManager is a factory method that returns a CgroupManager
  42. func NewCgroupManager(cs *CgroupSubsystems) CgroupManager {
  43. return &cgroupManagerImpl{
  44. subsystems: cs,
  45. }
  46. }
  47. // Exists checks if all subsystem cgroups already exist
  48. func (m *cgroupManagerImpl) Exists(name string) bool {
  49. // Get map of all cgroup paths on the system for the particular cgroup
  50. cgroupPaths := make(map[string]string, len(m.subsystems.MountPoints))
  51. for key, val := range m.subsystems.MountPoints {
  52. cgroupPaths[key] = path.Join(val, name)
  53. }
  54. // If even one cgroup doesn't exist we go on to create it
  55. for _, path := range cgroupPaths {
  56. if !libcontainercgroups.PathExists(path) {
  57. return false
  58. }
  59. }
  60. return true
  61. }
  62. // Destroy destroys the specified cgroup
  63. func (m *cgroupManagerImpl) Destroy(cgroupConfig *CgroupConfig) error {
  64. //cgroup name
  65. name := cgroupConfig.Name
  66. // Get map of all cgroup paths on the system for the particular cgroup
  67. cgroupPaths := make(map[string]string, len(m.subsystems.MountPoints))
  68. for key, val := range m.subsystems.MountPoints {
  69. cgroupPaths[key] = path.Join(val, name)
  70. }
  71. // Initialize libcontainer's cgroup config
  72. libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{
  73. Name: path.Base(name),
  74. Parent: path.Dir(name),
  75. }
  76. fsCgroupManager := cgroupfs.Manager{
  77. Cgroups: libcontainerCgroupConfig,
  78. Paths: cgroupPaths,
  79. }
  80. // Delete cgroups using libcontainers Managers Destroy() method
  81. if err := fsCgroupManager.Destroy(); err != nil {
  82. return fmt.Errorf("Unable to destroy cgroup paths for cgroup %v : %v", name, err)
  83. }
  84. return nil
  85. }
  86. type subsystem interface {
  87. // Name returns the name of the subsystem.
  88. Name() string
  89. // Set the cgroup represented by cgroup.
  90. Set(path string, cgroup *libcontainerconfigs.Cgroup) error
  91. }
  92. // Cgroup subsystems we currently support
  93. var supportedSubsystems = []subsystem{
  94. &cgroupfs.MemoryGroup{},
  95. &cgroupfs.CpuGroup{},
  96. }
  97. // setSupportedSubsytems sets cgroup resource limits only on the supported
  98. // subsytems. ie. cpu and memory. We don't use libcontainer's cgroup/fs/Set()
  99. // method as it doesn't allow us to skip updates on the devices cgroup
  100. // Allowing or denying all devices by writing 'a' to devices.allow or devices.deny is
  101. // not possible once the device cgroups has children. Once the pod level cgroup are
  102. // created under the QOS level cgroup we cannot update the QOS level device cgroup.
  103. // We would like to skip setting any values on the device cgroup in this case
  104. // but this is not possible with libcontainers Set() method
  105. // See https://github.com/opencontainers/runc/issues/932
  106. func setSupportedSubsytems(cgroupConfig *libcontainerconfigs.Cgroup) error {
  107. for _, sys := range supportedSubsystems {
  108. if _, ok := cgroupConfig.Paths[sys.Name()]; !ok {
  109. return fmt.Errorf("Failed to find subsytem mount for subsytem")
  110. }
  111. if err := sys.Set(cgroupConfig.Paths[sys.Name()], cgroupConfig); err != nil {
  112. return fmt.Errorf("Failed to set config for supported subsystems : %v", err)
  113. }
  114. }
  115. return nil
  116. }
  117. // Update updates the cgroup with the specified Cgroup Configuration
  118. func (m *cgroupManagerImpl) Update(cgroupConfig *CgroupConfig) error {
  119. //cgroup name
  120. name := cgroupConfig.Name
  121. // Extract the cgroup resource parameters
  122. resourceConfig := cgroupConfig.ResourceParameters
  123. resources := &libcontainerconfigs.Resources{}
  124. if resourceConfig.Memory != nil {
  125. resources.Memory = *resourceConfig.Memory
  126. }
  127. if resourceConfig.CpuShares != nil {
  128. resources.CpuShares = *resourceConfig.CpuShares
  129. }
  130. if resourceConfig.CpuQuota != nil {
  131. resources.CpuQuota = *resourceConfig.CpuQuota
  132. }
  133. // Get map of all cgroup paths on the system for the particular cgroup
  134. cgroupPaths := make(map[string]string, len(m.subsystems.MountPoints))
  135. for key, val := range m.subsystems.MountPoints {
  136. cgroupPaths[key] = path.Join(val, name)
  137. }
  138. // Initialize libcontainer's cgroup config
  139. libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{
  140. Name: path.Base(name),
  141. Parent: path.Dir(name),
  142. Resources: resources,
  143. Paths: cgroupPaths,
  144. }
  145. if err := setSupportedSubsytems(libcontainerCgroupConfig); err != nil {
  146. return fmt.Errorf("Failed to set supported cgroup subsystems for cgroup %v: %v", name, err)
  147. }
  148. return nil
  149. }
  150. // Create creates the specified cgroup
  151. func (m *cgroupManagerImpl) Create(cgroupConfig *CgroupConfig) error {
  152. // get cgroup name
  153. name := cgroupConfig.Name
  154. // Initialize libcontainer's cgroup config
  155. libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{
  156. Name: path.Base(name),
  157. Parent: path.Dir(name),
  158. Resources: &libcontainerconfigs.Resources{},
  159. }
  160. // get the fscgroup Manager with the specified cgroup configuration
  161. fsCgroupManager := &cgroupfs.Manager{
  162. Cgroups: libcontainerCgroupConfig,
  163. }
  164. //Apply(0) is a hack to create the cgroup directories for each resource
  165. // subsystem. The function [cgroups.Manager.apply()] applies cgroup
  166. // configuration to the process with the specified pid.
  167. // It creates cgroup files for each subsytems and writes the pid
  168. // in the tasks file. We use the function to create all the required
  169. // cgroup files but not attach any "real" pid to the cgroup.
  170. if err := fsCgroupManager.Apply(-1); err != nil {
  171. return fmt.Errorf("Failed to apply cgroup config for %v: %v", name, err)
  172. }
  173. return nil
  174. }