Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate correct output on NumCPU() when using cgroups2 #9816

Merged
merged 34 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e4a1129
file parsing for Cgroup2
nickorlow Mar 30, 2023
221e85f
added version detecting
nickorlow Mar 31, 2023
3ae35a0
ran gofmt
nickorlow Mar 31, 2023
7f64726
declarations to assignments
nickorlow Mar 31, 2023
a080ea1
correct types
nickorlow Mar 31, 2023
f35dae9
added test boilerplate
nickorlow Apr 16, 2023
dad8086
added test boilerplate
nickorlow Apr 16, 2023
7c4ac85
more boilerplate
nickorlow Apr 16, 2023
165d057
added a thing
sridharnandigam Apr 16, 2023
405a5aa
add some e2e tests (unfinished) + fix findMountPoint bug
nickorlow Apr 24, 2023
aa9a876
typo
nickorlow Apr 24, 2023
3714c2c
move error check
nickorlow Apr 25, 2023
6d96e11
try to figure out testing flags
nickorlow Apr 26, 2023
475adf7
add files
nickorlow Apr 26, 2023
c5dad5e
removed e2e tests for cgroups2 and associated functions
nickorlow May 12, 2023
a8028a5
remove test report
nickorlow May 12, 2023
ad1fb03
remove linux tag
nickorlow May 12, 2023
fddf4e0
fix formatting
nickorlow Jun 1, 2023
a9f9793
update default value for period when not set
nickorlow Jul 16, 2023
8f86603
Merge branch 'main' of github.com:nickorlow/ingress-nginx
nickorlow Jul 16, 2023
3814e1f
write e2e tests for cgroups
nickorlow Jul 16, 2023
8621dfc
fix e2e tests for cgroups
nickorlow Jul 16, 2023
0f4d054
gofmt
nickorlow Jul 17, 2023
c23cc0c
Merge branch 'kubernetes:main' into main
nickorlow Jul 17, 2023
b270b4a
remove build flags and rename cgroups_linux.go
nickorlow Jul 17, 2023
3a64d74
Merge branch 'main' of github.com:nickorlow/ingress-nginx
nickorlow Jul 17, 2023
30dc629
remove junit
nickorlow Jul 17, 2023
be6f1d5
gofmt
nickorlow Jul 17, 2023
0a01f55
bump to rerun ci
nickorlow Feb 21, 2024
63fb4c6
bump to rerun ci
nickorlow Feb 21, 2024
9e79a36
Merge branch 'kubernetes:main' into main
nickorlow May 18, 2024
ac0f6fc
fix lint errors
nickorlow May 18, 2024
b2d67ff
fix tests
nickorlow May 20, 2024
e9f3717
fix v1 test
nickorlow May 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 85 additions & 8 deletions pkg/util/runtime/cpu_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,42 @@ import (
//
// https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
func NumCPU() int {
return NumCPUWithCustomPath("")
}

func NumCPUWithCustomPath(path string) int {
cpus := runtime.NumCPU()

cgroupPath, err := libcontainercgroups.FindCgroupMountpoint("", "cpu")
if err != nil {
return cpus
cgroupVersionCheckPath := path

if cgroupVersionCheckPath == "" {
cgroupVersionCheckPath = "/sys/fs/cgroup/"
}

cpuQuota := readCgroupFileToInt64(cgroupPath, "cpu.cfs_quota_us")
cpuPeriod := readCgroupFileToInt64(cgroupPath, "cpu.cfs_period_us")
cgroupVersion := GetCgroupVersion(cgroupVersionCheckPath)
cpuQuota := int64(-1)
cpuPeriod := int64(-1)

if cgroupVersion == 1 {
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 {
cgroupPath := "/sys/fs/cgroup/"
if path != "" {
cgroupPath = path
}
cpuQuota, cpuPeriod = readCgroup2FileToInt64Tuple(cgroupPath, "cpu.max")
}

if cpuQuota == -1 || cpuPeriod == -1 {
return cpus
Expand All @@ -53,16 +80,66 @@ func NumCPU() int {
return int(math.Ceil(float64(cpuQuota) / float64(cpuPeriod)))
}

func readCgroupFileToInt64(cgroupPath, cgroupFile string) int64 {
func GetCgroupVersion(cgroupPath string) int64 {
// /sys/fs/cgroup/cgroup.controllers will not exist with cgroupsv1
if _, err := os.Stat(filepath.Join(cgroupPath, "cgroup.controllers")); err == nil {
return 2
}

return 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(cgroupString)

if values[0] == "max" {
return -1, -1
}

cpuQuota, err := strconv.ParseInt(values[0], 10, 64)
if err != nil {
return -1, -1
}

if len(values) == 1 {
return cpuQuota, 100000
}

cpuPeriod, err := strconv.ParseInt(values[1], 10, 64)
if err != nil {
return -1, -1
}

return cpuQuota, cpuPeriod
}

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))
}
115 changes: 115 additions & 0 deletions test/e2e/cgroups/cgroups.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
Copyright 2020 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cgroups

import (
"log"
"os"
"path/filepath"

"github.com/onsi/ginkgo/v2"
"github.com/stretchr/testify/assert"

"k8s.io/ingress-nginx/test/e2e/framework"

"k8s.io/ingress-nginx/pkg/util/runtime"
)

var _ = framework.IngressNginxDescribeSerial("[CGroups] cgroups", func() {
f := framework.NewDefaultFramework("cgroups")

ginkgo.BeforeEach(func() {
f.NewEchoDeployment()
f.NewSlowEchoDeployment()
})

ginkgo.It("detects cgroups version v1", func() {
cgroupPath := "/testing/sys/fs/cgroup/"
if err := os.MkdirAll(cgroupPath, os.ModePerm); err != nil {
log.Fatal(err)
}

quotaFile, err := os.Create(filepath.Join(cgroupPath, "cpu.cfs_quota_us"))
if err != nil {
log.Fatal(err)
}

periodFile, err := os.Create(filepath.Join(cgroupPath, "cpu.cfs_period_us"))
if err != nil {
log.Fatal(err)
}

_, err = quotaFile.WriteString("4")
if err != nil {
log.Fatal(err)
}

err = quotaFile.Sync()
if err != nil {
log.Fatal(err)
}

_, err = periodFile.WriteString("2")
if err != nil {
log.Fatal(err)
}

err = periodFile.Sync()
if err != nil {
log.Fatal(err)
}

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() {
cgroupPath := "/testing/sys/fs/cgroup/"
if err := os.MkdirAll(cgroupPath, os.ModePerm); err != nil {
log.Fatal(err)
}

_, err := os.Create(filepath.Join(cgroupPath, "cgroup.controllers"))
if err != nil {
log.Fatal(err)
}

file, err := os.Create(filepath.Join(cgroupPath, "cpu.max"))
if err != nil {
log.Fatal(err)
}

_, err = file.WriteString("4 2")
if err != nil {
log.Fatal(err)
}

err = file.Sync()
if err != nil {
log.Fatal(err)
}

assert.Equal(ginkgo.GinkgoT(), runtime.GetCgroupVersion(cgroupPath), int64(2))
assert.Equal(ginkgo.GinkgoT(), runtime.NumCPUWithCustomPath(cgroupPath), 2)

os.Remove(filepath.Join(cgroupPath, "cpu.max"))
os.Remove(filepath.Join(cgroupPath, "cgroup.controllers"))
})
})
1 change: 1 addition & 0 deletions test/e2e/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
_ "k8s.io/ingress-nginx/test/e2e/admission"
_ "k8s.io/ingress-nginx/test/e2e/annotations"
_ "k8s.io/ingress-nginx/test/e2e/annotations/modsecurity"
_ "k8s.io/ingress-nginx/test/e2e/cgroups"
_ "k8s.io/ingress-nginx/test/e2e/dbg"
_ "k8s.io/ingress-nginx/test/e2e/defaultbackend"
_ "k8s.io/ingress-nginx/test/e2e/disableleaderelection"
Expand Down