Skip to content

Commit be61414

Browse files
committed
Ensure cgroup v2 cpu controller is enabled
1 parent 8ec9e80 commit be61414

File tree

2 files changed

+132
-9
lines changed

2 files changed

+132
-9
lines changed

components/ws-daemon/pkg/cpulimit/dispatch.go

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212
"sync"
1313
"time"
1414

15-
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
16-
"github.com/opencontainers/runc/libcontainer/configs"
1715
"github.com/prometheus/client_golang/prometheus"
1816
"github.com/sirupsen/logrus"
1917
"golang.org/x/xerrors"
@@ -234,7 +232,7 @@ func newCFSController(basePath, cgroupPath string) (CFSController, error) {
234232

235233
if err == nil {
236234
fullPath := filepath.Join(basePath, cgroupPath)
237-
if err := ensureControllerEnabled(fullPath, "cpu"); err != nil {
235+
if err := ensureControllerEnabled(basePath, cgroupPath, "cpu"); err != nil {
238236
return nil, err
239237
}
240238

@@ -244,19 +242,59 @@ func newCFSController(basePath, cgroupPath string) (CFSController, error) {
244242
return nil, err
245243
}
246244

247-
func ensureControllerEnabled(targetPath, controller string) error {
248-
controllerFile := filepath.Join(targetPath, "cgroup.controllers")
249-
controllers, err := os.ReadFile(controllerFile)
245+
func ensureControllerEnabled(basePath, cgroupPath, controller string) error {
246+
targetPath := filepath.Join(basePath, cgroupPath)
247+
if enabled, err := isCpuControllerEnabled(targetPath); err != nil || enabled {
248+
return err
249+
}
250+
251+
err := writeCpuController(basePath)
250252
if err != nil {
251253
return err
252254
}
253255

256+
levelPath := basePath
257+
cgroupPath = strings.TrimPrefix(cgroupPath, "/")
258+
levels := strings.Split(cgroupPath, string(os.PathSeparator))
259+
for _, l := range levels[:len(levels)-1] {
260+
levelPath = filepath.Join(levelPath, l)
261+
err = writeCpuController(levelPath)
262+
if err != nil {
263+
return err
264+
}
265+
}
266+
267+
return nil
268+
}
269+
270+
func isCpuControllerEnabled(path string) (bool, error) {
271+
controllerFile := filepath.Join(path, "cgroup.controllers")
272+
controllers, err := os.ReadFile(controllerFile)
273+
if err != nil {
274+
return false, err
275+
}
276+
254277
for _, ctrl := range strings.Fields(string(controllers)) {
255-
if ctrl == controller {
278+
if ctrl == "cpu" {
256279
// controller is already activated
257-
return nil
280+
return true, nil
258281
}
259282
}
260283

261-
return fs2.CreateCgroupPath(targetPath, &configs.Cgroup{})
284+
return false, nil
285+
}
286+
287+
func writeCpuController(path string) error {
288+
f, err := os.OpenFile(filepath.Join(path, "cgroup.subtree_control"), os.O_WRONLY, 0)
289+
if err != nil {
290+
return err
291+
}
292+
defer f.Close()
293+
294+
_, err = f.Write([]byte("+cpu"))
295+
if err != nil {
296+
return err
297+
}
298+
299+
return nil
262300
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package cpulimit
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
)
8+
9+
var cgroupPath = []string{"kubepods", "burstable", "pods234sdf", "234as8df34"}
10+
11+
func createHierarchy(t *testing.T, cpuEnabled bool) (string, string) {
12+
testRoot := t.TempDir()
13+
if err := os.WriteFile(filepath.Join(testRoot, "cgroup.controllers"), []byte(""), 0755); err != nil {
14+
t.Fatal(err)
15+
}
16+
17+
if err := os.WriteFile(filepath.Join(testRoot, "cgroup.subtree_control"), []byte(""), 0755); err != nil {
18+
t.Fatal(err)
19+
}
20+
21+
testCgroup := ""
22+
for i, level := range cgroupPath {
23+
testCgroup = filepath.Join(testCgroup, level)
24+
fullPath := filepath.Join(testRoot, testCgroup)
25+
if err := os.Mkdir(fullPath, 0o755); err != nil {
26+
t.Fatal(err)
27+
}
28+
29+
ctrlFile, err := os.Create(filepath.Join(fullPath, "cgroup.controllers"))
30+
if err != nil {
31+
t.Fatal(err)
32+
}
33+
defer ctrlFile.Close()
34+
35+
if cpuEnabled {
36+
if _, err := ctrlFile.WriteString("cpu"); err != nil {
37+
t.Fatal(err)
38+
}
39+
}
40+
41+
subTreeFile, err := os.Create(filepath.Join(fullPath, "cgroup.subtree_control"))
42+
if err != nil {
43+
t.Fatal(err)
44+
}
45+
defer subTreeFile.Close()
46+
47+
if cpuEnabled && i < len(cgroupPath)-1 {
48+
if _, err := subTreeFile.WriteString("cpu"); err != nil {
49+
t.Fatal(err)
50+
}
51+
}
52+
}
53+
54+
return testRoot, testCgroup
55+
}
56+
57+
func TestEnableController(t *testing.T) {
58+
root, cgroup := createHierarchy(t, false)
59+
if err := ensureControllerEnabled(root, cgroup, "cpu"); err != nil {
60+
t.Fatal(err)
61+
}
62+
63+
levelPath := root
64+
for _, level := range cgroupPath {
65+
verifyCpuControllerToggled(t, levelPath, true)
66+
levelPath = filepath.Join(levelPath, level)
67+
}
68+
69+
verifyCpuControllerToggled(t, levelPath, false)
70+
}
71+
72+
func verifyCpuControllerToggled(t *testing.T, path string, enabled bool) {
73+
t.Helper()
74+
75+
content, err := os.ReadFile(filepath.Join(path, "cgroup.subtree_control"))
76+
if err != nil {
77+
t.Fatal(err)
78+
}
79+
80+
if enabled && string(content) != "+cpu" {
81+
t.Fatalf("%s should have enabled cpu controller", path)
82+
} else if !enabled && string(content) == "+cpu" {
83+
t.Fatalf("%s should not have enabled cpu controller", path)
84+
}
85+
}

0 commit comments

Comments
 (0)