mirror of
https://github.com/containers/podman.git
synced 2025-05-19 16:18:51 +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:
|
||||
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",
|
||||
|
@ -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"`
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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"))
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user