summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorflouthoc <flouthoc.git@gmail.com>2021-05-19 01:19:20 +0530
committerMatthew Heon <mheon@redhat.com>2021-05-25 15:19:03 -0400
commitc53638e9f61e61b1344cbf090c9766a1891c8a44 (patch)
treeaa81f5ffbf38d068e049d59756af9b99f047f2fc
parentac8b7ddd8dc2b3d4ac2da6b4ddd08b900eb02353 (diff)
downloadpodman-c53638e9f61e61b1344cbf090c9766a1891c8a44.tar.gz
podman-c53638e9f61e61b1344cbf090c9766a1891c8a44.tar.bz2
podman-c53638e9f61e61b1344cbf090c9766a1891c8a44.zip
Podman info add support for status of cgroup controllers
Signed-off-by: flouthoc <flouthoc.git@gmail.com>
-rw-r--r--docs/source/markdown/podman-info.1.md13
-rw-r--r--libpod/define/info.go31
-rw-r--r--libpod/info.go44
-rw-r--r--pkg/cgroups/cgroups.go106
-rw-r--r--test/e2e/info_test.go10
5 files changed, 163 insertions, 41 deletions
diff --git a/docs/source/markdown/podman-info.1.md b/docs/source/markdown/podman-info.1.md
index 4af51d3eb..227fbd92d 100644
--- a/docs/source/markdown/podman-info.1.md
+++ b/docs/source/markdown/podman-info.1.md
@@ -32,6 +32,12 @@ $ podman info
host:
arch: amd64
buildahVersion: 1.19.0-dev
+ cgroupControllers:
+ - cpuset
+ - cpu
+ - io
+ - memory
+ - pids
cgroupManager: systemd
cgroupVersion: v2
conmon:
@@ -145,6 +151,13 @@ Run podman info with JSON formatted response:
"buildahVersion": "1.19.0-dev",
"cgroupManager": "systemd",
"cgroupVersion": "v2",
+ "cgroupControllers": [
+ "cpuset",
+ "cpu",
+ "io",
+ "memory",
+ "pids"
+ ],
"conmon": {
"package": "conmon-2.0.22-2.fc33.x86_64",
"path": "/usr/bin/conmon",
diff --git a/libpod/define/info.go b/libpod/define/info.go
index c9d6877c0..de709be74 100644
--- a/libpod/define/info.go
+++ b/libpod/define/info.go
@@ -23,21 +23,22 @@ type SecurityInfo struct {
// HostInfo describes the libpod host
type HostInfo struct {
- Arch string `json:"arch"`
- BuildahVersion string `json:"buildahVersion"`
- CgroupManager string `json:"cgroupManager"`
- CGroupsVersion string `json:"cgroupVersion"`
- Conmon *ConmonInfo `json:"conmon"`
- CPUs int `json:"cpus"`
- Distribution DistributionInfo `json:"distribution"`
- EventLogger string `json:"eventLogger"`
- Hostname string `json:"hostname"`
- IDMappings IDMappings `json:"idMappings,omitempty"`
- Kernel string `json:"kernel"`
- MemFree int64 `json:"memFree"`
- MemTotal int64 `json:"memTotal"`
- OCIRuntime *OCIRuntimeInfo `json:"ociRuntime"`
- OS string `json:"os"`
+ Arch string `json:"arch"`
+ BuildahVersion string `json:"buildahVersion"`
+ CgroupManager string `json:"cgroupManager"`
+ CGroupsVersion string `json:"cgroupVersion"`
+ CgroupControllers []string `json:"cgroupControllers"`
+ Conmon *ConmonInfo `json:"conmon"`
+ CPUs int `json:"cpus"`
+ Distribution DistributionInfo `json:"distribution"`
+ EventLogger string `json:"eventLogger"`
+ Hostname string `json:"hostname"`
+ IDMappings IDMappings `json:"idMappings,omitempty"`
+ Kernel string `json:"kernel"`
+ MemFree int64 `json:"memFree"`
+ MemTotal int64 `json:"memTotal"`
+ OCIRuntime *OCIRuntimeInfo `json:"ociRuntime"`
+ OS string `json:"os"`
// RemoteSocket returns the UNIX domain socket the Podman service is listening on
RemoteSocket *RemoteSocket `json:"remoteSocket,omitempty"`
RuntimeInfo map[string]interface{} `json:"runtimeInfo,omitempty"`
diff --git a/libpod/info.go b/libpod/info.go
index 7a28a4cf7..461e39a48 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -93,20 +93,33 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
return nil, errors.Wrapf(err, "error getting Seccomp profile path")
}
+ // CGroups version
+ unified, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading cgroups mode")
+ }
+
+ // Get Map of all available controllers
+ availableControllers, err := cgroups.GetAvailableControllers(nil, unified)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting available cgroup controllers")
+ }
+
info := define.HostInfo{
- Arch: runtime.GOARCH,
- BuildahVersion: buildah.Version,
- CgroupManager: r.config.Engine.CgroupManager,
- Linkmode: linkmode.Linkmode(),
- CPUs: runtime.NumCPU(),
- Distribution: hostDistributionInfo,
- EventLogger: r.eventer.String(),
- Hostname: host,
- IDMappings: define.IDMappings{},
- Kernel: kv,
- MemFree: mi.MemFree,
- MemTotal: mi.MemTotal,
- OS: runtime.GOOS,
+ Arch: runtime.GOARCH,
+ BuildahVersion: buildah.Version,
+ CgroupManager: r.config.Engine.CgroupManager,
+ CgroupControllers: availableControllers,
+ Linkmode: linkmode.Linkmode(),
+ CPUs: runtime.NumCPU(),
+ Distribution: hostDistributionInfo,
+ EventLogger: r.eventer.String(),
+ Hostname: host,
+ IDMappings: define.IDMappings{},
+ Kernel: kv,
+ MemFree: mi.MemFree,
+ MemTotal: mi.MemTotal,
+ OS: runtime.GOOS,
Security: define.SecurityInfo{
AppArmorEnabled: apparmor.IsEnabled(),
DefaultCapabilities: strings.Join(r.config.Containers.DefaultCapabilities, ","),
@@ -120,11 +133,6 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
SwapTotal: mi.SwapTotal,
}
- // CGroups version
- unified, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- return nil, errors.Wrapf(err, "error reading cgroups mode")
- }
cgroupVersion := "v1"
if unified {
cgroupVersion = "v2"
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index aefb5183b..911edeb5b 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -128,28 +128,118 @@ func init() {
// getAvailableControllers get the available controllers
func getAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool) ([]controller, error) {
if cgroup2 {
- return nil, fmt.Errorf("getAvailableControllers not implemented yet for cgroup v2")
+ controllers := []controller{}
+ subtreeControl := cgroupRoot + "/cgroup.subtree_control"
+ // rootless cgroupv2: check available controllers for current user ,systemd or servicescope will inherit
+ if rootless.IsRootless() {
+ userSlice, err := getCgroupPathForCurrentProcess()
+ if err != nil {
+ return controllers, err
+ }
+ //userSlice already contains '/' so not adding here
+ basePath := cgroupRoot + userSlice
+ subtreeControl = fmt.Sprintf("%s/cgroup.subtree_control", basePath)
+ }
+ subtreeControlBytes, err := ioutil.ReadFile(subtreeControl)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed while reading controllers for cgroup v2 from %q", subtreeControl)
+ }
+ for _, controllerName := range strings.Fields(string(subtreeControlBytes)) {
+ c := controller{
+ name: controllerName,
+ symlink: false,
+ }
+ controllers = append(controllers, c)
+ }
+ return controllers, nil
}
- infos, err := ioutil.ReadDir(cgroupRoot)
- if err != nil {
- return nil, err
- }
+ subsystems, _ := cgroupV1GetAllSubsystems()
controllers := []controller{}
- for _, i := range infos {
- name := i.Name()
+ // cgroupv1 and rootless: No subsystem is available: delegation is unsafe.
+ if rootless.IsRootless() {
+ return controllers, nil
+ }
+
+ for _, name := range subsystems {
if _, found := exclude[name]; found {
continue
}
+ isSymLink := false
+ fileInfo, err := os.Stat(cgroupRoot + "/" + name)
+ if err != nil {
+ isSymLink = !fileInfo.IsDir()
+ }
c := controller{
name: name,
- symlink: !i.IsDir(),
+ symlink: isSymLink,
}
controllers = append(controllers, c)
}
+
return controllers, nil
}
+// GetAvailableControllers get string:bool map of all the available controllers
+func GetAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool) ([]string, error) {
+ availableControllers, err := getAvailableControllers(exclude, cgroup2)
+ if err != nil {
+ return nil, err
+ }
+ controllerList := []string{}
+ for _, controller := range availableControllers {
+ controllerList = append(controllerList, controller.name)
+ }
+
+ return controllerList, nil
+}
+
+func cgroupV1GetAllSubsystems() ([]string, error) {
+ f, err := os.Open("/proc/cgroups")
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ subsystems := []string{}
+
+ s := bufio.NewScanner(f)
+ for s.Scan() {
+ text := s.Text()
+ if text[0] != '#' {
+ parts := strings.Fields(text)
+ if len(parts) >= 4 && parts[3] != "0" {
+ subsystems = append(subsystems, parts[0])
+ }
+ }
+ }
+ if err := s.Err(); err != nil {
+ return nil, err
+ }
+ return subsystems, nil
+}
+
+func getCgroupPathForCurrentProcess() (string, error) {
+ path := fmt.Sprintf("/proc/%d/cgroup", os.Getpid())
+ f, err := os.Open(path)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+
+ cgroupPath := ""
+ s := bufio.NewScanner(f)
+ for s.Scan() {
+ text := s.Text()
+ procEntries := strings.SplitN(text, "::", 2)
+ cgroupPath = procEntries[1]
+ }
+ if err := s.Err(); err != nil {
+ return cgroupPath, err
+ }
+ return cgroupPath, nil
+}
+
// getCgroupv1Path is a helper function to get the cgroup v1 path
func (c *CgroupControl) getCgroupv1Path(name string) string {
return filepath.Join(cgroupRoot, name, c.path)
diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go
index 60136bcc2..f5b70d6bf 100644
--- a/test/e2e/info_test.go
+++ b/test/e2e/info_test.go
@@ -135,4 +135,14 @@ var _ = Describe("Podman Info", func() {
Expect(session.OutputToString()).To(ContainSubstring("false"))
}
})
+
+ It("Podman info must contain cgroupControllers with ReleventControllers", func() {
+ SkipIfRootless("Hard to tell which controllers are going to be enabled for rootless")
+ SkipIfRootlessCgroupsV1("Disable cgroups not supported on cgroupv1 for rootless users")
+ session := podmanTest.Podman([]string{"info", "--format", "{{.Host.CgroupControllers}}"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("memory"))
+ Expect(session.OutputToString()).To(ContainSubstring("pids"))
+ })
})