From 370d60c324399794c8f33ae0be976cc2880b004a Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 20 Nov 2019 10:53:15 -0500 Subject: [PATCH] Add Mode() func to check cgroup mount type This function will return the cgroup mode that is mounted on the host system. Signed-off-by: Michael Crosby --- Makefile | 5 ++++- cmd/cgctl/main.go | 21 +++++++++++++++++++++ utils.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d7f2628a..19e66075 100644 --- a/Makefile +++ b/Makefile @@ -14,8 +14,11 @@ PACKAGES=$(shell go list ./... | grep -v /vendor/) -all: +all: cgutil go build -v +cgutil: + cd cmd/cgctl && go build -v + proto: protobuild --quiet ${PACKAGES} diff --git a/cmd/cgctl/main.go b/cmd/cgctl/main.go index 98be1d05..5e102349 100644 --- a/cmd/cgctl/main.go +++ b/cmd/cgctl/main.go @@ -21,6 +21,7 @@ import ( "fmt" "os" + "github.com/containerd/cgroups" v2 "github.com/containerd/cgroups/v2" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -43,6 +44,7 @@ func main() { }, } app.Commands = []cli.Command{ + modeCommand, newCommand, delCommand, listCommand, @@ -158,3 +160,22 @@ var statCommand = cli.Command{ return json.NewEncoder(os.Stdout).Encode(stats) }, } + +var modeCommand = cli.Command{ + Name: "mode", + Usage: "return the cgroup mode that is mounted on the system", + Action: func(clix *cli.Context) error { + mode := cgroups.Mode() + switch mode { + case cgroups.Legacy: + fmt.Println("legacy") + case cgroups.Hybrid: + fmt.Println("hybrid") + case cgroups.Unified: + fmt.Println("unified") + case cgroups.Unavailable: + fmt.Println("cgroups unavailable") + } + return nil + }, +} diff --git a/utils.go b/utils.go index 8a97d04d..6b12c928 100644 --- a/utils.go +++ b/utils.go @@ -25,13 +25,59 @@ import ( "path/filepath" "strconv" "strings" + "sync" "time" units "github.com/docker/go-units" specs "github.com/opencontainers/runtime-spec/specs-go" + "golang.org/x/sys/unix" ) -var isUserNS = runningInUserNS() +var ( + isUserNS = runningInUserNS() + checkMode sync.Once + cgMode CGMode +) + +const unifiedMountpoint = "/sys/fs/cgroup" + +// CGMode is the cgroups mode of the host system +type CGMode int + +const ( + // Unavailable cgroup mountpoint + Unavailable CGMode = iota + // Legacy cgroups v1 + Legacy + // Hybrid with cgroups v1 and v2 controllers mounted + Hybrid + // Unified with only cgroups v2 mounted + Unified +) + +// Mode returns the cgroups mode running on the host +func Mode() CGMode { + checkMode.Do(func() { + var st unix.Statfs_t + if err := unix.Statfs(unifiedMountpoint, &st); err != nil { + cgMode = Unavailable + return + } + switch st.Type { + case unix.CGROUP2_SUPER_MAGIC: + cgMode = Unified + default: + cgMode = Legacy + if err := unix.Statfs(filepath.Join(unifiedMountpoint, "unified"), &st); err != nil { + return + } + if st.Type == unix.CGROUP2_SUPER_MAGIC { + cgMode = Hybrid + } + } + }) + return cgMode +} // runningInUserNS detects whether we are currently running in a user namespace. // Copied from github.com/lxc/lxd/shared/util.go