Merge pull request #776 from umohnani8/kpod_ps

Add 'kpod ps' command
This commit is contained in:
Daniel J Walsh 2017-08-23 07:08:31 -04:00 committed by GitHub
commit 7af1ae71ed
10 changed files with 1001 additions and 24 deletions

View file

@ -3,16 +3,21 @@ package formats
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/ghodss/yaml"
"os" "os"
"strings" "strings"
"text/tabwriter"
"text/template" "text/template"
"github.com/ghodss/yaml"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// JSONString const to save on duplicate variable names const (
const JSONString string = "json" // 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 // Writer interface for outputs
type Writer interface { type Writer interface {
@ -60,33 +65,34 @@ func (j JSONStructArray) Out() error {
// Out method for Go templates // Out method for Go templates
func (t StdoutTemplateArray) Out() error { func (t StdoutTemplateArray) Out() error {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
if strings.HasPrefix(t.Template, "table") { 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) headerTmpl, err := template.New("header").Funcs(headerFunctions).Parse(t.Template)
if err != nil { if err != nil {
return errors.Wrapf(err, "Template parsing error") return errors.Wrapf(err, "Template parsing error")
} }
err = headerTmpl.Execute(os.Stdout, t.Fields) err = headerTmpl.Execute(w, t.Fields)
if err != nil { if err != nil {
return err 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) tmpl, err := template.New("image").Funcs(basicFunctions).Parse(t.Template)
if err != nil { if err != nil {
return errors.Wrapf(err, "Template parsing error") return errors.Wrapf(err, "Template parsing error")
} }
for _, img := range t.Output { for _, img := range t.Output {
basicTmpl := tmpl.Funcs(basicFunctions) basicTmpl := tmpl.Funcs(basicFunctions)
err = basicTmpl.Execute(os.Stdout, img) err = basicTmpl.Execute(w, img)
if err != nil { if err != nil {
return err return err
} }
fmt.Println() fmt.Fprintln(w, "")
} }
return nil return w.Flush()
} }
// Out method for JSON struct // 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) { func genHistoryFormat(quiet, truncate, human bool) (format string) {
if quiet { if quiet {
return "{{.ID}}" return formats.IDString
} }
if truncate { if truncate {

View file

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

View file

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

View file

@ -51,8 +51,8 @@ type jsonMountPoint struct {
func mountCmd(c *cli.Context) error { func mountCmd(c *cli.Context) error {
formats := map[string]bool{ formats := map[string]bool{
"": true, "": true,
"json": true, of.JSONString: true,
} }
args := c.Args() 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" _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_() { _complete_() {
local options_with_args=$1 local options_with_args=$1
local boolean_options="$2 -h --help" local boolean_options="$2 -h --help"
@ -377,6 +393,7 @@ _kpod_kpod() {
load load
logs logs
mount mount
ps
pull pull
push push
rename rename

View file

@ -18,13 +18,14 @@ 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. flag is used to print the information using the Go template provided by the user.
Valid placeholders for the Go template are listed below: Valid placeholders for the Go template are listed below:
| **Placeholder** | **Description** |
|-----------------|------------------------------------------------------------------------------| | **Placeholder** | **Description** |
| .ID | Image ID | | --------------- | ----------------------------------------------------------------------------- |
| .Created | if **--human**, time elapsed since creation, otherwise time stamp of creation| | .ID | Image ID |
| .CreatedBy | Command used to create the layer | | .Created | if **--human**, time elapsed since creation, otherwise time stamp of creation |
| .Size | Size of layer on disk | | .CreatedBy | Command used to create the layer |
| .Comment | Comment for the layer | | .Size | Size of layer on disk |
| .Comment | Comment for the layer |
**kpod [GLOBAL OPTIONS]** **kpod [GLOBAL OPTIONS]**

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 ]
}