mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-09-26 23:19:11 +08:00
197 lines
4.3 KiB
Go
197 lines
4.3 KiB
Go
package cgroup
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const numberOfControllers = 5
|
|
|
|
// Controllers defines enabled controller of a cgroup
|
|
type Controllers struct {
|
|
CPU bool
|
|
CPUSet bool
|
|
CPUAcct bool
|
|
Memory bool
|
|
Pids bool
|
|
}
|
|
|
|
// Set changes the enabled status of a specific controller
|
|
func (c *Controllers) Set(ct string, value bool) {
|
|
switch ct {
|
|
case CPU:
|
|
c.CPU = value
|
|
case CPUSet:
|
|
c.CPUSet = value
|
|
case CPUAcct:
|
|
c.CPUAcct = value
|
|
case Memory:
|
|
c.Memory = value
|
|
case Pids:
|
|
c.Pids = value
|
|
}
|
|
}
|
|
|
|
// Intersect reset the specific controller if it is not enabled in the other
|
|
func (c *Controllers) Intersect(o *Controllers) {
|
|
c.CPU = c.CPU && o.CPU
|
|
c.CPUSet = c.CPUSet && o.CPUSet
|
|
c.CPUAcct = c.CPUAcct && o.CPUAcct
|
|
c.Memory = c.Memory && o.Memory
|
|
c.Pids = c.Pids && o.Pids
|
|
}
|
|
|
|
// Contains returns true if the current controller enabled all controllers in the other controller
|
|
func (c *Controllers) Contains(o *Controllers) bool {
|
|
return (c.CPU || !o.CPU) && (c.CPUSet || !o.CPUSet) && (c.CPUAcct || !o.CPUAcct) &&
|
|
(c.Memory || !o.Memory) && (c.Pids || !o.Pids)
|
|
}
|
|
|
|
// Names returns a list of string of all enabled container names
|
|
func (c *Controllers) Names() []string {
|
|
names := make([]string, 0, numberOfControllers)
|
|
for _, v := range []struct {
|
|
e bool
|
|
n string
|
|
}{
|
|
{c.CPU, CPU},
|
|
{c.CPUAcct, CPUAcct},
|
|
{c.CPUSet, CPUSet},
|
|
{c.Memory, Memory},
|
|
{c.Pids, Pids},
|
|
} {
|
|
if v.e {
|
|
names = append(names, v.n)
|
|
}
|
|
}
|
|
return names
|
|
}
|
|
|
|
func (c *Controllers) String() string {
|
|
return "[" + strings.Join(c.Names(), ", ") + "]"
|
|
}
|
|
|
|
// Info reads the cgroup mount info from /proc/cgroups
|
|
type Info struct {
|
|
Hierarchy int
|
|
NumCgroups int
|
|
Enabled bool
|
|
}
|
|
|
|
// GetCgroupV1Info read /proc/cgroups and return the result
|
|
func GetCgroupV1Info() (map[string]Info, error) {
|
|
f, err := os.Open(procCgroupsPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
|
|
rt := make(map[string]Info)
|
|
s := bufio.NewScanner(f)
|
|
for s.Scan() {
|
|
text := s.Text()
|
|
if text[0] == '#' {
|
|
continue
|
|
}
|
|
parts := strings.Fields(text)
|
|
if len(parts) < 4 {
|
|
continue
|
|
}
|
|
|
|
// format: subsys_name hierarchy num_cgroups enabled
|
|
name := parts[0]
|
|
hierarchy, err := strconv.Atoi(parts[1])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
numCgroups, err := strconv.Atoi(parts[2])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
enabled := parts[3] != "0"
|
|
rt[name] = Info{
|
|
Hierarchy: hierarchy,
|
|
NumCgroups: numCgroups,
|
|
Enabled: enabled,
|
|
}
|
|
}
|
|
if err := s.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return rt, nil
|
|
}
|
|
|
|
// GetCurrentCgroupPrefix returns the cgroup prefix of current process
|
|
func GetCurrentCgroupPrefix() (string, error) {
|
|
c, err := os.ReadFile(procSelfCgroup)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
firstLine, _, _ := strings.Cut(string(c), "\n")
|
|
f := strings.Split(firstLine, ":")
|
|
if len(f) < 3 {
|
|
return "", fmt.Errorf("invalid " + procSelfCgroup)
|
|
}
|
|
return f[2][1:], nil
|
|
}
|
|
|
|
// GetAvailableController returns available cgroup controller in the system
|
|
func GetAvailableController() (*Controllers, error) {
|
|
if DetectedCgroupType == TypeV1 {
|
|
return GetAvailableControllerV1()
|
|
}
|
|
return GetAvailableControllerV2()
|
|
}
|
|
|
|
// GetAvailableControllerWithPrefix returns available cgroup controller within the cgroup prefix
|
|
func GetAvailableControllerWithPrefix(prefix string) (*Controllers, error) {
|
|
if DetectedCgroupType == TypeV1 {
|
|
return GetAvailableControllerV1()
|
|
}
|
|
return getAvailableControllerV2(prefix)
|
|
}
|
|
|
|
// GetAvailableControllerV1 reads /proc/cgroups and get all available controller as set
|
|
func GetAvailableControllerV1() (*Controllers, error) {
|
|
info, err := GetCgroupV1Info()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rt := &Controllers{}
|
|
for k, v := range info {
|
|
if !v.Enabled {
|
|
continue
|
|
}
|
|
rt.Set(k, true)
|
|
}
|
|
return rt, nil
|
|
}
|
|
|
|
// GetAvailableControllerV2 reads /sys/fs/cgroup/cgroup.controllers to get all controller
|
|
func GetAvailableControllerV2() (*Controllers, error) {
|
|
return getAvailableControllerV2(".")
|
|
}
|
|
|
|
func getAvailableControllerV2(prefix string) (*Controllers, error) {
|
|
return getAvailableControllerV2path(filepath.Join(basePath, prefix, cgroupControllers))
|
|
}
|
|
|
|
func getAvailableControllerV2path(p string) (*Controllers, error) {
|
|
c, err := readFile(p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
m := &Controllers{}
|
|
f := strings.Fields(string(c))
|
|
for _, v := range f {
|
|
m.Set(v, true)
|
|
}
|
|
return m, nil
|
|
}
|