cgroups.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package cgroups
  2. import (
  3. "bufio"
  4. "fmt"
  5. "github.com/dotcloud/docker/mount"
  6. "io"
  7. "io/ioutil"
  8. "os"
  9. "path/filepath"
  10. "strconv"
  11. "strings"
  12. )
  13. // https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt
  14. func FindCgroupMountpoint(subsystem string) (string, error) {
  15. mounts, err := mount.GetMounts()
  16. if err != nil {
  17. return "", err
  18. }
  19. for _, mount := range mounts {
  20. if mount.Fstype == "cgroup" {
  21. for _, opt := range strings.Split(mount.VfsOpts, ",") {
  22. if opt == subsystem {
  23. return mount.Mountpoint, nil
  24. }
  25. }
  26. }
  27. }
  28. return "", fmt.Errorf("cgroup mountpoint not found for %s", subsystem)
  29. }
  30. // Returns the relative path to the cgroup docker is running in.
  31. func getThisCgroupDir(subsystem string) (string, error) {
  32. f, err := os.Open("/proc/self/cgroup")
  33. if err != nil {
  34. return "", err
  35. }
  36. defer f.Close()
  37. return parseCgroupFile(subsystem, f)
  38. }
  39. func parseCgroupFile(subsystem string, r io.Reader) (string, error) {
  40. s := bufio.NewScanner(r)
  41. for s.Scan() {
  42. if err := s.Err(); err != nil {
  43. return "", err
  44. }
  45. text := s.Text()
  46. parts := strings.Split(text, ":")
  47. if parts[1] == subsystem {
  48. return parts[2], nil
  49. }
  50. }
  51. return "", fmt.Errorf("cgroup '%s' not found in /proc/self/cgroup", subsystem)
  52. }
  53. // Returns a list of pids for the given container.
  54. func GetPidsForContainer(id string) ([]int, error) {
  55. pids := []int{}
  56. // memory is chosen randomly, any cgroup used by docker works
  57. subsystem := "memory"
  58. cgroupRoot, err := FindCgroupMountpoint(subsystem)
  59. if err != nil {
  60. return pids, err
  61. }
  62. cgroupDir, err := getThisCgroupDir(subsystem)
  63. if err != nil {
  64. return pids, err
  65. }
  66. filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
  67. if _, err := os.Stat(filename); os.IsNotExist(err) {
  68. // With more recent lxc versions use, cgroup will be in lxc/
  69. filename = filepath.Join(cgroupRoot, cgroupDir, "lxc", id, "tasks")
  70. }
  71. output, err := ioutil.ReadFile(filename)
  72. if err != nil {
  73. return pids, err
  74. }
  75. for _, p := range strings.Split(string(output), "\n") {
  76. if len(p) == 0 {
  77. continue
  78. }
  79. pid, err := strconv.Atoi(p)
  80. if err != nil {
  81. return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
  82. }
  83. pids = append(pids, pid)
  84. }
  85. return pids, nil
  86. }