github.com/opencontainers/runtime-tools@v0.9.0/cgroups/cgroups.go (about) 1 package cgroups 2 3 import ( 4 "bufio" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 11 rspec "github.com/opencontainers/runtime-spec/specs-go" 12 ) 13 14 var ( 15 // AbsCgroupPath is absolute path for container's cgroup mount 16 AbsCgroupPath = "/cgrouptest" 17 // RelCgroupPath is relative path for container's cgroup mount 18 RelCgroupPath = "testdir/cgrouptest/container" 19 ) 20 21 // Cgroup represents interfaces for cgroup validation 22 type Cgroup interface { 23 GetBlockIOData(pid int, cgPath string) (*rspec.LinuxBlockIO, error) 24 GetCPUData(pid int, cgPath string) (*rspec.LinuxCPU, error) 25 GetDevicesData(pid int, cgPath string) ([]rspec.LinuxDeviceCgroup, error) 26 GetHugepageLimitData(pid int, cgPath string) ([]rspec.LinuxHugepageLimit, error) 27 GetMemoryData(pid int, cgPath string) (*rspec.LinuxMemory, error) 28 GetNetworkData(pid int, cgPath string) (*rspec.LinuxNetwork, error) 29 GetPidsData(pid int, cgPath string) (*rspec.LinuxPids, error) 30 } 31 32 // FindCgroup gets cgroup root mountpoint 33 func FindCgroup() (Cgroup, error) { 34 f, err := os.Open("/proc/self/mountinfo") 35 if err != nil { 36 return nil, err 37 } 38 defer f.Close() 39 40 cgroupv2 := false 41 scanner := bufio.NewScanner(f) 42 for scanner.Scan() { 43 text := scanner.Text() 44 fields := strings.Split(text, " ") 45 // Safe as mountinfo encodes mountpoints with spaces as \040. 46 index := strings.Index(text, " - ") 47 postSeparatorFields := strings.Split(text[index+3:], " ") 48 numPostFields := len(postSeparatorFields) 49 50 // This is an error as we can't detect if the mount is for "cgroup" 51 if numPostFields == 0 { 52 return nil, fmt.Errorf("Found no fields post '-' in %q", text) 53 } 54 55 if postSeparatorFields[0] == "cgroup" { 56 // No need to parse the rest of the postSeparatorFields 57 58 cg := &CgroupV1{ 59 MountPath: filepath.Dir(fields[4]), 60 } 61 return cg, nil 62 } else if postSeparatorFields[0] == "cgroup2" { 63 cgroupv2 = true 64 continue 65 //TODO cgroupv2 unimplemented 66 } 67 } 68 69 if err := scanner.Err(); err != nil { 70 return nil, err 71 } 72 73 if cgroupv2 { 74 return nil, fmt.Errorf("cgroupv2 is not supported yet") 75 } 76 return nil, fmt.Errorf("cgroup is not found") 77 } 78 79 // GetSubsystemPath gets path of subsystem 80 func GetSubsystemPath(pid int, subsystem string) (string, error) { 81 contents, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid)) 82 if err != nil { 83 return "", err 84 } 85 86 parts := strings.Split(strings.TrimSpace(string(contents)), "\n") 87 for _, part := range parts { 88 elem := strings.SplitN(part, ":", 3) 89 if len(elem) < 3 { 90 continue 91 } 92 subelems := strings.Split(elem[1], ",") 93 for _, subelem := range subelems { 94 if subelem == subsystem { 95 return elem[2], nil 96 } 97 } 98 } 99 100 return "", fmt.Errorf("subsystem %s not found", subsystem) 101 }