Skip to content

Commit

Permalink
Memory cgroup is not available on some systems
Browse files Browse the repository at this point in the history
Signed-off-by: Maciej "Iwan" Iwanowski <[email protected]>
  • Loading branch information
iwankgb committed Mar 1, 2021
1 parent 950e389 commit b366b6e
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 18 deletions.
44 changes: 26 additions & 18 deletions manager/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ import (
var enableLoadReader = flag.Bool("enable_load_reader", false, "Whether to enable cpu load reader")
var HousekeepingInterval = flag.Duration("housekeeping_interval", 1*time.Second, "Interval between container housekeepings")

// TODO: replace regular expressions with something simpler, such as strings.Split().
// cgroup type chosen to fetch the cgroup path of a process.
// Memory has been chosen, as it is one of the default cgroups that is enabled for most containers.
var cgroupPathRegExp = regexp.MustCompile(`memory[^:]*:(.*?)[,;$]`)
// Memory has been chosen, as it is one of the default cgroups that is enabled for most containers...
var cgroupMemoryPathRegExp = regexp.MustCompile(`memory[^:]*:(.*?)[,;$]`)

// ... but there are systems (e.g. Raspberry Pi 4) where memory cgroup controller is disabled by default.
// We should check cpu cgroup then.
var cgroupCPUPathRegExp = regexp.MustCompile(`cpu[^:]*:(.*?)[,;$]`)

type containerInfo struct {
info.ContainerReference
Expand Down Expand Up @@ -195,20 +200,28 @@ func (cd *containerData) DerivedStats() (v2.DerivedStats, error) {
return cd.summaryReader.DerivedStats()
}

func (cd *containerData) getCgroupPath(cgroups string) (string, error) {
func (cd *containerData) getCgroupPath(cgroups string) string {
if cgroups == "-" {
return "/", nil
return "/"
}
if strings.HasPrefix(cgroups, "0::") {
return cgroups[3:], nil
return cgroups[3:]
}
matches := cgroupPathRegExp.FindSubmatch([]byte(cgroups))
matches := cgroupMemoryPathRegExp.FindSubmatch([]byte(cgroups))
if len(matches) != 2 {
klog.V(3).Infof("failed to get memory cgroup path from %q", cgroups)
// return root in case of failures - memory hierarchy might not be enabled.
return "/", nil
klog.V(3).Infof(
"failed to get memory cgroup path from %q, will try to get cpu cgroup path",
cgroups,
)
// On some systems (e.g. Raspberry PI 4) cgroup memory controlled is disabled by default.
matches = cgroupCPUPathRegExp.FindSubmatch([]byte(cgroups))
if len(matches) != 2 {
klog.V(3).Infof("failed to get cpu cgroup path from %q; assuming root cgroup", cgroups)
// return root in case of failures - memory hierarchy might not be enabled.
return "/"
}
}
return string(matches[1]), nil
return string(matches[1])
}

// Returns contents of a file inside the container root.
Expand Down Expand Up @@ -271,10 +284,7 @@ func (cd *containerData) getContainerPids(inHostNamespace bool) ([]string, error
return nil, fmt.Errorf("expected at least %d fields, found %d: output: %q", expectedFields, len(fields), line)
}
pid := fields[0]
cgroup, err := cd.getCgroupPath(fields[1])
if err != nil {
return nil, fmt.Errorf("could not parse cgroup path from %q: %v", fields[1], err)
}
cgroup := cd.getCgroupPath(fields[1])
if cd.info.Name == cgroup {
pids = append(pids, pid)
}
Expand Down Expand Up @@ -316,6 +326,7 @@ func (cd *containerData) parseProcessList(cadvisorContainer string, inHostNamesp
}
fdCount = len(fds)
processInfo.FdCount = fdCount

processes = append(processes, *processInfo)
}
return processes, nil
Expand Down Expand Up @@ -386,10 +397,7 @@ func (cd *containerData) parsePsLine(line, cadvisorContainer string, inHostNames
if err != nil {
return nil, fmt.Errorf("invalid psr %q: %v", lastTwoFields[0], err)
}
info.CgroupPath, err = cd.getCgroupPath(lastTwoFields[1])
if err != nil {
return nil, fmt.Errorf("could not parse cgroup path from %q: %v", lastTwoFields[1], err)
}
info.CgroupPath = cd.getCgroupPath(lastTwoFields[1])

// Remove the ps command we just ran from cadvisor container.
// Not necessary, but makes the cadvisor page look cleaner.
Expand Down
52 changes: 52 additions & 0 deletions manager/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,3 +505,55 @@ func TestParsePsLine(t *testing.T) {
})
}
}

var cgroupCases = []struct {
name string
cgroups string
path string
}{
{
name: "no cgroup",
cgroups: "-",
path: "/",
},
{
name: "random and meaningless string",
cgroups: "/this/is/a/path/to/some.file",
path: "/",
},
{
name: "0::-type cgroup",
cgroups: "0::/docker/some-cgroup",
path: "/docker/some-cgroup",
},
{
name: "memory cgroup",
cgroups: "4:memory:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6",
path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6",
},
{
name: "cpu,cpuacct cgroup",
cgroups: "4:cpu,cpuacct:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6",
path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6",
},
{
name: "cpu cgroup",
cgroups: "4:cpu:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6",
path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6",
},
{
name: "cpuacct cgroup",
cgroups: "4:cpuacct:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6",
path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6",
},
}

func TestGetCgroupPath(t *testing.T) {
for _, cgroup := range cgroupCases {
t.Run(cgroup.name, func(tt *testing.T) {
cd := &containerData{}
path := cd.getCgroupPath(cgroup.cgroups)
assert.Equal(t, cgroup.path, path)
})
}
}

0 comments on commit b366b6e

Please sign in to comment.