github.com/criyle/go-sandbox@v0.10.3/pkg/cgroup/cgroup_info_linux.go (about) 1 package cgroup 2 3 import ( 4 "bufio" 5 "fmt" 6 "os" 7 "path" 8 "strconv" 9 "strings" 10 ) 11 12 const numberOfControllers = 5 13 14 // Controllers defines enabled controller of a cgroup 15 type Controllers struct { 16 CPU bool 17 CPUSet bool 18 CPUAcct bool 19 Memory bool 20 Pids bool 21 } 22 23 // Set changes the enabled status of a specific controller 24 func (c *Controllers) Set(ct string, value bool) { 25 switch ct { 26 case CPU: 27 c.CPU = value 28 case CPUSet: 29 c.CPUSet = value 30 case CPUAcct: 31 c.CPUAcct = value 32 case Memory: 33 c.Memory = value 34 case Pids: 35 c.Pids = value 36 } 37 } 38 39 // Intersect reset the specific controller if it is not enabled in the other 40 func (c *Controllers) Intersect(o *Controllers) { 41 c.CPU = c.CPU && o.CPU 42 c.CPUSet = c.CPUSet && o.CPUSet 43 c.CPUAcct = c.CPUAcct && o.CPUAcct 44 c.Memory = c.Memory && o.Memory 45 c.Pids = c.Pids && o.Pids 46 } 47 48 // Contains returns true if the current controller enabled all controllers in the other controller 49 func (c *Controllers) Contains(o *Controllers) bool { 50 return (c.CPU || !o.CPU) && (c.CPUSet || !o.CPUSet) && (c.CPUAcct || !o.CPUAcct) && 51 (c.Memory || !o.Memory) && (c.Pids || !o.Pids) 52 } 53 54 // Names returns a list of string of all enabled container names 55 func (c *Controllers) Names() []string { 56 names := make([]string, 0, numberOfControllers) 57 for _, v := range []struct { 58 e bool 59 n string 60 }{ 61 {c.CPU, CPU}, 62 {c.CPUAcct, CPUAcct}, 63 {c.CPUSet, CPUSet}, 64 {c.Memory, Memory}, 65 {c.Pids, Pids}, 66 } { 67 if v.e { 68 names = append(names, v.n) 69 } 70 } 71 return names 72 } 73 74 func (c *Controllers) String() string { 75 return "[" + strings.Join(c.Names(), ", ") + "]" 76 } 77 78 // Info reads the cgroup mount info from /proc/cgroups 79 type Info struct { 80 Hierarchy int 81 NumCgroups int 82 Enabled bool 83 } 84 85 // GetCgroupV1Info read /proc/cgroups and return the result 86 func GetCgroupV1Info() (map[string]Info, error) { 87 f, err := os.Open(procCgroupsPath) 88 if err != nil { 89 return nil, err 90 } 91 defer f.Close() 92 93 rt := make(map[string]Info) 94 s := bufio.NewScanner(f) 95 for s.Scan() { 96 text := s.Text() 97 if text[0] == '#' { 98 continue 99 } 100 parts := strings.Fields(text) 101 if len(parts) < 4 { 102 continue 103 } 104 105 // format: subsys_name hierarchy num_cgroups enabled 106 name := parts[0] 107 hierarchy, err := strconv.Atoi(parts[1]) 108 if err != nil { 109 return nil, err 110 } 111 numCgroups, err := strconv.Atoi(parts[2]) 112 if err != nil { 113 return nil, err 114 } 115 enabled := parts[3] != "0" 116 rt[name] = Info{ 117 Hierarchy: hierarchy, 118 NumCgroups: numCgroups, 119 Enabled: enabled, 120 } 121 } 122 if err := s.Err(); err != nil { 123 return nil, err 124 } 125 return rt, nil 126 } 127 128 // GetCurrentCgroupPrefix returns the cgroup prefix of current process 129 func GetCurrentCgroupPrefix() (string, error) { 130 c, err := os.ReadFile(procSelfCgroup) 131 if err != nil { 132 return "", err 133 } 134 firstLine, _, _ := strings.Cut(string(c), "\n") 135 f := strings.Split(firstLine, ":") 136 if len(f) < 3 { 137 return "", fmt.Errorf("invalid " + procSelfCgroup) 138 } 139 return f[2][1:], nil 140 } 141 142 // GetAvailableController returns available cgroup controller in the system 143 func GetAvailableController() (*Controllers, error) { 144 if DetectedCgroupType == TypeV1 { 145 return GetAvailableControllerV1() 146 } 147 return GetAvailableControllerV2() 148 } 149 150 // GetAvailableControllerWithPrefix returns available cgroup controller within the cgroup prefix 151 func GetAvailableControllerWithPrefix(prefix string) (*Controllers, error) { 152 if DetectedCgroupType == TypeV1 { 153 return GetAvailableControllerV1() 154 } 155 return getAvailableControllerV2(prefix) 156 } 157 158 // GetAvailableControllerV1 reads /proc/cgroups and get all available controller as set 159 func GetAvailableControllerV1() (*Controllers, error) { 160 info, err := GetCgroupV1Info() 161 if err != nil { 162 return nil, err 163 } 164 165 rt := &Controllers{} 166 for k, v := range info { 167 if !v.Enabled { 168 continue 169 } 170 rt.Set(k, true) 171 } 172 return rt, nil 173 } 174 175 // GetAvailableControllerV2 reads /sys/fs/cgroup/cgroup.controllers to get all controller 176 func GetAvailableControllerV2() (*Controllers, error) { 177 return getAvailableControllerV2(".") 178 } 179 180 func getAvailableControllerV2(prefix string) (*Controllers, error) { 181 return getAvailableControllerV2path(path.Join(basePath, prefix, cgroupControllers)) 182 } 183 184 func getAvailableControllerV2path(p string) (*Controllers, error) { 185 c, err := readFile(p) 186 if err != nil { 187 return nil, err 188 } 189 190 m := &Controllers{} 191 f := strings.Fields(string(c)) 192 for _, v := range f { 193 m.Set(v, true) 194 } 195 return m, nil 196 }