From aa8003ca79589e6ab8a1d081b2d768eb9f35b5c8 Mon Sep 17 00:00:00 2001 From: Cameron Sparr Date: Wed, 16 Feb 2022 17:48:07 -0800 Subject: [PATCH] Fix systemd full path Signed-off-by: Cameron Sparr --- v2/manager.go | 33 ++++++++++++++++++++--- v2/manager_test.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/v2/manager.go b/v2/manager.go index f5466785..c08d9a7d 100644 --- a/v2/manager.go +++ b/v2/manager.go @@ -701,12 +701,39 @@ func setDevices(path string, devices []specs.LinuxDeviceCgroup) error { return nil } +// getSystemdFullPath returns the full systemd path when creating a systemd slice group. +// the reason this is necessary is because the "-" character has a special meaning in +// systemd slice. For example, when creating a slice called "my-group-112233.slice", +// systemd will create a hierarchy like this: +// /sys/fs/cgroup/my.slice/my-group.slice/my-group-112233.slice +func getSystemdFullPath(slice, group string) string { + return filepath.Join(defaultCgroup2Path, dashesToPath(slice), dashesToPath(group)) +} + +// dashesToPath converts a slice name with dashes to it's corresponding systemd filesystem path. +func dashesToPath(in string) string { + path := "" + if strings.HasSuffix(in, ".slice") && strings.Contains(in, "-") { + parts := strings.Split(in, "-") + for i := range parts { + s := strings.Join(parts[0:i+1], "-") + if !strings.HasSuffix(s, ".slice") { + s += ".slice" + } + path = filepath.Join(path, s) + } + } else { + path = filepath.Join(path, in) + } + return path +} + func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, error) { if slice == "" { slice = defaultSlice } ctx := context.TODO() - path := filepath.Join(defaultCgroup2Path, slice, group) + path := getSystemdFullPath(slice, group) conn, err := systemdDbus.NewWithContext(ctx) if err != nil { return &Manager{}, err @@ -796,9 +823,9 @@ func LoadSystemd(slice, group string) (*Manager, error) { if slice == "" { slice = defaultSlice } - group = filepath.Join(defaultCgroup2Path, slice, group) + path := getSystemdFullPath(slice, group) return &Manager{ - path: group, + path: path, }, nil } diff --git a/v2/manager_test.go b/v2/manager_test.go index 35d104ca..650af280 100644 --- a/v2/manager_test.go +++ b/v2/manager_test.go @@ -22,6 +22,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "go.uber.org/goleak" ) @@ -74,3 +75,67 @@ func TestEventChanCleanupOnCgroupRemoval(t *testing.T) { } goleak.VerifyNone(t) } + +func TestSystemdFullPath(t *testing.T) { + tests := []struct { + inputSlice string + inputGroup string + expectedOut string + }{ + { + inputSlice: "user.slice", + inputGroup: "myGroup.slice", + expectedOut: "/sys/fs/cgroup/user.slice/myGroup.slice", + }, + { + inputSlice: "/", + inputGroup: "myGroup.slice", + expectedOut: "/sys/fs/cgroup/myGroup.slice", + }, + { + inputSlice: "system.slice", + inputGroup: "myGroup.slice", + expectedOut: "/sys/fs/cgroup/system.slice/myGroup.slice", + }, + { + inputSlice: "user.slice", + inputGroup: "my-group.slice", + expectedOut: "/sys/fs/cgroup/user.slice/my.slice/my-group.slice", + }, + { + inputSlice: "user.slice", + inputGroup: "my-group-more-dashes.slice", + expectedOut: "/sys/fs/cgroup/user.slice/my.slice/my-group.slice/my-group-more.slice/my-group-more-dashes.slice", + }, + { + inputSlice: "user.slice", + inputGroup: "my-group-dashes.slice", + expectedOut: "/sys/fs/cgroup/user.slice/my.slice/my-group.slice/my-group-dashes.slice", + }, + { + inputSlice: "user.slice", + inputGroup: "myGroup.scope", + expectedOut: "/sys/fs/cgroup/user.slice/myGroup.scope", + }, + { + inputSlice: "user.slice", + inputGroup: "my-group-dashes.scope", + expectedOut: "/sys/fs/cgroup/user.slice/my-group-dashes.scope", + }, + { + inputSlice: "test-waldo.slice", + inputGroup: "my-group.slice", + expectedOut: "/sys/fs/cgroup/test.slice/test-waldo.slice/my.slice/my-group.slice", + }, + { + inputSlice: "test-waldo.slice", + inputGroup: "my.service", + expectedOut: "/sys/fs/cgroup/test.slice/test-waldo.slice/my.service", + }, + } + + for _, test := range tests { + actual := getSystemdFullPath(test.inputSlice, test.inputGroup) + assert.Equal(t, test.expectedOut, actual) + } +}