aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-02-26 09:08:19 -0600
committerAtomic Bot <atomic-devel@projectatomic.io>2018-02-26 23:41:47 +0000
commit6cb1c31d3f9e575688ace95206898c7fff0c88f9 (patch)
tree70bd6b99e6e8068abfadbd224126512d9625bb00
parentf47a5be60d91fd2055ed6afbb6bb014c9635f2df (diff)
downloadpodman-6cb1c31d3f9e575688ace95206898c7fff0c88f9.tar.gz
podman-6cb1c31d3f9e575688ace95206898c7fff0c88f9.tar.bz2
podman-6cb1c31d3f9e575688ace95206898c7fff0c88f9.zip
Restrict top output to container's pids only
Due to the way ps arguments work, it was possible to display pids that dont below to the container in top output. We now filter pids that dont belong to the container out of the output. This also means the pid column must be present in the output or we throw an error. This resolves issue #391 Signed-off-by: baude <bbaude@redhat.com> Closes: #400 Approved by: rhatdan
-rw-r--r--cmd/podman/top.go4
-rw-r--r--libpod/container_top.go54
-rw-r--r--test/e2e/top_test.go16
3 files changed, 68 insertions, 6 deletions
diff --git a/cmd/podman/top.go b/cmd/podman/top.go
index 6aff25a71..5ff3b6643 100644
--- a/cmd/podman/top.go
+++ b/cmd/podman/top.go
@@ -70,11 +70,11 @@ func topCmd(c *cli.Context) error {
psArgs = append(psArgs, psOpts...)
- results, err := container.GetContainerPidInformation(psArgs)
+ psOutput, err := container.GetContainerPidInformation(psArgs)
if err != nil {
return err
}
- for _, line := range results {
+ for _, line := range psOutput {
fmt.Println(line)
}
return nil
diff --git a/libpod/container_top.go b/libpod/container_top.go
index 3eb484acd..241e3a3e7 100644
--- a/libpod/container_top.go
+++ b/libpod/container_top.go
@@ -38,7 +38,7 @@ func (c *Container) getContainerPids() ([]string, error) {
}
// GetContainerPidInformation calls ps with the appropriate options and returns
-// the results as a string
+// the results as a string and the container's PIDs as a []string
func (c *Container) GetContainerPidInformation(args []string) ([]string, error) {
if !c.locked {
c.lock.Lock()
@@ -57,5 +57,55 @@ func (c *Container) GetContainerPidInformation(args []string) ([]string, error)
if err != nil {
return []string{}, errors.Wrapf(err, "unable to obtain information about pids")
}
- return strings.Split(results, "\n"), nil
+
+ 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, results[0])
+
+ 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 StringInSlice(pid, pids) {
+ output = append(output, l)
+ }
+ }
+ 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)
}
diff --git a/test/e2e/top_test.go b/test/e2e/top_test.go
index d4438293b..410803353 100644
--- a/test/e2e/top_test.go
+++ b/test/e2e/top_test.go
@@ -59,14 +59,26 @@ var _ = Describe("Podman top", func() {
Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1))
})
- It("podman top on non-running container", func() {
+ It("podman top with options", func() {
session := podmanTest.Podman([]string{"run", "-d", ALPINE, "top", "-d", "2"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- result := podmanTest.Podman([]string{"top", session.OutputToString(), "-o", "fuser,f,comm,label"})
+ result := podmanTest.Podman([]string{"top", session.OutputToString(), "-o", "pid,fuser,f,comm,label"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1))
})
+
+ It("podman top on container invalid options", func() {
+ sleep := podmanTest.RunSleepContainer("")
+ sleep.WaitWithDefaultTimeout()
+ Expect(sleep.ExitCode()).To(Equal(0))
+ cid := sleep.OutputToString()
+
+ result := podmanTest.Podman([]string{"top", cid, "-o time"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(125))
+ })
+
})