commit
7af1ae71ed
10 changed files with 1001 additions and 24 deletions
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ func main() {
|
||||||
loadCommand,
|
loadCommand,
|
||||||
logsCommand,
|
logsCommand,
|
||||||
mountCommand,
|
mountCommand,
|
||||||
|
psCommand,
|
||||||
pullCommand,
|
pullCommand,
|
||||||
pushCommand,
|
pushCommand,
|
||||||
renameCommand,
|
renameCommand,
|
||||||
|
|
|
@ -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
547
cmd/kpod/ps.go
Normal 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
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
119
docs/kpod-ps.1.md
Normal 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
287
test/kpod_ps.bats
Normal 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 ]
|
||||||
|
}
|
Loading…
Reference in a new issue