diff options
-rw-r--r-- | cmd/podman/top.go | 19 | ||||
-rw-r--r-- | libpod/container_top.go | 24 | ||||
-rw-r--r-- | test/e2e/top_test.go | 8 |
3 files changed, 38 insertions, 13 deletions
diff --git a/cmd/podman/top.go b/cmd/podman/top.go index 7ea8a1169..d848723e2 100644 --- a/cmd/podman/top.go +++ b/cmd/podman/top.go @@ -2,6 +2,8 @@ package main import ( "fmt" + "os" + "text/tabwriter" "github.com/pkg/errors" "github.com/projectatomic/libpod/cmd/podman/libpodruntime" @@ -34,8 +36,7 @@ func topCmd(c *cli.Context) error { var container *libpod.Container var err error args := c.Args() - var psArgs []string - psOpts := []string{"-o", "uid,pid,ppid,c,stime,tname,time,cmd"} + if len(args) < 1 && !c.Bool("latest") { return errors.Errorf("you must provide the name or id of a running container") } @@ -48,9 +49,6 @@ func topCmd(c *cli.Context) error { return errors.Wrapf(err, "error creating libpod runtime") } defer runtime.Shutdown(false) - if len(args) > 1 { - psOpts = args[1:] - } if c.Bool("latest") { container, err = runtime.GetLatestContainer() @@ -69,14 +67,15 @@ func topCmd(c *cli.Context) error { return errors.Errorf("top can only be used on running containers") } - psArgs = append(psArgs, psOpts...) - - psOutput, err := container.GetContainerPidInformation(psArgs) + psOutput, err := container.GetContainerPidInformation([]string{}) if err != nil { return err } - for _, line := range psOutput { - fmt.Println(line) + + w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) + for _, proc := range psOutput { + fmt.Fprintln(w, proc) } + w.Flush() return nil } diff --git a/libpod/container_top.go b/libpod/container_top.go index a83303036..f5d314d49 100644 --- a/libpod/container_top.go +++ b/libpod/container_top.go @@ -44,8 +44,20 @@ func (c *Container) getContainerPids() ([]string, error) { } // GetContainerPidInformation calls ps with the appropriate options and returns -// the results as a string and the container's PIDs as a []string +// 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() @@ -80,7 +92,7 @@ func filterPids(psOutput string, pids []string) ([]string, error) { // Pids that don't belong. // append the headers back in - output = append(output, results[0]) + output = append(output, strings.Join(headers, "\t")) pidIndex := -1 for i, header := range headers { @@ -98,7 +110,13 @@ func filterPids(psOutput string, pids []string) ([]string, error) { cols := fieldsASCII(l) pid := cols[pidIndex] if util.StringInSlice(pid, pids) { - output = append(output, l) + // 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 diff --git a/test/e2e/top_test.go b/test/e2e/top_test.go index 4b4cb47e4..e7ac90219 100644 --- a/test/e2e/top_test.go +++ b/test/e2e/top_test.go @@ -59,7 +59,14 @@ var _ = Describe("Podman top", func() { Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1)) }) + // XXX(ps-issue): for the time being, podman-top and the libpod API + // GetContainerPidInformation(...) will ignore any arguments passed to ps, + // so we have to disable the tests below. Please refer to + // https://github.com/projectatomic/libpod/pull/939 for more background + // information. + It("podman top with options", func() { + Skip("podman-top with options: options are temporarily ignored") session := podmanTest.Podman([]string{"run", "-d", ALPINE, "top", "-d", "2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -71,6 +78,7 @@ var _ = Describe("Podman top", func() { }) It("podman top on container invalid options", func() { + Skip("podman-top with invalid options: options are temporarily ignored") top := podmanTest.RunTopContainer("") top.WaitWithDefaultTimeout() Expect(top.ExitCode()).To(Equal(0)) |