mirror of
https://github.com/containers/podman.git
synced 2025-06-09 09:04:08 +08:00
Podman info add support for status of cgroup controllers
Signed-off-by: flouthoc <flouthoc.git@gmail.com>
This commit is contained in:
@ -32,6 +32,12 @@ $ podman info
|
|||||||
host:
|
host:
|
||||||
arch: amd64
|
arch: amd64
|
||||||
buildahVersion: 1.19.0-dev
|
buildahVersion: 1.19.0-dev
|
||||||
|
cgroupControllers:
|
||||||
|
- cpuset
|
||||||
|
- cpu
|
||||||
|
- io
|
||||||
|
- memory
|
||||||
|
- pids
|
||||||
cgroupManager: systemd
|
cgroupManager: systemd
|
||||||
cgroupVersion: v2
|
cgroupVersion: v2
|
||||||
conmon:
|
conmon:
|
||||||
@ -145,6 +151,13 @@ Run podman info with JSON formatted response:
|
|||||||
"buildahVersion": "1.19.0-dev",
|
"buildahVersion": "1.19.0-dev",
|
||||||
"cgroupManager": "systemd",
|
"cgroupManager": "systemd",
|
||||||
"cgroupVersion": "v2",
|
"cgroupVersion": "v2",
|
||||||
|
"cgroupControllers": [
|
||||||
|
"cpuset",
|
||||||
|
"cpu",
|
||||||
|
"io",
|
||||||
|
"memory",
|
||||||
|
"pids"
|
||||||
|
],
|
||||||
"conmon": {
|
"conmon": {
|
||||||
"package": "conmon-2.0.22-2.fc33.x86_64",
|
"package": "conmon-2.0.22-2.fc33.x86_64",
|
||||||
"path": "/usr/bin/conmon",
|
"path": "/usr/bin/conmon",
|
||||||
|
@ -27,6 +27,7 @@ type HostInfo struct {
|
|||||||
BuildahVersion string `json:"buildahVersion"`
|
BuildahVersion string `json:"buildahVersion"`
|
||||||
CgroupManager string `json:"cgroupManager"`
|
CgroupManager string `json:"cgroupManager"`
|
||||||
CGroupsVersion string `json:"cgroupVersion"`
|
CGroupsVersion string `json:"cgroupVersion"`
|
||||||
|
CgroupControllers []string `json:"cgroupControllers"`
|
||||||
Conmon *ConmonInfo `json:"conmon"`
|
Conmon *ConmonInfo `json:"conmon"`
|
||||||
CPUs int `json:"cpus"`
|
CPUs int `json:"cpus"`
|
||||||
Distribution DistributionInfo `json:"distribution"`
|
Distribution DistributionInfo `json:"distribution"`
|
||||||
|
@ -93,10 +93,23 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
|
|||||||
return nil, errors.Wrapf(err, "error getting Seccomp profile path")
|
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{
|
info := define.HostInfo{
|
||||||
Arch: runtime.GOARCH,
|
Arch: runtime.GOARCH,
|
||||||
BuildahVersion: buildah.Version,
|
BuildahVersion: buildah.Version,
|
||||||
CgroupManager: r.config.Engine.CgroupManager,
|
CgroupManager: r.config.Engine.CgroupManager,
|
||||||
|
CgroupControllers: availableControllers,
|
||||||
Linkmode: linkmode.Linkmode(),
|
Linkmode: linkmode.Linkmode(),
|
||||||
CPUs: runtime.NumCPU(),
|
CPUs: runtime.NumCPU(),
|
||||||
Distribution: hostDistributionInfo,
|
Distribution: hostDistributionInfo,
|
||||||
@ -120,11 +133,6 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
|
|||||||
SwapTotal: mi.SwapTotal,
|
SwapTotal: mi.SwapTotal,
|
||||||
}
|
}
|
||||||
|
|
||||||
// CGroups version
|
|
||||||
unified, err := cgroups.IsCgroup2UnifiedMode()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "error reading cgroups mode")
|
|
||||||
}
|
|
||||||
cgroupVersion := "v1"
|
cgroupVersion := "v1"
|
||||||
if unified {
|
if unified {
|
||||||
cgroupVersion = "v2"
|
cgroupVersion = "v2"
|
||||||
|
@ -128,28 +128,118 @@ func init() {
|
|||||||
// getAvailableControllers get the available controllers
|
// getAvailableControllers get the available controllers
|
||||||
func getAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool) ([]controller, error) {
|
func getAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool) ([]controller, error) {
|
||||||
if cgroup2 {
|
if cgroup2 {
|
||||||
return nil, fmt.Errorf("getAvailableControllers not implemented yet for cgroup v2")
|
|
||||||
}
|
|
||||||
|
|
||||||
infos, err := ioutil.ReadDir(cgroupRoot)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
controllers := []controller{}
|
controllers := []controller{}
|
||||||
for _, i := range infos {
|
subtreeControl := cgroupRoot + "/cgroup.subtree_control"
|
||||||
name := i.Name()
|
// rootless cgroupv2: check available controllers for current user ,systemd or servicescope will inherit
|
||||||
if _, found := exclude[name]; found {
|
if rootless.IsRootless() {
|
||||||
continue
|
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{
|
c := controller{
|
||||||
name: name,
|
name: controllerName,
|
||||||
symlink: !i.IsDir(),
|
symlink: false,
|
||||||
}
|
}
|
||||||
controllers = append(controllers, c)
|
controllers = append(controllers, c)
|
||||||
}
|
}
|
||||||
return controllers, nil
|
return controllers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subsystems, _ := cgroupV1GetAllSubsystems()
|
||||||
|
controllers := []controller{}
|
||||||
|
// 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: 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
|
// getCgroupv1Path is a helper function to get the cgroup v1 path
|
||||||
func (c *CgroupControl) getCgroupv1Path(name string) string {
|
func (c *CgroupControl) getCgroupv1Path(name string) string {
|
||||||
return filepath.Join(cgroupRoot, name, c.path)
|
return filepath.Join(cgroupRoot, name, c.path)
|
||||||
|
@ -135,4 +135,14 @@ var _ = Describe("Podman Info", func() {
|
|||||||
Expect(session.OutputToString()).To(ContainSubstring("false"))
|
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"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user