From 7a0d60d80c238741839730123b48a14bb67e03cf Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Mon, 30 Jan 2023 23:37:18 +0900 Subject: [PATCH] move ParseCgroupFileUnified from v3/cgroup1 to v3 The function isn't really for cgroup1. Signed-off-by: Akihiro Suda --- cgroup1/paths_test.go | 32 +++------------------------ cgroup1/utils.go | 40 ++++------------------------------ utils.go | 43 +++++++++++++++++++++++++++++++++++++ utils_test.go | 50 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 65 deletions(-) create mode 100644 utils_test.go diff --git a/cgroup1/paths_test.go b/cgroup1/paths_test.go index fee4fee8..8afe2cee 100644 --- a/cgroup1/paths_test.go +++ b/cgroup1/paths_test.go @@ -21,6 +21,8 @@ import ( "path/filepath" "strings" "testing" + + "github.com/containerd/cgroups/v3" ) func TestStaticPath(t *testing.T) { @@ -89,34 +91,6 @@ func TestRootPath(t *testing.T) { } } -func TestEmptySubsystem(t *testing.T) { - const data = `10:devices:/user.slice - 9:net_cls,net_prio:/ - 8:blkio:/ - 7:freezer:/ - 6:perf_event:/ - 5:cpuset:/ - 4:memory:/ - 3:pids:/user.slice/user-1000.slice/user@1000.service - 2:cpu,cpuacct:/ - 1:name=systemd:/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service - 0::/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service` - r := strings.NewReader(data) - paths, unified, err := parseCgroupFromReaderUnified(r) - if err != nil { - t.Fatal(err) - } - for subsystem, path := range paths { - if subsystem == "" { - t.Fatalf("empty subsystem for %q", path) - } - } - unifiedExpected := "/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service" - if unified != unifiedExpected { - t.Fatalf("expected %q, got %q", unifiedExpected, unified) - } -} - func TestSystemd240(t *testing.T) { if isUnified { t.Skipf("requires the system to be running in legacy mode") @@ -131,7 +105,7 @@ func TestSystemd240(t *testing.T) { 1:name=systemd:/system.slice/docker.service 0::/system.slice/docker.service` r := strings.NewReader(data) - paths, unified, err := parseCgroupFromReaderUnified(r) + paths, unified, err := cgroups.ParseCgroupFromReaderUnified(r) if err != nil { t.Fatal(err) } diff --git a/cgroup1/utils.go b/cgroup1/utils.go index 33b1f3ab..8ae005da 100644 --- a/cgroup1/utils.go +++ b/cgroup1/utils.go @@ -19,7 +19,6 @@ package cgroup1 import ( "bufio" "fmt" - "io" "os" "path/filepath" "strconv" @@ -180,7 +179,7 @@ func parseKV(raw string) (string, uint64, error) { // etc. // // The resulting map does not have an element for cgroup v2 unified hierarchy. -// Use ParseCgroupFileUnified to get the unified path. +// Use [cgroups.ParseCgroupFileUnified] to get the unified path. func ParseCgroupFile(path string) (map[string]string, error) { x, _, err := ParseCgroupFileUnified(path) return x, err @@ -188,41 +187,10 @@ func ParseCgroupFile(path string) (map[string]string, error) { // ParseCgroupFileUnified returns legacy subsystem paths as the first value, // and returns the unified path as the second value. +// +// Deprecated: use [cgroups.ParseCgroupFileUnified] instead . func ParseCgroupFileUnified(path string) (map[string]string, string, error) { - f, err := os.Open(path) - if err != nil { - return nil, "", err - } - defer f.Close() - return parseCgroupFromReaderUnified(f) -} - -func parseCgroupFromReaderUnified(r io.Reader) (map[string]string, string, error) { - var ( - cgroups = make(map[string]string) - unified = "" - s = bufio.NewScanner(r) - ) - for s.Scan() { - var ( - text = s.Text() - parts = strings.SplitN(text, ":", 3) - ) - if len(parts) < 3 { - return nil, unified, fmt.Errorf("invalid cgroup entry: %q", text) - } - for _, subs := range strings.Split(parts[1], ",") { - if subs == "" { - unified = parts[2] - } else { - cgroups[subs] = parts[2] - } - } - } - if err := s.Err(); err != nil { - return nil, unified, err - } - return cgroups, unified, nil + return cgroups.ParseCgroupFileUnified(path) } func getCgroupDestination(subsystem string) (string, error) { diff --git a/utils.go b/utils.go index f6325e7d..ebff755a 100644 --- a/utils.go +++ b/utils.go @@ -19,8 +19,10 @@ package cgroups import ( "bufio" "fmt" + "io" "os" "path/filepath" + "strings" "sync" "golang.org/x/sys/unix" @@ -105,3 +107,44 @@ func RunningInUserNS() bool { }) return inUserNS } + +// ParseCgroupFileUnified returns legacy subsystem paths as the first value, +// and returns the unified path as the second value. +func ParseCgroupFileUnified(path string) (map[string]string, string, error) { + f, err := os.Open(path) + if err != nil { + return nil, "", err + } + defer f.Close() + return ParseCgroupFromReaderUnified(f) +} + +// ParseCgroupFromReaderUnified returns legacy subsystem paths as the first value, +// and returns the unified path as the second value. +func ParseCgroupFromReaderUnified(r io.Reader) (map[string]string, string, error) { + var ( + cgroups = make(map[string]string) + unified = "" + s = bufio.NewScanner(r) + ) + for s.Scan() { + var ( + text = s.Text() + parts = strings.SplitN(text, ":", 3) + ) + if len(parts) < 3 { + return nil, unified, fmt.Errorf("invalid cgroup entry: %q", text) + } + for _, subs := range strings.Split(parts[1], ",") { + if subs == "" { + unified = parts[2] + } else { + cgroups[subs] = parts[2] + } + } + } + if err := s.Err(); err != nil { + return nil, unified, err + } + return cgroups, unified, nil +} diff --git a/utils_test.go b/utils_test.go new file mode 100644 index 00000000..280ef57a --- /dev/null +++ b/utils_test.go @@ -0,0 +1,50 @@ +/* + Copyright The containerd 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 ( + "strings" + "testing" +) + +func TestParseCgroupFromReaderUnified(t *testing.T) { + const data = `10:devices:/user.slice + 9:net_cls,net_prio:/ + 8:blkio:/ + 7:freezer:/ + 6:perf_event:/ + 5:cpuset:/ + 4:memory:/ + 3:pids:/user.slice/user-1000.slice/user@1000.service + 2:cpu,cpuacct:/ + 1:name=systemd:/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service + 0::/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service` + r := strings.NewReader(data) + paths, unified, err := ParseCgroupFromReaderUnified(r) + if err != nil { + t.Fatal(err) + } + for subsystem, path := range paths { + if subsystem == "" { + t.Fatalf("empty subsystem for %q", path) + } + } + unifiedExpected := "/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service" + if unified != unifiedExpected { + t.Fatalf("expected %q, got %q", unifiedExpected, unified) + } +}