Add 'kpod ps' command

kpod ps lists the containers currently stored

Displays the list of containers

Signed-off-by: umohnani8 <umohnani@redhat.com>
This commit is contained in:
umohnani8 2017-08-08 09:24:58 -04:00
parent c67859731f
commit 35ca80abe6
10 changed files with 1001 additions and 24 deletions

View file

@ -3,16 +3,21 @@ package formats
import (
"encoding/json"
"fmt"
"github.com/ghodss/yaml"
"os"
"strings"
"text/tabwriter"
"text/template"
"github.com/ghodss/yaml"
"github.com/pkg/errors"
)
// JSONString const to save on duplicate variable names
const JSONString string = "json"
const (
// JSONString const to save on duplicate variable names
JSONString = "json"
// IDString const to save on duplicates for Go templates
IDString = "{{.ID}}"
)
// Writer interface for outputs
type Writer interface {
@ -60,33 +65,34 @@ func (j JSONStructArray) Out() error {
// Out method for Go templates
func (t StdoutTemplateArray) Out() error {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
if strings.HasPrefix(t.Template, "table") {
t.Template = strings.TrimSpace(t.Template[5:])
// replace any spaces with tabs in template so that tabwriter can align it
t.Template = strings.Replace(strings.TrimSpace(t.Template[5:]), " ", "\t", -1)
headerTmpl, err := template.New("header").Funcs(headerFunctions).Parse(t.Template)
if err != nil {
return errors.Wrapf(err, "Template parsing error")
}
err = headerTmpl.Execute(os.Stdout, t.Fields)
err = headerTmpl.Execute(w, t.Fields)
if err != nil {
return err
}
fmt.Println()
fmt.Fprintln(w, "")
}
t.Template = strings.Replace(t.Template, " ", "\t", -1)
tmpl, err := template.New("image").Funcs(basicFunctions).Parse(t.Template)
if err != nil {
return errors.Wrapf(err, "Template parsing error")
}
for _, img := range t.Output {
basicTmpl := tmpl.Funcs(basicFunctions)
err = basicTmpl.Execute(os.Stdout, img)
err = basicTmpl.Execute(w, img)
if err != nil {
return err
}
fmt.Println()
fmt.Fprintln(w, "")
}
return nil
return w.Flush()
}
// Out method for JSON struct

View file

@ -124,7 +124,7 @@ func historyCmd(c *cli.Context) error {
func genHistoryFormat(quiet, truncate, human bool) (format string) {
if quiet {
return "{{.ID}}"
return formats.IDString
}
if truncate {

View file

@ -1,7 +1,6 @@
package main
import (
"fmt"
"reflect"
"strings"
@ -110,7 +109,7 @@ func imagesCmd(c *cli.Context) error {
func genImagesFormat(quiet, truncate, digests bool) (format string) {
if quiet {
return "{{.ID}}"
return formats.IDString
}
if truncate {
format = "table {{ .ID | printf \"%-20.12s\" }} "
@ -197,7 +196,7 @@ func (i *imageOutputParams) headerMap() map[string]string {
if value == "ID" || value == "Name" {
value = "Image" + value
}
values[key] = fmt.Sprintf("%s ", strings.ToUpper(splitCamelCase(value)))
values[key] = strings.ToUpper(splitCamelCase(value))
}
return values
}

View file

@ -31,6 +31,7 @@ func main() {
loadCommand,
logsCommand,
mountCommand,
psCommand,
pullCommand,
pushCommand,
renameCommand,

View file

@ -52,7 +52,7 @@ type jsonMountPoint struct {
func mountCmd(c *cli.Context) error {
formats := map[string]bool{
"": true,
"json": true,
of.JSONString: true,
}
args := c.Args()

547
cmd/kpod/ps.go Normal file
View file

@ -0,0 +1,547 @@
package main
import (
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"github.com/docker/go-units"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/fields"
"github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
"github.com/kubernetes-incubator/cri-o/libkpod"
"github.com/kubernetes-incubator/cri-o/oci"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
type psOptions struct {
all bool
filter string
format string
last int
latest bool
noTrunc bool
quiet bool
size bool
label string
}
type psOutputParams struct {
ID string `json:"id"`
Image string `json:"image"`
Command string `json:"command"`
CreatedAt string `json:"created"`
RunningFor string `json:"running"`
Status string `json:"status"`
Ports string `json:"ports"`
Size string `json:"size"`
Names string `json:"names"`
Labels string `json:"labels"`
Mounts string `json:"mounts"`
}
const runningState = "running"
var (
psFlags = []cli.Flag{
cli.BoolFlag{
Name: "all, a",
Usage: "Show all the containers, default is only running containers",
},
cli.StringFlag{
Name: "filter, f",
Usage: "Filter output based on conditions given",
},
cli.StringFlag{
Name: "format",
Usage: "Pretty-print containers to JSON or using a Go template",
},
cli.IntFlag{
Name: "last, n",
Usage: "Print the n last created containers (all states)",
},
cli.BoolFlag{
Name: "latest, l",
Usage: "Show the latest container created (all states)",
},
cli.BoolFlag{
Name: "no-trunc",
Usage: "Display the extended information",
},
cli.BoolFlag{
Name: "quiet, q",
Usage: "Print the numeric IDs of the containers only",
},
cli.BoolFlag{
Name: "size, s",
Usage: "Display the total file sizes",
},
}
psDescription = "Prints out information about the containers"
psCommand = cli.Command{
Name: "ps",
Usage: "List containers",
Description: psDescription,
Flags: psFlags,
Action: psCmd,
ArgsUsage: "",
}
)
func psCmd(c *cli.Context) error {
config, err := getConfig(c)
if err != nil {
return errors.Wrapf(err, "could not get config")
}
server, err := libkpod.New(config)
if err != nil {
return errors.Wrapf(err, "error creating server")
}
if err := server.Update(); err != nil {
return errors.Wrapf(err, "error updating list of containers")
}
if len(c.Args()) > 0 {
return errors.Errorf("too many arguments, ps takes no arguments")
}
format := genPsFormat(c.Bool("quiet"), c.Bool("size"))
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, latest, and last are mutually exclusive. Only one flag can be used at a time
exclusiveOpts := 0
if opts.last > 0 {
exclusiveOpts++
}
if opts.latest {
exclusiveOpts++
}
if opts.all {
exclusiveOpts++
}
if exclusiveOpts > 1 {
return errors.Errorf("Last, latest and all are mutually exclusive")
}
containers, err := server.ListContainers()
if err != nil {
return errors.Wrapf(err, "error getting containers from server")
}
var params *FilterParamsPS
if opts.filter != "" {
params, err = parseFilter(opts.filter, containers)
if err != nil {
return errors.Wrapf(err, "error parsing filter")
}
} else {
params = nil
}
containerList := getContainersMatchingFilter(containers, params, server)
return psOutput(containerList, server, opts)
}
// generate the template based on conditions given
func genPsFormat(quiet, size bool) (format string) {
if quiet {
return formats.IDString
}
format = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.CreatedAt}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t"
if size {
format += "{{.Size}}\t"
}
return
}
func psToGeneric(params []psOutputParams) []interface{} {
genericParams := make([]interface{}, len(params))
for i, v := range params {
genericParams[i] = interface{}(v)
}
return genericParams
}
// generate the accurate header based on template given
func (p *psOutputParams) headerMap() map[string]string {
v := reflect.Indirect(reflect.ValueOf(p))
values := make(map[string]string)
for i := 0; i < v.NumField(); i++ {
key := v.Type().Field(i).Name
value := key
if value == "ID" {
value = "Container" + value
}
values[key] = strings.ToUpper(splitCamelCase(value))
}
return values
}
// getContainers gets the containers that match the flags given
func getContainers(containers []*libkpod.ContainerData, opts psOptions) []*libkpod.ContainerData {
var containersOutput []*libkpod.ContainerData
if opts.last > 0 && opts.last < len(containers) {
for i := 0; i < opts.last; i++ {
containersOutput = append(containersOutput, containers[i])
}
return containersOutput
}
if opts.latest {
return []*libkpod.ContainerData{containers[0]}
}
if opts.all || opts.last >= len(containers) {
return containers
}
for _, ctr := range containers {
if ctr.State.Status == runningState {
containersOutput = append(containersOutput, ctr)
}
}
return containersOutput
}
func psOutput(containers []*libkpod.ContainerData, server *libkpod.ContainerServer, opts psOptions) error {
var (
output []psOutputParams
containersOutput []*libkpod.ContainerData
status string
ctrID string
command string
runningFor string
imageName string
mounts string
ports string
size string
labels string
createdAt string
)
if len(containers) == 0 {
fmt.Println("hereee")
return nil
}
containersOutput = getContainers(containers, opts)
for _, ctr := range containersOutput {
ctrID = ctr.ID
runningFor = units.HumanDuration(time.Since(ctr.State.Created))
createdAt = runningFor + " ago"
command = getCommand(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)
switch ctr.State.Status {
case "stopped":
status = "Exited (" + strconv.FormatInt(int64(ctr.State.ExitCode), 10) + ") " + runningFor + " ago"
case runningState:
status = "Up " + runningFor + " ago"
default:
status = "Created"
}
if !opts.noTrunc {
ctrID = ctr.ID[:idTruncLength]
imageName = getImageName(ctr.FromImage)
}
params := psOutputParams{
ID: ctrID,
Image: imageName,
Command: command,
CreatedAt: createdAt,
RunningFor: runningFor,
Status: status,
Ports: ports,
Size: size,
Names: ctr.Name,
Labels: labels,
Mounts: mounts,
}
output = append(output, params)
}
if len(output) == 0 {
return nil
}
var out formats.Writer
switch opts.format {
case formats.JSONString:
out = formats.JSONStructArray{Output: psToGeneric(output)}
default:
out = formats.StdoutTemplateArray{Output: psToGeneric(output), Template: opts.format, Fields: output[0].headerMap()}
}
return formats.Writer(out).Out()
}
// getCommand gets the actual command from the whole command
func getCommand(cmd string) string {
reg, err := regexp.Compile(".*\\[|\\].*")
if err != nil {
return ""
}
arr := strings.Split(reg.ReplaceAllLiteralString(cmd, ""), ",")
return strings.Join(arr, ",")
}
// getImageName shortens the image name
func getImageName(img string) string {
arr := strings.Split(img, "/")
if arr[0] == "docker.io" && arr[1] == "library" {
img = strings.Join(arr[2:], "/")
} else if arr[0] == "docker.io" {
img = strings.Join(arr[1:], "/")
}
return img
}
// getLabels converts the labels to a string of the form "key=value, key2=value2"
func getLabels(labels fields.Set) string {
var arr []string
if len(labels) > 0 {
for key, val := range labels {
temp := key + "=" + val
arr = append(arr, temp)
}
return strings.Join(arr, ",")
}
return ""
}
// getMounts converts the volumes mounted to a string of the form "mount1, mount2"
// it truncates it if noTrunc is false
func getMounts(mounts []specs.Mount, noTrunc bool) string {
var arr []string
if len(mounts) == 0 {
return ""
}
for _, mount := range mounts {
if noTrunc {
arr = append(arr, mount.Source)
continue
}
tempArr := strings.SplitAfter(mount.Source, "/")
if len(tempArr) >= 3 {
arr = append(arr, strings.Join(tempArr[:3], ""))
} else {
arr = append(arr, mount.Source)
}
}
return strings.Join(arr, ",")
}
// getPorts converts the ports used to a string of the from "port1, port2"
func getPorts(ports map[string]struct{}) string {
var arr []string
if len(ports) == 0 {
return ""
}
for key := range ports {
arr = append(arr, key)
}
return strings.Join(arr, ",")
}
// FilterParamsPS contains the filter options for ps
type FilterParamsPS struct {
id string
label string
name string
exited int32
status string
ancestor string
before time.Time
since time.Time
volume string
}
// parseFilter takes a filter string and a list of containers and filters it
func parseFilter(filter string, containers []*oci.Container) (*FilterParamsPS, error) {
params := new(FilterParamsPS)
allFilters := strings.Split(filter, ",")
for _, param := range allFilters {
pair := strings.SplitN(param, "=", 2)
switch strings.TrimSpace(pair[0]) {
case "id":
params.id = pair[1]
case "label":
params.label = pair[1]
case "name":
params.name = pair[1]
case "exited":
exitedCode, err := strconv.ParseInt(pair[1], 10, 32)
if err != nil {
return nil, errors.Errorf("exited code out of range %q", pair[1])
}
params.exited = int32(exitedCode)
case "status":
params.status = pair[1]
case "ancestor":
params.ancestor = pair[1]
case "before":
if ctr, err := findContainer(containers, pair[1]); err == nil {
params.before = ctr.CreatedAt()
} else {
return nil, errors.Wrapf(err, "no such container %q", pair[1])
}
case "since":
if ctr, err := findContainer(containers, pair[1]); err == nil {
params.before = ctr.CreatedAt()
} else {
return nil, errors.Wrapf(err, "no such container %q", pair[1])
}
case "volume":
params.volume = pair[1]
default:
return nil, errors.Errorf("invalid filter %q", pair[0])
}
}
return params, nil
}
// findContainer finds a container with a specific name or id from a list of containers
func findContainer(containers []*oci.Container, ref string) (*oci.Container, error) {
for _, ctr := range containers {
if strings.HasPrefix(ctr.ID(), ref) || ctr.Name() == ref {
return ctr, nil
}
}
return nil, errors.Errorf("could not find container")
}
// matchesFilter checks if a container matches all the filter parameters
func matchesFilter(ctrData *libkpod.ContainerData, params *FilterParamsPS) bool {
if params == nil {
return true
}
if params.id != "" && !matchesID(ctrData, params.id) {
return false
}
if params.name != "" && !matchesName(ctrData, params.name) {
return false
}
if !params.before.IsZero() && !matchesBeforeContainer(ctrData, params.before) {
return false
}
if !params.since.IsZero() && !matchesSinceContainer(ctrData, params.since) {
return false
}
if params.exited > 0 && !matchesExited(ctrData, params.exited) {
return false
}
if params.status != "" && !matchesStatus(ctrData, params.status) {
return false
}
if params.ancestor != "" && !matchesAncestor(ctrData, params.ancestor) {
return false
}
if params.label != "" && !matchesLabel(ctrData, params.label) {
return false
}
if params.volume != "" && !matchesVolume(ctrData, params.volume) {
return false
}
return true
}
// GetContainersMatchingFilter returns a slice of all the containers that match the provided filter parameters
func getContainersMatchingFilter(containers []*oci.Container, filter *FilterParamsPS, server *libkpod.ContainerServer) []*libkpod.ContainerData {
var filteredCtrs []*libkpod.ContainerData
for _, ctr := range containers {
ctrData, err := server.GetContainerData(ctr.ID(), true)
if err != nil {
logrus.Warn("unable to get container data for matched container")
}
if filter == nil || matchesFilter(ctrData, filter) {
filteredCtrs = append(filteredCtrs, ctrData)
}
}
return filteredCtrs
}
// matchesID returns true if the id's match
func matchesID(ctrData *libkpod.ContainerData, id string) bool {
return strings.HasPrefix(ctrData.ID, id)
}
// matchesBeforeContainer returns true if the container was created before the filter image
func matchesBeforeContainer(ctrData *libkpod.ContainerData, beforeTime time.Time) bool {
return ctrData.State.Created.Before(beforeTime)
}
// matchesSincecontainer returns true if the container was created since the filter image
func matchesSinceContainer(ctrData *libkpod.ContainerData, sinceTime time.Time) bool {
return ctrData.State.Created.After(sinceTime)
}
// matchesLabel returns true if the container label matches that of the filter label
func matchesLabel(ctrData *libkpod.ContainerData, label string) bool {
pair := strings.SplitN(label, "=", 2)
if val, ok := ctrData.Labels[pair[0]]; ok {
if len(pair) == 2 && val == pair[1] {
return true
}
if len(pair) == 1 {
return true
}
return false
}
return false
}
// matchesName returns true if the names are identical
func matchesName(ctrData *libkpod.ContainerData, name string) bool {
return ctrData.Name == name
}
// matchesExited returns true if the exit codes are identical
func matchesExited(ctrData *libkpod.ContainerData, exited int32) bool {
return ctrData.State.ExitCode == exited
}
// matchesStatus returns true if the container status matches that of filter status
func matchesStatus(ctrData *libkpod.ContainerData, status string) bool {
return ctrData.State.Status == status
}
// matchesAncestor returns true if filter ancestor is in container image name
func matchesAncestor(ctrData *libkpod.ContainerData, ancestor string) bool {
return strings.Contains(ctrData.FromImage, ancestor)
}
// matchesVolue returns true if the volume mounted or path to volue of the container matches that of filter volume
func matchesVolume(ctrData *libkpod.ContainerData, volume string) bool {
for _, vol := range ctrData.Mounts {
if strings.Contains(vol.Source, volume) {
return true
}
}
return false
}

View file

@ -327,6 +327,22 @@ _kpod_export() {
_complete_ "$options_with_args" "$boolean_options"
}
_kpod_ps() {
local options_with_args="
--filter -f
--format
--last -n
"
local boolean_options="
--all -a
--latest -l
--no-trunc
--quiet -q
--size -s
"
_complete_ "$options_with_args" "$boolean_options"
}
_complete_() {
local options_with_args=$1
local boolean_options="$2 -h --help"
@ -377,6 +393,7 @@ _kpod_kpod() {
load
logs
mount
ps
pull
push
rename

View file

@ -18,10 +18,11 @@ The **--quiet** flag displays the ID of the image only when set and the **--form
flag is used to print the information using the Go template provided by the user.
Valid placeholders for the Go template are listed below:
| **Placeholder** | **Description** |
|-----------------|------------------------------------------------------------------------------|
| --------------- | ----------------------------------------------------------------------------- |
| .ID | Image ID |
| .Created | if **--human**, time elapsed since creation, otherwise time stamp of creation|
| .Created | if **--human**, time elapsed since creation, otherwise time stamp of creation |
| .CreatedBy | Command used to create the layer |
| .Size | Size of layer on disk |
| .Comment | Comment for the layer |

119
docs/kpod-ps.1.md Normal file
View file

@ -0,0 +1,119 @@
% kpod(1) kpod-ps - Simple tool to list containers
% Urvashi Mohnani
% kpod-ps "1" "AUGUST 2017" "kpod"
## NAME
kpod-ps - Prints out information about containers
## SYNOPSIS
**kpod ps [OPTIONS] CONTAINER**
## DESCRIPTION
**kpod ps** lists the running containers on the system. Use the **--all** flag to view
all the containers information. By default it lists:
* container id
* the name of the image the container is using
* the COMMAND the container is executing
* the time the container was created
* the status of the container
* port mappings the container is using
* alternative names for the container
**kpod [GLOBAL OPTIONS]**
**kpod [GLOBAL OPTIONS] ps [OPTIONS]**
## GLOBAL OPTIONS
**--help, -h**
Print usage statement
## OPTIONS
**--all, -a**
Show all the containers, default is only running containers
**--no-trunc**
Display the extended information
**--quiet, -q**
Print the numeric IDs of the containers only
**--format**
Pretty-print containers to JSON or using a Go template
Valid placeholders for the Go template are listed below:
| **Placeholder** | **Description** |
| --------------- | ------------------------------------------------ |
| .ID | Container ID |
| .Image | Image ID/Name |
| .Command | Quoted command used |
| .CreatedAt | Creation time for container |
| .RunningFor | Time elapsed since container was started |
| .Status | Status of container |
| .Ports | Exposed ports |
| .Size | Size of container |
| .Names | Name of container |
| .Labels | All the labels assigned to the container |
| .Label | Value of the specific label provided by the user |
| .Mounts | Volumes mounted in the container |
**--size, -s**
Display the total file size
**--last, -n**
Print the n last created containers (all states)
**--latest, -l**
show the latest container created (all states)
**--filter, -f**
Filter output based on conditions given
Valid filters are listed below:
| **Filter** | **Description** |
| --------------- | ------------------------------------------------------------------- |
| id | [ID] Container's ID |
| name | [Name] Container's name |
| label | [Key] or [Key=Value] Label assigned to a container |
| exited | [Int] Container's exit code |
| status | [Status] Container's status, e.g *running*, *stopped* |
| ancestor | [ImageName] Image or descendant used to create container |
| before | [ID] or [Name] Containers created before this container |
| since | [ID] or [Name] Containers created since this container |
| volume | [VolumeName] or [MountpointDestination] Volume mounted in container |
## COMMANDS
```
sudo kpod ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
02f65160e14ca redis:alpine "redis-server" 19 hours ago Exited (-1) 19 hours ago 6379/tcp k8s_podsandbox1-redis_podsandbox1_redhat.test.crio_redhat-test-crio_0
69ed779d8ef9f redis:alpine "redis-server" 25 hours ago Created 6379/tcp k8s_container1_podsandbox1_redhat.test.crio_redhat-test-crio_1
```
```
sudo kpod ps -a -s
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
02f65160e14ca redis:alpine "redis-server" 20 hours ago Exited (-1) 20 hours ago 6379/tcp k8s_podsandbox1-redis_podsandbox1_redhat.test.crio_redhat-test-crio_0 27.49 MB
69ed779d8ef9f redis:alpine "redis-server" 25 hours ago Created 6379/tcp k8s_container1_podsandbox1_redhat.test.crio_redhat-test-crio_1 27.49 MB
```
```
sudo kpod ps -a --format "{{.ID}} {{.Image}} {{.Labels}} {{.Mounts}}"
02f65160e14ca redis:alpine tier=backend 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/
```
## ps
Print a list of containers
## SEE ALSO
kpod(1), crio(8), crio.conf(5)
## HISTORY
August 2017, Originally compiled by Urvashi Mohnani <umohnani@redhat.com>

287
test/kpod_ps.bats Normal file
View file

@ -0,0 +1,287 @@
#!/usr/bin/env bats
load helpers
IMAGE="redis:alpine"
ROOT="$TESTDIR/crio"
RUNROOT="$TESTDIR/crio-run"
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT ${STORAGE_OPTS}"
@test "kpod ps with no containers" {
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps
echo "$output"
[ "$status" -eq 0 ]
}
@test "kpod ps default" {
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 ]
ctr_id="$output"
run crioctl ctr start --id "$ctr_id"
echo "$output"
[ "$status" -eq 0 ]
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps all 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
echo "$output"
[ "$status" -eq 0 ]
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps --all
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps size 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 -s
echo "$output"
[ "$status" -eq 0 ]
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps -a --size
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps quiet 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 -q
echo "$output"
[ "$status" -eq 0 ]
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps -a --quiet
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps latest 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 --latest
echo "$output"
[ "$status" -eq 0 ]
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps -l
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps last 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 --last 2
echo "$output"
[ "$status" -eq 0 ]
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps -n 2
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps no-trunc 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 --no-trunc
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 ]
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 bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} ps -a --format json | python -m json.tool"
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps format flag = go template" {
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 --format "table {{.ID}} {{.Image}} {{.Labels}}"
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps filter flag - ancestor" {
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 --filter ancestor=${IMAGE}
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps filter flag - id" {
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 ]
ctr_id="$output"
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps -a --filter id="$ctr_id"
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}
@test "kpod ps filter flag - status" {
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 ]
ctr_id="$output"
run ${KPOD_BINARY} ${KPOD_OPTIONS} ps -a --filter status=running
echo "$output"
[ "$status" -eq 0 ]
cleanup_ctrs
cleanup_pods
stop_crio
[ "$status" -eq 0 ]
}