mirror of
https://github.com/containers/podman.git
synced 2025-10-26 02:35:43 +08:00
top: make output tabular
Make the output of top tabular to be compatible with Docker. Please note, that any user-input for `GetContainerPidInformation(...)` will be ignored until we have found a way to generically and reliably parse ps-1 output or until there is a go-lib to extract all the data from /proc in a ps-1 compatible fashion. Fixes: #458 Signed-off-by: Valentin Rothberg <vrothberg@suse.com> Closes: #939 Approved by: rhatdan
This commit is contained in:
committed by
Atomic Bot
parent
9e134576e8
commit
b1e709806d
@ -2,6 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
|
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
|
||||||
@ -34,8 +36,7 @@ func topCmd(c *cli.Context) error {
|
|||||||
var container *libpod.Container
|
var container *libpod.Container
|
||||||
var err error
|
var err error
|
||||||
args := c.Args()
|
args := c.Args()
|
||||||
var psArgs []string
|
|
||||||
psOpts := []string{"-o", "uid,pid,ppid,c,stime,tname,time,cmd"}
|
|
||||||
if len(args) < 1 && !c.Bool("latest") {
|
if len(args) < 1 && !c.Bool("latest") {
|
||||||
return errors.Errorf("you must provide the name or id of a running container")
|
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")
|
return errors.Wrapf(err, "error creating libpod runtime")
|
||||||
}
|
}
|
||||||
defer runtime.Shutdown(false)
|
defer runtime.Shutdown(false)
|
||||||
if len(args) > 1 {
|
|
||||||
psOpts = args[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Bool("latest") {
|
if c.Bool("latest") {
|
||||||
container, err = runtime.GetLatestContainer()
|
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")
|
return errors.Errorf("top can only be used on running containers")
|
||||||
}
|
}
|
||||||
|
|
||||||
psArgs = append(psArgs, psOpts...)
|
psOutput, err := container.GetContainerPidInformation([]string{})
|
||||||
|
|
||||||
psOutput, err := container.GetContainerPidInformation(psArgs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,8 +44,20 @@ func (c *Container) getContainerPids() ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetContainerPidInformation calls ps with the appropriate options and returns
|
// 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) {
|
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 {
|
if !c.batched {
|
||||||
c.lock.Lock()
|
c.lock.Lock()
|
||||||
defer c.lock.Unlock()
|
defer c.lock.Unlock()
|
||||||
@ -80,7 +92,7 @@ func filterPids(psOutput string, pids []string) ([]string, error) {
|
|||||||
// Pids that don't belong.
|
// Pids that don't belong.
|
||||||
|
|
||||||
// append the headers back in
|
// append the headers back in
|
||||||
output = append(output, results[0])
|
output = append(output, strings.Join(headers, "\t"))
|
||||||
|
|
||||||
pidIndex := -1
|
pidIndex := -1
|
||||||
for i, header := range headers {
|
for i, header := range headers {
|
||||||
@ -98,7 +110,13 @@ func filterPids(psOutput string, pids []string) ([]string, error) {
|
|||||||
cols := fieldsASCII(l)
|
cols := fieldsASCII(l)
|
||||||
pid := cols[pidIndex]
|
pid := cols[pidIndex]
|
||||||
if util.StringInSlice(pid, pids) {
|
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
|
return output, nil
|
||||||
|
|||||||
@ -59,7 +59,14 @@ var _ = Describe("Podman top", func() {
|
|||||||
Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1))
|
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() {
|
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 := podmanTest.Podman([]string{"run", "-d", ALPINE, "top", "-d", "2"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
@ -71,6 +78,7 @@ var _ = Describe("Podman top", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("podman top on container invalid options", func() {
|
It("podman top on container invalid options", func() {
|
||||||
|
Skip("podman-top with invalid options: options are temporarily ignored")
|
||||||
top := podmanTest.RunTopContainer("")
|
top := podmanTest.RunTopContainer("")
|
||||||
top.WaitWithDefaultTimeout()
|
top.WaitWithDefaultTimeout()
|
||||||
Expect(top.ExitCode()).To(Equal(0))
|
Expect(top.ExitCode()).To(Equal(0))
|
||||||
|
|||||||
Reference in New Issue
Block a user