summaryrefslogtreecommitdiff
path: root/libpod/container_top.go
diff options
context:
space:
mode:
authorValentin Rothberg <vrothberg@suse.com>2018-07-19 14:41:58 +0200
committerAtomic Bot <atomic-devel@projectatomic.io>2018-07-19 20:47:52 +0000
commitba1871dac033783ab0329c9b3c9113a34a90992f (patch)
treef0be2944ff09d857306ea42864c7b24ae86ae9bd /libpod/container_top.go
parent98703eb204923f06555605c648fc165a55214520 (diff)
downloadpodman-ba1871dac033783ab0329c9b3c9113a34a90992f.tar.gz
podman-ba1871dac033783ab0329c9b3c9113a34a90992f.tar.bz2
podman-ba1871dac033783ab0329c9b3c9113a34a90992f.zip
podman-top: use containers/psgo
Use github.com/containers/psgo instead of execing `ps (1)`. The psgo library enables a much more flexible interface with respect to which data to be printed (e.g., capabilities, seccomp mode, PID, PCPU, etc.) while the output can be parsed reliably. The library does not use ps (1) but parses /proc and /dev instead. To list the processes of a given container, psgo will join the mount namespace of the given container and extract all data from there. Notice that this commit breaks compatibility with docker-top. Signed-off-by: Valentin Rothberg <vrothberg@suse.com> Closes: #1113 Approved by: rhatdan
Diffstat (limited to 'libpod/container_top.go')
-rw-r--r--libpod/container_top.go135
1 files changed, 0 insertions, 135 deletions
diff --git a/libpod/container_top.go b/libpod/container_top.go
deleted file mode 100644
index f5d314d49..000000000
--- a/libpod/container_top.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package libpod
-
-import (
- "io/ioutil"
- "path/filepath"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/pkg/util"
- "github.com/projectatomic/libpod/utils"
- "github.com/sirupsen/logrus"
-)
-
-// GetContainerPids reads sysfs to obtain the pids associated with the container's cgroup
-// and uses locking
-func (c *Container) GetContainerPids() ([]string, error) {
- if !c.batched {
- c.lock.Lock()
- defer c.lock.Unlock()
- if err := c.syncContainer(); err != nil {
- return []string{}, errors.Wrapf(err, "error updating container %s state", c.ID())
- }
- }
- return c.getContainerPids()
-}
-
-// Gets the pids for a container without locking. should only be called from a func where
-// locking has already been established.
-func (c *Container) getContainerPids() ([]string, error) {
- cgroupPath, err := c.CGroupPath()
- if err != nil {
- return nil, err
- }
-
- taskFile := filepath.Join("/sys/fs/cgroup/pids", cgroupPath, "tasks")
-
- logrus.Debug("reading pids from ", taskFile)
-
- content, err := ioutil.ReadFile(taskFile)
- if err != nil {
- return []string{}, errors.Wrapf(err, "unable to read pids from %s", taskFile)
- }
- return strings.Fields(string(content)), nil
-}
-
-// GetContainerPidInformation calls ps with the appropriate options and returns
-// the results as a string and the container's PIDs as a []string. Note that
-// the ps output columns of each string are separated by a '\t\'. Currently,
-// the args argument is overwriten with []string{"-ef"} until there is a
-// portable library for ps-1 or to parse the procFS to extract all data.
-func (c *Container) GetContainerPidInformation(args []string) ([]string, error) {
- // XXX(ps-issue): args is overwriten with []{"-ef"} as the ps-1 tool
- // doesn't support a generic way of splitting columns, rendering its
- // output hard to parse. Docker first deterimes the number of columns
- // and merges all exceeding ones into the last one. We believe that
- // writing a go library which parses procFS in a ps-compatible way may
- // be more beneficial in the long run. Until then, args will be
- // ignored.
- args = []string{"-ef"}
-
- if !c.batched {
- c.lock.Lock()
- defer c.lock.Unlock()
- if err := c.syncContainer(); err != nil {
- return []string{}, errors.Wrapf(err, "error updating container %s state", c.ID())
- }
- }
- pids, err := c.getContainerPids()
- if err != nil {
- return []string{}, errors.Wrapf(err, "unable to obtain pids for ", c.ID())
- }
- args = append(args, "-p", strings.Join(pids, ","))
- logrus.Debug("Executing: ", strings.Join(args, " "))
- results, err := utils.ExecCmd("ps", args...)
- if err != nil {
- return []string{}, errors.Wrapf(err, "unable to obtain information about pids")
- }
-
- filteredOutput, err := filterPids(results, pids)
- if err != nil {
- return []string{}, err
- }
- return filteredOutput, nil
-}
-
-func filterPids(psOutput string, pids []string) ([]string, error) {
- var output []string
- results := strings.Split(psOutput, "\n")
- // The headers are in the first line of the results
- headers := fieldsASCII(results[0])
- // We need to make sure PID in headers, so that we can filter
- // Pids that don't belong.
-
- // append the headers back in
- output = append(output, strings.Join(headers, "\t"))
-
- pidIndex := -1
- for i, header := range headers {
- if header == "PID" {
- pidIndex = i
- }
- }
- if pidIndex == -1 {
- return []string{}, errors.Errorf("unable to find PID field in ps output. try a different set of ps arguments")
- }
- for _, l := range results[1:] {
- if l == "" {
- continue
- }
- cols := fieldsASCII(l)
- pid := cols[pidIndex]
- if util.StringInSlice(pid, pids) {
- // XXX(ps-issue): Strip cols down to the header's size
- // and merge exceeding fields. This is required to
- // "merge" the overhanging CMD entries which can
- // contain white spaces.
- out := cols[:len(headers)-1]
- out = append(out, strings.Join(cols[len(headers)-1:], " "))
- output = append(output, strings.Join(out, "\t"))
- }
- }
- return output, nil
-}
-
-// Detects ascii whitespaces
-func fieldsASCII(s string) []string {
- fn := func(r rune) bool {
- switch r {
- case '\t', '\n', '\f', '\r', ' ':
- return true
- }
- return false
- }
- return strings.FieldsFunc(s, fn)
-}