diff --git a/pkg/util/runtime/cpu_linux.go b/pkg/util/runtime/cpu_linux.go index 9cb260c4ba..7db6090539 100644 --- a/pkg/util/runtime/cpu_linux.go +++ b/pkg/util/runtime/cpu_linux.go @@ -36,21 +36,41 @@ import ( // // https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt func NumCPU() int { + return NumCPUWithCustomPath("") +} + +func NumCPUWithCustomPath(path string) int { cpus := runtime.NumCPU() - cgroupVersion := GetCgroupVersion() + cgroupVersionCheckPath := path + + if cgroupVersionCheckPath == "" { + cgroupVersionCheckPath = "/sys/fs/cgroup/" + } + + cgroupVersion := GetCgroupVersion(cgroupVersionCheckPath) cpuQuota := int64(-1) cpuPeriod := int64(-1) if cgroupVersion == 1 { - cgroupPath, err := libcontainercgroups.FindCgroupMountpoint("", "cpu") - if err != nil { - return cpus + cgroupPath := "" + if path == "" { + cgroupPathRd, err := libcontainercgroups.FindCgroupMountpoint("", "cpu") + if err != nil { + return cpus + } + cgroupPath = cgroupPathRd + } else { + cgroupPath = path } cpuQuota = readCgroupFileToInt64(cgroupPath, "cpu.cfs_quota_us") cpuPeriod = readCgroupFileToInt64(cgroupPath, "cpu.cfs_period_us") } else if cgroupVersion == 2 { - cpuQuota, cpuPeriod = readCgroup2FileToInt64Tuple("cpu.max") + cgroupPath := "/sys/fs/cgroup/" + if path != "" { + cgroupPath = path + } + cpuQuota, cpuPeriod = readCgroup2FileToInt64Tuple(cgroupPath, "cpu.max") } if cpuQuota == -1 || cpuPeriod == -1 { @@ -60,26 +80,21 @@ func NumCPU() int { return int(math.Ceil(float64(cpuQuota) / float64(cpuPeriod))) } -func GetCgroupVersion() int64 { +func GetCgroupVersion(cgroupPath string) int64 { // /sys/fs/cgroup/cgroup.controllers will not exist with cgroupsv1 - if _, err := os.Stat("/sys/fs/cgroup/cgroup.controllers"); err == nil { + if _, err := os.Stat(filepath.Join(cgroupPath, "cgroup.controllers")); err == nil { return 2 } return 1 } -func readCgroup2FileToInt64Tuple(cgroupFile string) (quota, period int64) { - contents, err := os.ReadFile(filepath.Join(string(os.PathSeparator), "sys", "fs", "cgroup", cgroupFile)) - if err != nil { - return -1, -1 - } - +func readCgroup2StringToInt64Tuple(cgroupString string) (quota, period int64) { // file contents looks like: $MAX $PERIOD // $MAX can have value "max" indicating no limit // it is possible for $PERIOD to be unset - values := strings.Fields(string(contents)) + values := strings.Fields(cgroupString) if values[0] == "max" { return -1, -1 @@ -102,16 +117,29 @@ func readCgroup2FileToInt64Tuple(cgroupFile string) (quota, period int64) { return cpuQuota, cpuPeriod } -func readCgroupFileToInt64(cgroupPath, cgroupFile string) int64 { +func readCgroup2FileToInt64Tuple(cgroupPath, cgroupFile string) (quota, period int64) { contents, err := os.ReadFile(filepath.Join(cgroupPath, cgroupFile)) if err != nil { - return -1 + return -1, -1 } - strValue := strings.TrimSpace(string(contents)) + return readCgroup2StringToInt64Tuple(string(contents)) +} + +func readCgroupStringToInt64(contents string) int64 { + strValue := strings.TrimSpace(contents) if value, err := strconv.ParseInt(strValue, 10, 64); err == nil { return value } return -1 } + +func readCgroupFileToInt64(cgroupPath, cgroupFile string) int64 { + contents, err := os.ReadFile(filepath.Join(cgroupPath, cgroupFile)) + if err != nil { + return -1 + } + + return readCgroupStringToInt64(string(contents)) +} diff --git a/test/e2e/cgroups/cgroups.go b/test/e2e/cgroups/cgroups.go index e01f683e47..59c6f6bf6c 100644 --- a/test/e2e/cgroups/cgroups.go +++ b/test/e2e/cgroups/cgroups.go @@ -27,8 +27,6 @@ import ( "k8s.io/ingress-nginx/test/e2e/framework" "k8s.io/ingress-nginx/pkg/util/runtime" - - libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups" ) var _ = framework.IngressNginxDescribeSerial("[CGroups] cgroups", func() { @@ -40,10 +38,7 @@ var _ = framework.IngressNginxDescribeSerial("[CGroups] cgroups", func() { }) ginkgo.It("detects cgroups version v1", func() { - cgroupPath, err := libcontainercgroups.FindCgroupMountpoint("", "cpu") - if err != nil { - log.Fatal(err) - } + cgroupPath := "/testing/sys/fs/cgroup/" quotaFile, err := os.Create(filepath.Join(cgroupPath, "cpu.cfs_quota_us")) if err != nil { @@ -75,24 +70,25 @@ var _ = framework.IngressNginxDescribeSerial("[CGroups] cgroups", func() { log.Fatal(err) } - assert.Equal(ginkgo.GinkgoT(), runtime.GetCgroupVersion(), int64(1)) - assert.Equal(ginkgo.GinkgoT(), runtime.NumCPU(), 2) + assert.Equal(ginkgo.GinkgoT(), runtime.GetCgroupVersion(cgroupPath), int64(1)) + assert.Equal(ginkgo.GinkgoT(), runtime.NumCPUWithCustomPath(cgroupPath), 2) os.Remove(filepath.Join(cgroupPath, "cpu.cfs_quota_us")) os.Remove(filepath.Join(cgroupPath, "cpu.cfs_period_us")) }) ginkgo.It("detect cgroups version v2", func() { - if err := os.MkdirAll("/sys/fs/cgroup/", os.ModePerm); err != nil { + cgroupPath := "/testing/sys/fs/cgroup/" + if err := os.MkdirAll(cgroupPath, os.ModePerm); err != nil { log.Fatal(err) } - _, err := os.Create("/sys/fs/cgroup/cgroup.controllers") + _, err := os.Create(filepath.Join(cgroupPath, "cgroup.controllers")) if err != nil { log.Fatal(err) } - file, err := os.Create("/sys/fs/cgroup/cpu.max") + file, err := os.Create(filepath.Join(cgroupPath, "cpu.max")) if err != nil { log.Fatal(err) } @@ -107,10 +103,10 @@ var _ = framework.IngressNginxDescribeSerial("[CGroups] cgroups", func() { log.Fatal(err) } - assert.Equal(ginkgo.GinkgoT(), runtime.GetCgroupVersion(), int64(2)) - assert.Equal(ginkgo.GinkgoT(), runtime.NumCPU(), 2) + assert.Equal(ginkgo.GinkgoT(), runtime.GetCgroupVersion(cgroupPath), int64(2)) + assert.Equal(ginkgo.GinkgoT(), runtime.NumCPUWithCustomPath(cgroupPath), 2) - os.Remove("/sys/fs/cgroup/cpu.max") - os.Remove("/sys/fs/cgroup/cgroup.controllers") + os.Remove(filepath.Join(cgroupPath, "cpu.max")) + os.Remove(filepath.Join(cgroupPath, "cgroup.controllers")) }) })