diff --git a/cgroups/cgroups.go b/cgroups/cgroups.go index 598454862..567e9a6c1 100644 --- a/cgroups/cgroups.go +++ b/cgroups/cgroups.go @@ -1,15 +1,11 @@ package cgroups import ( - "errors" + "fmt" "github.com/docker/libcontainer/devices" ) -var ( - ErrNotFound = errors.New("mountpoint not found") -) - type FreezerState string const ( @@ -18,6 +14,29 @@ const ( Thawed FreezerState = "THAWED" ) +type NotFoundError struct { + Subsystem string +} + +func (e *NotFoundError) Error() string { + return fmt.Sprintf("mountpoint for %s not found", e.Subsystem) +} + +func NewNotFoundError(sub string) error { + return &NotFoundError{ + Subsystem: sub, + } +} + +func IsNotFound(err error) bool { + if err == nil { + return false + } + + _, ok := err.(*NotFoundError) + return ok +} + type Cgroup struct { Name string `json:"name,omitempty"` Parent string `json:"parent,omitempty"` // name of parent cgroup or slice diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index e20cdbb92..443dbb698 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -76,7 +76,7 @@ func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) { path, err := d.path(sysname) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem - if err == cgroups.ErrNotFound { + if cgroups.IsNotFound(err) { continue } @@ -155,25 +155,45 @@ func (raw *data) parent(subsystem string) (string, error) { func (raw *data) Paths() (map[string]string, error) { paths := make(map[string]string) + for sysname := range subsystems { path, err := raw.path(sysname) if err != nil { + // Don't fail if a cgroup hierarchy was not found, just skip this subsystem + if cgroups.IsNotFound(err) { + continue + } + return nil, err } + paths[sysname] = path } + return paths, nil } func (raw *data) path(subsystem string) (string, error) { // If the cgroup name/path is absolute do not look relative to the cgroup of the init process. if filepath.IsAbs(raw.cgroup) { - return filepath.Join(raw.root, subsystem, raw.cgroup), nil + path := filepath.Join(raw.root, subsystem, raw.cgroup) + + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + return "", cgroups.NewNotFoundError(subsystem) + } + + return "", err + } + + return path, nil } + parent, err := raw.parent(subsystem) if err != nil { return "", err } + return filepath.Join(parent, raw.cgroup), nil } diff --git a/cgroups/fs/blkio.go b/cgroups/fs/blkio.go index 38b875772..f784d0115 100644 --- a/cgroups/fs/blkio.go +++ b/cgroups/fs/blkio.go @@ -16,9 +16,10 @@ type BlkioGroup struct { func (s *BlkioGroup) Set(d *data) error { // we just want to join this group even though we don't set anything - if _, err := d.join("blkio"); err != nil && err != cgroups.ErrNotFound { + if _, err := d.join("blkio"); err != nil && !cgroups.IsNotFound(err) { return err } + return nil } diff --git a/cgroups/fs/cpuacct.go b/cgroups/fs/cpuacct.go index 7761d4c28..853ab6bff 100644 --- a/cgroups/fs/cpuacct.go +++ b/cgroups/fs/cpuacct.go @@ -27,9 +27,10 @@ type CpuacctGroup struct { func (s *CpuacctGroup) Set(d *data) error { // we just want to join this group even though we don't set anything - if _, err := d.join("cpuacct"); err != nil && err != cgroups.ErrNotFound { + if _, err := d.join("cpuacct"); err != nil && !cgroups.IsNotFound(err) { return err } + return nil } diff --git a/cgroups/fs/freezer.go b/cgroups/fs/freezer.go index db2a41ca3..c6b677fa9 100644 --- a/cgroups/fs/freezer.go +++ b/cgroups/fs/freezer.go @@ -33,7 +33,7 @@ func (s *FreezerGroup) Set(d *data) error { time.Sleep(1 * time.Millisecond) } default: - if _, err := d.join("freezer"); err != nil && err != cgroups.ErrNotFound { + if _, err := d.join("freezer"); err != nil && !cgroups.IsNotFound(err) { return err } } diff --git a/cgroups/fs/perf_event.go b/cgroups/fs/perf_event.go index 5f45678ff..813274d8c 100644 --- a/cgroups/fs/perf_event.go +++ b/cgroups/fs/perf_event.go @@ -9,7 +9,7 @@ type PerfEventGroup struct { func (s *PerfEventGroup) Set(d *data) error { // we just want to join this group even though we don't set anything - if _, err := d.join("perf_event"); err != nil && err != cgroups.ErrNotFound { + if _, err := d.join("perf_event"); err != nil && !cgroups.IsNotFound(err) { return err } return nil diff --git a/cgroups/fs/utils_test.go b/cgroups/fs/utils_test.go index 6ea59bc50..63d743f06 100644 --- a/cgroups/fs/utils_test.go +++ b/cgroups/fs/utils_test.go @@ -5,8 +5,6 @@ import ( "os" "path/filepath" "testing" - - "github.com/docker/libcontainer/cgroups" ) const ( @@ -68,20 +66,3 @@ func TestGetCgroupParamsInt(t *testing.T) { t.Fatal("Expecting error, got none") } } - -func TestAbsolutePathHandling(t *testing.T) { - testCgroup := cgroups.Cgroup{ - Name: "bar", - Parent: "/foo", - } - cgroupData := data{ - root: "/sys/fs/cgroup", - cgroup: "/foo/bar", - c: &testCgroup, - pid: 1, - } - expectedPath := filepath.Join(cgroupData.root, "cpu", testCgroup.Parent, testCgroup.Name) - if path, err := cgroupData.path("cpu"); path != expectedPath || err != nil { - t.Fatalf("expected path %s but got %s %s", expectedPath, path, err) - } -} diff --git a/cgroups/systemd/apply_systemd.go b/cgroups/systemd/apply_systemd.go index 252fb60e4..7af4818e2 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -166,7 +166,7 @@ func (c *systemdCgroup) Paths() (map[string]string, error) { subsystemPath, err := getSubsystemPath(c.cgroup, sysname) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem - if err == cgroups.ErrNotFound { + if cgroups.IsNotFound(err) { continue } @@ -274,7 +274,7 @@ func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) { subsystemPath, err := getSubsystemPath(c, sysname) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem - if err == cgroups.ErrNotFound { + if cgroups.IsNotFound(err) { continue } diff --git a/cgroups/utils.go b/cgroups/utils.go index 6688ff71e..5516c5a22 100644 --- a/cgroups/utils.go +++ b/cgroups/utils.go @@ -29,7 +29,8 @@ func FindCgroupMountpoint(subsystem string) (string, error) { } } } - return "", ErrNotFound + + return "", NewNotFoundError(subsystem) } type Mount struct { @@ -153,19 +154,23 @@ func ReadProcsFile(dir string) ([]int, error) { func parseCgroupFile(subsystem string, r io.Reader) (string, error) { s := bufio.NewScanner(r) + for s.Scan() { if err := s.Err(); err != nil { return "", err } + text := s.Text() parts := strings.Split(text, ":") + for _, subs := range strings.Split(parts[1], ",") { if subs == subsystem { return parts[2], nil } } } - return "", ErrNotFound + + return "", NewNotFoundError(subsystem) } func pathExists(path string) bool {