Merge pull request #871 from umohnani8/kpod_ps
Add namespace flag to kpod ps
This commit is contained in:
commit
a3a0bb5e55
4 changed files with 140 additions and 26 deletions
128
cmd/kpod/ps.go
128
cmd/kpod/ps.go
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
@ -21,15 +23,16 @@ import (
|
|||
)
|
||||
|
||||
type psOptions struct {
|
||||
all bool
|
||||
filter string
|
||||
format string
|
||||
last int
|
||||
latest bool
|
||||
noTrunc bool
|
||||
quiet bool
|
||||
size bool
|
||||
label string
|
||||
all bool
|
||||
filter string
|
||||
format string
|
||||
last int
|
||||
latest bool
|
||||
noTrunc bool
|
||||
quiet bool
|
||||
size bool
|
||||
label string
|
||||
namespace bool
|
||||
}
|
||||
|
||||
type psTemplateParams struct {
|
||||
|
@ -44,6 +47,14 @@ type psTemplateParams struct {
|
|||
Names string
|
||||
Labels string
|
||||
Mounts string
|
||||
PID int
|
||||
Cgroup string
|
||||
IPC string
|
||||
MNT string
|
||||
NET string
|
||||
PIDNS string
|
||||
User string
|
||||
UTS string
|
||||
}
|
||||
|
||||
// psJSONParams is only used when the JSON format is specified,
|
||||
|
@ -64,6 +75,18 @@ type psJSONParams struct {
|
|||
Labels fields.Set `json:"labels"`
|
||||
Mounts []specs.Mount `json:"mounts"`
|
||||
ContainerRunning bool `json:"ctrRunning"`
|
||||
Namespaces namespace `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
type namespace struct {
|
||||
PID string `json:"ctrPID,omitempty"`
|
||||
Cgroup string `json:"cgroup,omitempty"`
|
||||
IPC string `json:"ipc,omitempty"`
|
||||
MNT string `json:"mnt,omitempty"`
|
||||
NET string `json:"net,omitempty"`
|
||||
PIDNS string `json:"pid,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
UTS string `json:"uts,omitempty"`
|
||||
}
|
||||
|
||||
const runningState = "running"
|
||||
|
@ -103,6 +126,10 @@ var (
|
|||
Name: "size, s",
|
||||
Usage: "Display the total file sizes",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "namespace, ns",
|
||||
Usage: "Display namespace information",
|
||||
},
|
||||
}
|
||||
psDescription = "Prints out information about the containers"
|
||||
psCommand = cli.Command{
|
||||
|
@ -132,20 +159,21 @@ func psCmd(c *cli.Context) error {
|
|||
return errors.Errorf("too many arguments, ps takes no arguments")
|
||||
}
|
||||
|
||||
format := genPsFormat(c.Bool("quiet"), c.Bool("size"))
|
||||
format := genPsFormat(c.Bool("quiet"), c.Bool("size"), c.Bool("namespace"))
|
||||
if c.IsSet("format") {
|
||||
format = c.String("format")
|
||||
}
|
||||
|
||||
opts := psOptions{
|
||||
all: c.Bool("all"),
|
||||
filter: c.String("filter"),
|
||||
format: format,
|
||||
last: c.Int("last"),
|
||||
latest: c.Bool("latest"),
|
||||
noTrunc: c.Bool("no-trunc"),
|
||||
quiet: c.Bool("quiet"),
|
||||
size: c.Bool("size"),
|
||||
all: c.Bool("all"),
|
||||
filter: c.String("filter"),
|
||||
format: format,
|
||||
last: c.Int("last"),
|
||||
latest: c.Bool("latest"),
|
||||
noTrunc: c.Bool("no-trunc"),
|
||||
quiet: c.Bool("quiet"),
|
||||
size: c.Bool("size"),
|
||||
namespace: c.Bool("namespace"),
|
||||
}
|
||||
|
||||
// all, latest, and last are mutually exclusive. Only one flag can be used at a time
|
||||
|
@ -183,10 +211,14 @@ func psCmd(c *cli.Context) error {
|
|||
}
|
||||
|
||||
// generate the template based on conditions given
|
||||
func genPsFormat(quiet, size bool) (format string) {
|
||||
func genPsFormat(quiet, size, namespace bool) (format string) {
|
||||
if quiet {
|
||||
return formats.IDString
|
||||
}
|
||||
if namespace {
|
||||
format = "table {{.ID}}\t{{.Names}}\t{{.PID}}\t{{.Cgroup}}\t{{.IPC}}\t{{.MNT}}\t{{.NET}}\t{{.PIDNS}}\t{{.User}}\t{{.UTS}}\t"
|
||||
return
|
||||
}
|
||||
format = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.CreatedAt}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t"
|
||||
if size {
|
||||
format += "{{.Size}}\t"
|
||||
|
@ -253,13 +285,15 @@ func getTemplateOutput(containers []*libkpod.ContainerData, opts psOptions) (psO
|
|||
ctrID := ctr.ID
|
||||
runningFor := units.HumanDuration(time.Since(ctr.State.Created))
|
||||
createdAt := runningFor + " ago"
|
||||
command := getCommand(ctr.ImageCreatedBy)
|
||||
command := getStrFromSquareBrackets(ctr.ImageCreatedBy)
|
||||
imageName := ctr.FromImage
|
||||
mounts := getMounts(ctr.Mounts, opts.noTrunc)
|
||||
ports := getPorts(ctr.Config.ExposedPorts)
|
||||
size := units.HumanSize(float64(ctr.SizeRootFs))
|
||||
labels := getLabels(ctr.Labels)
|
||||
|
||||
ns := getNamespaces(ctr.State.Pid)
|
||||
|
||||
switch ctr.State.Status {
|
||||
case "stopped":
|
||||
status = "Exited (" + strconv.FormatInt(int64(ctr.State.ExitCode), 10) + ") " + runningFor + " ago"
|
||||
|
@ -286,20 +320,63 @@ func getTemplateOutput(containers []*libkpod.ContainerData, opts psOptions) (psO
|
|||
Names: ctr.Name,
|
||||
Labels: labels,
|
||||
Mounts: mounts,
|
||||
PID: ctr.State.Pid,
|
||||
Cgroup: ns.Cgroup,
|
||||
IPC: ns.IPC,
|
||||
MNT: ns.MNT,
|
||||
NET: ns.NET,
|
||||
PIDNS: ns.PID,
|
||||
User: ns.User,
|
||||
UTS: ns.UTS,
|
||||
}
|
||||
psOutput = append(psOutput, params)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getNamespaces(pid int) namespace {
|
||||
ctrPID := strconv.Itoa(pid)
|
||||
cgroup, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
|
||||
ipc, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
|
||||
mnt, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
|
||||
net, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
|
||||
pidns, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
|
||||
user, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
|
||||
uts, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
|
||||
|
||||
return namespace{
|
||||
PID: ctrPID,
|
||||
Cgroup: cgroup,
|
||||
IPC: ipc,
|
||||
MNT: mnt,
|
||||
NET: net,
|
||||
PIDNS: pidns,
|
||||
User: user,
|
||||
UTS: uts,
|
||||
}
|
||||
}
|
||||
|
||||
func getNamespaceInfo(path string) (string, error) {
|
||||
val, err := os.Readlink(path)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "error getting info from %q", path)
|
||||
}
|
||||
return getStrFromSquareBrackets(val), nil
|
||||
}
|
||||
|
||||
// getJSONOutput returns the container info in its raw form
|
||||
func getJSONOutput(containers []*libkpod.ContainerData) (psOutput []psJSONParams) {
|
||||
func getJSONOutput(containers []*libkpod.ContainerData, nSpace bool) (psOutput []psJSONParams) {
|
||||
var ns namespace
|
||||
for _, ctr := range containers {
|
||||
if nSpace {
|
||||
ns = getNamespaces(ctr.State.Pid)
|
||||
}
|
||||
|
||||
params := psJSONParams{
|
||||
ID: ctr.ID,
|
||||
Image: ctr.FromImage,
|
||||
ImageID: ctr.FromImageID,
|
||||
Command: getCommand(ctr.ImageCreatedBy),
|
||||
Command: getStrFromSquareBrackets(ctr.ImageCreatedBy),
|
||||
CreatedAt: ctr.State.Created,
|
||||
RunningFor: time.Since(ctr.State.Created),
|
||||
Status: ctr.State.Status,
|
||||
|
@ -309,6 +386,7 @@ func getJSONOutput(containers []*libkpod.ContainerData) (psOutput []psJSONParams
|
|||
Labels: ctr.Labels,
|
||||
Mounts: ctr.Mounts,
|
||||
ContainerRunning: ctr.State.Status == runningState,
|
||||
Namespaces: ns,
|
||||
}
|
||||
psOutput = append(psOutput, params)
|
||||
}
|
||||
|
@ -325,7 +403,7 @@ func generatePsOutput(containers []*libkpod.ContainerData, server *libkpod.Conta
|
|||
|
||||
switch opts.format {
|
||||
case formats.JSONString:
|
||||
psOutput := getJSONOutput(containersOutput)
|
||||
psOutput := getJSONOutput(containersOutput, opts.namespace)
|
||||
out = formats.JSONStructArray{Output: psToGeneric([]psTemplateParams{}, psOutput)}
|
||||
default:
|
||||
psOutput := getTemplateOutput(containersOutput, opts)
|
||||
|
@ -335,8 +413,8 @@ func generatePsOutput(containers []*libkpod.ContainerData, server *libkpod.Conta
|
|||
return formats.Writer(out).Out()
|
||||
}
|
||||
|
||||
// getCommand gets the actual command from the whole command
|
||||
func getCommand(cmd string) string {
|
||||
// getStrFromSquareBrackets gets the string inside [] from a string
|
||||
func getStrFromSquareBrackets(cmd string) string {
|
||||
reg, err := regexp.Compile(".*\\[|\\].*")
|
||||
if err != nil {
|
||||
return ""
|
||||
|
|
|
@ -361,6 +361,7 @@ _kpod_ps() {
|
|||
--no-trunc
|
||||
--quiet -q
|
||||
--size -s
|
||||
--namespace --ns
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
|
|
@ -69,6 +69,9 @@ Valid placeholders for the Go template are listed below:
|
|||
**--latest, -l**
|
||||
show the latest container created (all states)
|
||||
|
||||
**--namespace, --ns**
|
||||
Display namespace information
|
||||
|
||||
**--filter, -f**
|
||||
Filter output based on conditions given
|
||||
|
||||
|
@ -108,6 +111,14 @@ sudo kpod ps -a --format "{{.ID}} {{.Image}} {{.Labels}} {{.Mounts}}"
|
|||
69ed779d8ef9f redis:alpine batch=no,type=small proc,tmpfs,devpts,shm,mqueue,sysfs,cgroup,/var/run/,/var/run/
|
||||
```
|
||||
|
||||
```
|
||||
sudo kpod ps --ns -a
|
||||
CONTAINER ID NAMES PID CGROUP IPC MNT NET PIDNS USER UTS
|
||||
3557d882a82e3 k8s_container2_podsandbox1_redhat.test.crio_redhat-test-crio_1 29910 4026531835 4026532585 4026532593 4026532508 4026532595 4026531837 4026532594
|
||||
09564cdae0bec k8s_container1_podsandbox1_redhat.test.crio_redhat-test-crio_1 29851 4026531835 4026532585 4026532590 4026532508 4026532592 4026531837 4026532591
|
||||
a31ebbee9cee7 k8s_podsandbox1-redis_podsandbox1_redhat.test.crio_redhat-test-crio_0 29717 4026531835 4026532585 4026532587 4026532508 4026532589 4026531837 4026532588
|
||||
```
|
||||
|
||||
## ps
|
||||
Print a list of containers
|
||||
|
||||
|
|
|
@ -179,6 +179,30 @@ KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT ${STORAGE_OPTS}"
|
|||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "kpod ps namespace flag" {
|
||||
start_crio
|
||||
[ "$status" -eq 0 ]
|
||||
run crioctl pod run --config "$TESTDATA"/sandbox_config.json
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
pod_id="$output"
|
||||
run crioctl image pull "$IMAGE"
|
||||
[ "$status" -eq 0 ]
|
||||
run crioctl ctr create --config "$TESTDATA"/container_config.json --pod "$pod_id"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps -a --ns
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps --all --namespace
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
cleanup_ctrs
|
||||
cleanup_pods
|
||||
stop_crio
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "kpod ps format flag = json" {
|
||||
start_crio
|
||||
[ "$status" -eq 0 ]
|
||||
|
@ -191,7 +215,7 @@ KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT ${STORAGE_OPTS}"
|
|||
run crioctl ctr create --config "$TESTDATA"/container_config.json --pod "$pod_id"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} ps -a --format json | python -m json.tool"
|
||||
run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} ps -a --ns --format json | python -m json.tool"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
cleanup_ctrs
|
||||
|
|
Loading…
Reference in a new issue