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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -21,15 +23,16 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type psOptions struct {
|
type psOptions struct {
|
||||||
all bool
|
all bool
|
||||||
filter string
|
filter string
|
||||||
format string
|
format string
|
||||||
last int
|
last int
|
||||||
latest bool
|
latest bool
|
||||||
noTrunc bool
|
noTrunc bool
|
||||||
quiet bool
|
quiet bool
|
||||||
size bool
|
size bool
|
||||||
label string
|
label string
|
||||||
|
namespace bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type psTemplateParams struct {
|
type psTemplateParams struct {
|
||||||
|
@ -44,6 +47,14 @@ type psTemplateParams struct {
|
||||||
Names string
|
Names string
|
||||||
Labels string
|
Labels string
|
||||||
Mounts 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,
|
// psJSONParams is only used when the JSON format is specified,
|
||||||
|
@ -64,6 +75,18 @@ type psJSONParams struct {
|
||||||
Labels fields.Set `json:"labels"`
|
Labels fields.Set `json:"labels"`
|
||||||
Mounts []specs.Mount `json:"mounts"`
|
Mounts []specs.Mount `json:"mounts"`
|
||||||
ContainerRunning bool `json:"ctrRunning"`
|
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"
|
const runningState = "running"
|
||||||
|
@ -103,6 +126,10 @@ var (
|
||||||
Name: "size, s",
|
Name: "size, s",
|
||||||
Usage: "Display the total file sizes",
|
Usage: "Display the total file sizes",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "namespace, ns",
|
||||||
|
Usage: "Display namespace information",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
psDescription = "Prints out information about the containers"
|
psDescription = "Prints out information about the containers"
|
||||||
psCommand = cli.Command{
|
psCommand = cli.Command{
|
||||||
|
@ -132,20 +159,21 @@ func psCmd(c *cli.Context) error {
|
||||||
return errors.Errorf("too many arguments, ps takes no arguments")
|
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") {
|
if c.IsSet("format") {
|
||||||
format = c.String("format")
|
format = c.String("format")
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := psOptions{
|
opts := psOptions{
|
||||||
all: c.Bool("all"),
|
all: c.Bool("all"),
|
||||||
filter: c.String("filter"),
|
filter: c.String("filter"),
|
||||||
format: format,
|
format: format,
|
||||||
last: c.Int("last"),
|
last: c.Int("last"),
|
||||||
latest: c.Bool("latest"),
|
latest: c.Bool("latest"),
|
||||||
noTrunc: c.Bool("no-trunc"),
|
noTrunc: c.Bool("no-trunc"),
|
||||||
quiet: c.Bool("quiet"),
|
quiet: c.Bool("quiet"),
|
||||||
size: c.Bool("size"),
|
size: c.Bool("size"),
|
||||||
|
namespace: c.Bool("namespace"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// all, latest, and last are mutually exclusive. Only one flag can be used at a time
|
// 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
|
// generate the template based on conditions given
|
||||||
func genPsFormat(quiet, size bool) (format string) {
|
func genPsFormat(quiet, size, namespace bool) (format string) {
|
||||||
if quiet {
|
if quiet {
|
||||||
return formats.IDString
|
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"
|
format = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.CreatedAt}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t"
|
||||||
if size {
|
if size {
|
||||||
format += "{{.Size}}\t"
|
format += "{{.Size}}\t"
|
||||||
|
@ -253,13 +285,15 @@ func getTemplateOutput(containers []*libkpod.ContainerData, opts psOptions) (psO
|
||||||
ctrID := ctr.ID
|
ctrID := ctr.ID
|
||||||
runningFor := units.HumanDuration(time.Since(ctr.State.Created))
|
runningFor := units.HumanDuration(time.Since(ctr.State.Created))
|
||||||
createdAt := runningFor + " ago"
|
createdAt := runningFor + " ago"
|
||||||
command := getCommand(ctr.ImageCreatedBy)
|
command := getStrFromSquareBrackets(ctr.ImageCreatedBy)
|
||||||
imageName := ctr.FromImage
|
imageName := ctr.FromImage
|
||||||
mounts := getMounts(ctr.Mounts, opts.noTrunc)
|
mounts := getMounts(ctr.Mounts, opts.noTrunc)
|
||||||
ports := getPorts(ctr.Config.ExposedPorts)
|
ports := getPorts(ctr.Config.ExposedPorts)
|
||||||
size := units.HumanSize(float64(ctr.SizeRootFs))
|
size := units.HumanSize(float64(ctr.SizeRootFs))
|
||||||
labels := getLabels(ctr.Labels)
|
labels := getLabels(ctr.Labels)
|
||||||
|
|
||||||
|
ns := getNamespaces(ctr.State.Pid)
|
||||||
|
|
||||||
switch ctr.State.Status {
|
switch ctr.State.Status {
|
||||||
case "stopped":
|
case "stopped":
|
||||||
status = "Exited (" + strconv.FormatInt(int64(ctr.State.ExitCode), 10) + ") " + runningFor + " ago"
|
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,
|
Names: ctr.Name,
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
Mounts: mounts,
|
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)
|
psOutput = append(psOutput, params)
|
||||||
}
|
}
|
||||||
return
|
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
|
// 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 {
|
for _, ctr := range containers {
|
||||||
|
if nSpace {
|
||||||
|
ns = getNamespaces(ctr.State.Pid)
|
||||||
|
}
|
||||||
|
|
||||||
params := psJSONParams{
|
params := psJSONParams{
|
||||||
ID: ctr.ID,
|
ID: ctr.ID,
|
||||||
Image: ctr.FromImage,
|
Image: ctr.FromImage,
|
||||||
ImageID: ctr.FromImageID,
|
ImageID: ctr.FromImageID,
|
||||||
Command: getCommand(ctr.ImageCreatedBy),
|
Command: getStrFromSquareBrackets(ctr.ImageCreatedBy),
|
||||||
CreatedAt: ctr.State.Created,
|
CreatedAt: ctr.State.Created,
|
||||||
RunningFor: time.Since(ctr.State.Created),
|
RunningFor: time.Since(ctr.State.Created),
|
||||||
Status: ctr.State.Status,
|
Status: ctr.State.Status,
|
||||||
|
@ -309,6 +386,7 @@ func getJSONOutput(containers []*libkpod.ContainerData) (psOutput []psJSONParams
|
||||||
Labels: ctr.Labels,
|
Labels: ctr.Labels,
|
||||||
Mounts: ctr.Mounts,
|
Mounts: ctr.Mounts,
|
||||||
ContainerRunning: ctr.State.Status == runningState,
|
ContainerRunning: ctr.State.Status == runningState,
|
||||||
|
Namespaces: ns,
|
||||||
}
|
}
|
||||||
psOutput = append(psOutput, params)
|
psOutput = append(psOutput, params)
|
||||||
}
|
}
|
||||||
|
@ -325,7 +403,7 @@ func generatePsOutput(containers []*libkpod.ContainerData, server *libkpod.Conta
|
||||||
|
|
||||||
switch opts.format {
|
switch opts.format {
|
||||||
case formats.JSONString:
|
case formats.JSONString:
|
||||||
psOutput := getJSONOutput(containersOutput)
|
psOutput := getJSONOutput(containersOutput, opts.namespace)
|
||||||
out = formats.JSONStructArray{Output: psToGeneric([]psTemplateParams{}, psOutput)}
|
out = formats.JSONStructArray{Output: psToGeneric([]psTemplateParams{}, psOutput)}
|
||||||
default:
|
default:
|
||||||
psOutput := getTemplateOutput(containersOutput, opts)
|
psOutput := getTemplateOutput(containersOutput, opts)
|
||||||
|
@ -335,8 +413,8 @@ func generatePsOutput(containers []*libkpod.ContainerData, server *libkpod.Conta
|
||||||
return formats.Writer(out).Out()
|
return formats.Writer(out).Out()
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCommand gets the actual command from the whole command
|
// getStrFromSquareBrackets gets the string inside [] from a string
|
||||||
func getCommand(cmd string) string {
|
func getStrFromSquareBrackets(cmd string) string {
|
||||||
reg, err := regexp.Compile(".*\\[|\\].*")
|
reg, err := regexp.Compile(".*\\[|\\].*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -361,6 +361,7 @@ _kpod_ps() {
|
||||||
--no-trunc
|
--no-trunc
|
||||||
--quiet -q
|
--quiet -q
|
||||||
--size -s
|
--size -s
|
||||||
|
--namespace --ns
|
||||||
"
|
"
|
||||||
_complete_ "$options_with_args" "$boolean_options"
|
_complete_ "$options_with_args" "$boolean_options"
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,9 @@ Valid placeholders for the Go template are listed below:
|
||||||
**--latest, -l**
|
**--latest, -l**
|
||||||
show the latest container created (all states)
|
show the latest container created (all states)
|
||||||
|
|
||||||
|
**--namespace, --ns**
|
||||||
|
Display namespace information
|
||||||
|
|
||||||
**--filter, -f**
|
**--filter, -f**
|
||||||
Filter output based on conditions given
|
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/
|
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
|
## ps
|
||||||
Print a list of containers
|
Print a list of containers
|
||||||
|
|
||||||
|
|
|
@ -179,6 +179,30 @@ KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT ${STORAGE_OPTS}"
|
||||||
[ "$status" -eq 0 ]
|
[ "$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" {
|
@test "kpod ps format flag = json" {
|
||||||
start_crio
|
start_crio
|
||||||
[ "$status" -eq 0 ]
|
[ "$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"
|
run crioctl ctr create --config "$TESTDATA"/container_config.json --pod "$pod_id"
|
||||||
echo "$output"
|
echo "$output"
|
||||||
[ "$status" -eq 0 ]
|
[ "$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"
|
echo "$output"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
cleanup_ctrs
|
cleanup_ctrs
|
||||||
|
|
Loading…
Reference in a new issue