Merge pull request #1065 from haircommander/pod-start-create-rm

Podman pod create/rm/ps commands with man pages and tests
This commit is contained in:
Daniel J Walsh 2018-07-13 13:57:04 -04:00 committed by GitHub
commit 827359c8e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1802 additions and 1 deletions

View File

@ -71,6 +71,7 @@ func main() {
mountCommand,
pauseCommand,
psCommand,
podCommand,
portCommand,
pullCommand,
pushCommand,

25
cmd/podman/pod.go Normal file
View File

@ -0,0 +1,25 @@
package main
import (
"github.com/urfave/cli"
)
var (
podDescription = `
podman pod
Manage container pods.
Pods are a group of one or more containers sharing the same network, pid and ipc namespaces.
`
podCommand = cli.Command{
Name: "pod",
Usage: "Manage pods",
Description: podDescription,
UseShortOptionHandling: true,
Subcommands: []cli.Command{
podCreateCommand,
podPsCommand,
podRmCommand,
},
}
)

109
cmd/podman/pod_create.go Normal file
View File

@ -0,0 +1,109 @@
package main
import (
"fmt"
"os"
"github.com/pkg/errors"
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
"github.com/projectatomic/libpod/libpod"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
var podCreateDescription = "Creates a new empty pod. The pod ID is then" +
" printed to stdout. You can then start it at any time with the" +
" podman pod start <pod_id> command. The pod will be created with the" +
" initial state 'created'."
var podCreateFlags = []cli.Flag{
cli.StringFlag{
Name: "cgroup-parent",
Usage: "Set parent cgroup for the pod",
},
cli.StringSliceFlag{
Name: "label-file",
Usage: "Read in a line delimited file of labels (default [])",
},
cli.StringSliceFlag{
Name: "label, l",
Usage: "Set metadata on pod (default [])",
},
cli.StringFlag{
Name: "name, n",
Usage: "Assign a name to the pod",
},
cli.StringFlag{
Name: "pod-id-file",
Usage: "Write the pod ID to the file",
},
}
var podCreateCommand = cli.Command{
Name: "create",
Usage: "create a new empty pod",
Description: podCreateDescription,
Flags: podCreateFlags,
Action: podCreateCmd,
SkipArgReorder: true,
UseShortOptionHandling: true,
}
func podCreateCmd(c *cli.Context) error {
var options []libpod.PodCreateOption
var err error
if err = validateFlags(c, createFlags); err != nil {
return err
}
runtime, err := libpodruntime.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
defer runtime.Shutdown(false)
if c.IsSet("pod-id-file") {
if _, err = os.Stat(c.String("pod-id-file")); err == nil {
return errors.Errorf("pod id file exists. ensure another pod is not using it or delete %s", c.String("pod-id-file"))
}
if err = libpod.WriteFile("", c.String("pod-id-file")); err != nil {
return errors.Wrapf(err, "unable to write pod id file %s", c.String("pod-id-file"))
}
}
if c.IsSet("cgroup-parent") {
options = append(options, libpod.WithPodCgroupParent(c.String("cgroup-parent")))
}
labels, err := getAllLabels(c.StringSlice("label-file"), c.StringSlice("label"))
if err != nil {
return errors.Wrapf(err, "unable to process labels")
}
if len(labels) != 0 {
options = append(options, libpod.WithPodLabels(labels))
}
if c.IsSet("name") {
options = append(options, libpod.WithPodName(c.String("name")))
}
// always have containers use pod cgroups
options = append(options, libpod.WithPodCgroups())
pod, err := runtime.NewPod(options...)
if err != nil {
return err
}
if c.IsSet("pod-id-file") {
err = libpod.WriteFile(pod.ID(), c.String("pod-id-file"))
if err != nil {
logrus.Error(err)
}
}
fmt.Printf("%s\n", pod.ID())
return nil
}

600
cmd/podman/pod_ps.go Normal file
View File

@ -0,0 +1,600 @@
package main
import (
"reflect"
"sort"
"strconv"
"strings"
"time"
"github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/projectatomic/libpod/cmd/podman/batchcontainer"
"github.com/projectatomic/libpod/cmd/podman/formats"
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
"github.com/projectatomic/libpod/libpod"
"github.com/projectatomic/libpod/pkg/util"
"github.com/urfave/cli"
)
const (
STOPPED = "Stopped"
RUNNING = "Running"
PAUSED = "Paused"
EXITED = "Exited"
ERROR = "Error"
CREATED = "Created"
NUM_CTR_INFO = 10
)
var (
bc_opts batchcontainer.PsOptions
)
type podPsCtrInfo struct {
Name string `"json:name,omitempty"`
Id string `"json:id,omitempty"`
Status string `"json:status,omitempty"`
}
type podPsOptions struct {
NoTrunc bool
Format string
Sort string
Quiet bool
NumberOfContainers bool
Cgroup bool
NamesOfContainers bool
IdsOfContainers bool
StatusOfContainers bool
}
type podPsTemplateParams struct {
Created string
ID string
Name string
NumberOfContainers int
Status string
Cgroup string
UsePodCgroup bool
ContainerInfo string
}
// podPsJSONParams is used as a base structure for the psParams
// If template output is requested, podPsJSONParams will be converted to
// podPsTemplateParams.
// podPsJSONParams will be populated by data from libpod.Container,
// the members of the struct are the sama data types as their sources.
type podPsJSONParams struct {
CreatedAt time.Time `json:"createdAt"`
ID string `json:"id"`
Name string `json:"name"`
NumberOfContainers int `json:"numberofcontainers"`
Status string `json:"status"`
CtrsInfo []podPsCtrInfo `json:"containerinfo,omitempty"`
Cgroup string `json:"cgroup,omitempty"`
UsePodCgroup bool `json:"podcgroup,omitempty"`
}
// Type declaration and functions for sorting the pod PS output
type podPsSorted []podPsJSONParams
func (a podPsSorted) Len() int { return len(a) }
func (a podPsSorted) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
type podPsSortedCreated struct{ podPsSorted }
func (a podPsSortedCreated) Less(i, j int) bool {
return a.podPsSorted[i].CreatedAt.After(a.podPsSorted[j].CreatedAt)
}
type podPsSortedId struct{ podPsSorted }
func (a podPsSortedId) Less(i, j int) bool { return a.podPsSorted[i].ID < a.podPsSorted[j].ID }
type podPsSortedNumber struct{ podPsSorted }
func (a podPsSortedNumber) Less(i, j int) bool {
return len(a.podPsSorted[i].CtrsInfo) < len(a.podPsSorted[j].CtrsInfo)
}
type podPsSortedName struct{ podPsSorted }
func (a podPsSortedName) Less(i, j int) bool { return a.podPsSorted[i].Name < a.podPsSorted[j].Name }
type podPsSortedStatus struct{ podPsSorted }
func (a podPsSortedStatus) Less(i, j int) bool {
return a.podPsSorted[i].Status < a.podPsSorted[j].Status
}
var (
podPsFlags = []cli.Flag{
cli.BoolFlag{
Name: "cgroup",
Usage: "Print the Cgroup information of the pod",
},
cli.BoolFlag{
Name: "ctr-names",
Usage: "Display the container names",
},
cli.BoolFlag{
Name: "ctr-ids",
Usage: "Display the container UUIDs. If no-trunc is not set they will be truncated",
},
cli.BoolFlag{
Name: "ctr-status",
Usage: "Display the container status",
},
cli.StringFlag{
Name: "filter, f",
Usage: "Filter output based on conditions given",
},
cli.StringFlag{
Name: "format",
Usage: "Pretty-print pods to JSON or using a Go template",
},
cli.BoolFlag{
Name: "latest, l",
Usage: "Show the latest pod created",
},
cli.BoolFlag{
Name: "no-trunc",
Usage: "Do not truncate pod and container IDs",
},
cli.BoolFlag{
Name: "quiet, q",
Usage: "Print the numeric IDs of the pods only",
},
cli.StringFlag{
Name: "sort",
Usage: "Sort output by created, id, name, or number",
Value: "created",
},
}
podPsDescription = "List all pods on system including their names, ids and current state."
podPsCommand = cli.Command{
Name: "ps",
Aliases: []string{"ls", "list"},
Usage: "List pods",
Description: podPsDescription,
Flags: podPsFlags,
Action: podPsCmd,
UseShortOptionHandling: true,
}
)
func podPsCmd(c *cli.Context) error {
if err := validateFlags(c, podPsFlags); err != nil {
return err
}
if err := podPsCheckFlagsPassed(c); err != nil {
return errors.Wrapf(err, "error with flags passed")
}
runtime, err := libpodruntime.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
defer runtime.Shutdown(false)
if len(c.Args()) > 0 {
return errors.Errorf("too many arguments, ps takes no arguments")
}
opts := podPsOptions{
NoTrunc: c.Bool("no-trunc"),
Quiet: c.Bool("quiet"),
Sort: c.String("sort"),
IdsOfContainers: c.Bool("ctr-ids"),
NamesOfContainers: c.Bool("ctr-names"),
StatusOfContainers: c.Bool("ctr-status"),
}
opts.Format = genPodPsFormat(c)
var filterFuncs []libpod.PodFilter
if c.String("filter") != "" {
filters := strings.Split(c.String("filter"), ",")
for _, f := range filters {
filterSplit := strings.Split(f, "=")
if len(filterSplit) < 2 {
return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
}
generatedFunc, err := generatePodFilterFuncs(filterSplit[0], filterSplit[1], runtime)
if err != nil {
return errors.Wrapf(err, "invalid filter")
}
filterFuncs = append(filterFuncs, generatedFunc)
}
}
var pods []*libpod.Pod
if c.IsSet("latest") {
pod, err := runtime.GetLatestPod()
if err != nil {
return err
}
pods = append(pods, pod)
} else {
pods, err = runtime.GetAllPods()
if err != nil {
return err
}
}
podsFiltered := make([]*libpod.Pod, 0, len(pods))
for _, pod := range pods {
include := true
for _, filter := range filterFuncs {
include = include && filter(pod)
}
if include {
podsFiltered = append(podsFiltered, pod)
}
}
return generatePodPsOutput(podsFiltered, opts, runtime)
}
// podPsCheckFlagsPassed checks if mutually exclusive flags are passed together
func podPsCheckFlagsPassed(c *cli.Context) error {
// quiet, and format with Go template are mutually exclusive
flags := 0
if c.Bool("quiet") {
flags++
}
if c.IsSet("format") && c.String("format") != formats.JSONString {
flags++
}
if flags > 1 {
return errors.Errorf("quiet and format with Go template are mutually exclusive")
}
return nil
}
func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) (func(pod *libpod.Pod) bool, error) {
switch filter {
case "ctr-ids":
return func(p *libpod.Pod) bool {
ctrIds, err := p.AllContainersByID()
if err != nil {
return false
}
return util.StringInSlice(filterValue, ctrIds)
}, nil
case "ctr-names":
return func(p *libpod.Pod) bool {
ctrs, err := p.AllContainers()
if err != nil {
return false
}
for _, ctr := range ctrs {
if filterValue == ctr.Name() {
return true
}
}
return false
}, nil
case "ctr-number":
return func(p *libpod.Pod) bool {
ctrIds, err := p.AllContainersByID()
if err != nil {
return false
}
fVint, err2 := strconv.Atoi(filterValue)
if err2 != nil {
return false
}
return len(ctrIds) == fVint
}, nil
case "ctr-status":
if !util.StringInSlice(filterValue, []string{"created", "restarting", "running", "paused", "exited", "unknown"}) {
return nil, errors.Errorf("%s is not a valid status", filterValue)
}
return func(p *libpod.Pod) bool {
ctrs, err := p.AllContainers()
if err != nil {
return false
}
for _, ctr := range ctrs {
status, err := ctr.State()
if err != nil {
return false
}
state := status.String()
if status == libpod.ContainerStateConfigured {
state = "created"
}
if state == filterValue {
return true
}
}
return false
}, nil
case "id":
return func(p *libpod.Pod) bool {
return strings.Contains(p.ID(), filterValue)
}, nil
case "name":
return func(p *libpod.Pod) bool {
return strings.Contains(p.Name(), filterValue)
}, nil
case "status":
if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created"}) {
return nil, errors.Errorf("%s is not a valid pod status", filterValue)
}
return func(p *libpod.Pod) bool {
ctrs, err := p.AllContainers()
if err != nil {
return false
}
status, err := getPodStatus(ctrs)
if err != nil {
return false
}
if strings.ToLower(status) == filterValue {
return true
}
return false
}, nil
}
return nil, errors.Errorf("%s is an invalid filter", filter)
}
// generate the template based on conditions given
func genPodPsFormat(c *cli.Context) string {
format := ""
if c.String("format") != "" {
// "\t" from the command line is not being recognized as a tab
// replacing the string "\t" to a tab character if the user passes in "\t"
format = strings.Replace(c.String("format"), `\t`, "\t", -1)
} else if c.Bool("quiet") {
format = formats.IDString
} else {
format = "table {{.ID}}\t{{.Name}}\t{{.Status}}\t{{.Created}}"
if c.Bool("cgroup") {
format += "\t{{.Cgroup}}\t{{.UsePodCgroup}}"
}
if c.Bool("ctr-names") || c.Bool("ctr-ids") || c.Bool("ctr-status") {
format += "\t{{.ContainerInfo}}"
} else {
format += "\t{{.NumberOfContainers}}"
}
}
return format
}
func podPsToGeneric(templParams []podPsTemplateParams, JSONParams []podPsJSONParams) (genericParams []interface{}) {
if len(templParams) > 0 {
for _, v := range templParams {
genericParams = append(genericParams, interface{}(v))
}
return
}
for _, v := range JSONParams {
genericParams = append(genericParams, interface{}(v))
}
return
}
// generate the accurate header based on template given
func (p *podPsTemplateParams) podHeaderMap() 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 = "Pod" + value
}
values[key] = strings.ToUpper(splitCamelCase(value))
}
return values
}
func sortPodPsOutput(sortBy string, psOutput podPsSorted) (podPsSorted, error) {
switch sortBy {
case "created":
sort.Sort(podPsSortedCreated{psOutput})
case "id":
sort.Sort(podPsSortedId{psOutput})
case "name":
sort.Sort(podPsSortedName{psOutput})
case "number":
sort.Sort(podPsSortedNumber{psOutput})
case "status":
sort.Sort(podPsSortedStatus{psOutput})
default:
return nil, errors.Errorf("invalid option for --sort, options are: id, names, or number")
}
return psOutput, nil
}
// getPodTemplateOutput returns the modified container information
func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podPsTemplateParams, error) {
var (
psOutput []podPsTemplateParams
)
for _, psParam := range psParams {
podID := psParam.ID
var ctrStr string
truncated := ""
if !opts.NoTrunc {
podID = shortID(podID)
if len(psParam.CtrsInfo) > NUM_CTR_INFO {
psParam.CtrsInfo = psParam.CtrsInfo[:NUM_CTR_INFO]
truncated = "..."
}
}
for _, ctrInfo := range psParam.CtrsInfo {
ctrStr += "[ "
if opts.IdsOfContainers {
if opts.NoTrunc {
ctrStr += ctrInfo.Id
} else {
ctrStr += shortID(ctrInfo.Id)
}
}
if opts.NamesOfContainers {
ctrStr += ctrInfo.Name + " "
}
if opts.StatusOfContainers {
ctrStr += ctrInfo.Status + " "
}
ctrStr += "] "
}
ctrStr += truncated
params := podPsTemplateParams{
Created: units.HumanDuration(time.Since(psParam.CreatedAt)) + " ago",
ID: podID,
Name: psParam.Name,
Status: psParam.Status,
NumberOfContainers: psParam.NumberOfContainers,
UsePodCgroup: psParam.UsePodCgroup,
Cgroup: psParam.Cgroup,
ContainerInfo: ctrStr,
}
psOutput = append(psOutput, params)
}
return psOutput, nil
}
func getPodStatus(ctrs []*libpod.Container) (string, error) {
ctrNum := len(ctrs)
if ctrNum == 0 {
return CREATED, nil
}
statuses := map[string]int{
STOPPED: 0,
RUNNING: 0,
PAUSED: 0,
CREATED: 0,
ERROR: 0,
}
for _, ctr := range ctrs {
state, err := ctr.State()
if err != nil {
return "", err
}
switch state {
case libpod.ContainerStateStopped:
statuses[STOPPED]++
case libpod.ContainerStateRunning:
statuses[RUNNING]++
case libpod.ContainerStatePaused:
statuses[PAUSED]++
case libpod.ContainerStateCreated, libpod.ContainerStateConfigured:
statuses[CREATED]++
default:
statuses[ERROR]++
}
}
if statuses[RUNNING] > 0 {
return RUNNING, nil
} else if statuses[PAUSED] == ctrNum {
return PAUSED, nil
} else if statuses[STOPPED] == ctrNum {
return EXITED, nil
} else if statuses[STOPPED] > 0 {
return STOPPED, nil
} else if statuses[ERROR] > 0 {
return ERROR, nil
} else {
return CREATED, nil
}
}
// getAndSortPodJSONOutput returns the container info in its raw, sorted form
func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *libpod.Runtime) ([]podPsJSONParams, error) {
var (
psOutput []podPsJSONParams
)
for _, pod := range pods {
ctrs, err := pod.AllContainers()
ctrsInfo := make([]podPsCtrInfo, 0)
if err != nil {
return nil, err
}
ctrNum := len(ctrs)
status, err := getPodStatus(ctrs)
if err != nil {
return nil, err
}
for _, ctr := range ctrs {
batchInfo, err := batchcontainer.BatchContainerOp(ctr, bc_opts)
if err != nil {
return nil, err
}
var status string
switch batchInfo.ConState {
case libpod.ContainerStateStopped:
status = EXITED
case libpod.ContainerStateRunning:
status = RUNNING
case libpod.ContainerStatePaused:
status = PAUSED
case libpod.ContainerStateCreated, libpod.ContainerStateConfigured:
status = CREATED
default:
status = ERROR
}
ctrsInfo = append(ctrsInfo, podPsCtrInfo{
Name: batchInfo.ConConfig.Name,
Id: ctr.ID(),
Status: status,
})
}
params := podPsJSONParams{
CreatedAt: pod.CreatedTime(),
ID: pod.ID(),
Name: pod.Name(),
Status: status,
Cgroup: pod.CgroupParent(),
UsePodCgroup: pod.UsePodCgroup(),
NumberOfContainers: ctrNum,
CtrsInfo: ctrsInfo,
}
psOutput = append(psOutput, params)
}
return sortPodPsOutput(opts.Sort, psOutput)
}
func generatePodPsOutput(pods []*libpod.Pod, opts podPsOptions, runtime *libpod.Runtime) error {
if len(pods) == 0 && opts.Format != formats.JSONString {
return nil
}
psOutput, err := getAndSortPodJSONParams(pods, opts, runtime)
if err != nil {
return err
}
var out formats.Writer
switch opts.Format {
case formats.JSONString:
if err != nil {
return errors.Wrapf(err, "unable to create JSON for output")
}
out = formats.JSONStructArray{Output: podPsToGeneric([]podPsTemplateParams{}, psOutput)}
default:
psOutput, err := getPodTemplateOutput(psOutput, opts)
if err != nil {
return errors.Wrapf(err, "unable to create output")
}
out = formats.StdoutTemplateArray{Output: podPsToGeneric(psOutput, []podPsJSONParams{}), Template: opts.Format, Fields: psOutput[0].podHeaderMap()}
}
return formats.Writer(out).Out()
}

103
cmd/podman/pod_rm.go Normal file
View File

@ -0,0 +1,103 @@
package main
import (
"fmt"
"os"
"github.com/pkg/errors"
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
"github.com/projectatomic/libpod/libpod"
"github.com/urfave/cli"
)
var (
podRmFlags = []cli.Flag{
cli.BoolFlag{
Name: "force, f",
Usage: "Force removal of a running pod by first stopping all containers, then removing all containers in the pod. The default is false",
},
cli.BoolFlag{
Name: "all, a",
Usage: "Remove all pods",
},
LatestFlag,
}
podRmDescription = "Remove one or more pods"
podRmCommand = cli.Command{
Name: "rm",
Usage: fmt.Sprintf(`podman rm will remove one or more pods from the host. The pod name or ID can be used.
A pod with containers will not be removed without --force.
If --force is specified, all containers will be stopped, then removed.`),
Description: podRmDescription,
Flags: podRmFlags,
Action: podRmCmd,
ArgsUsage: "[POD ...]",
UseShortOptionHandling: true,
}
)
// saveCmd saves the image to either docker-archive or oci
func podRmCmd(c *cli.Context) error {
ctx := getContext()
if err := validateFlags(c, rmFlags); err != nil {
return err
}
if c.Bool("latest") && c.Bool("all") {
return errors.Errorf("--all and --latest cannot be used together")
}
runtime, err := libpodruntime.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
args := c.Args()
if len(args) == 0 && !c.Bool("all") && !c.Bool("latest") {
return errors.Errorf("specify one or more pods to remove")
}
var delPods []*libpod.Pod
var lastError error
if c.IsSet("all") {
delPods, err = runtime.GetAllPods()
if err != nil {
return errors.Wrapf(err, "unable to get pod list")
}
} else if c.IsSet("latest") {
delPod, err := runtime.GetLatestPod()
if err != nil {
return errors.Wrapf(err, "unable to get latest pod")
}
delPods = append(delPods, delPod)
} else {
for _, i := range args {
pod, err := runtime.LookupPod(i)
if err != nil {
fmt.Fprintln(os.Stderr, err)
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
}
lastError = errors.Wrapf(err, "unable to find pods %s", i)
continue
}
delPods = append(delPods, pod)
}
}
force := c.IsSet("force")
for _, pod := range delPods {
err = runtime.RemovePod(ctx, pod, force, force)
if err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
}
lastError = errors.Wrapf(err, "failed to delete pod %v", pod.ID())
} else {
fmt.Println(pod.ID())
}
}
return lastError
}

View File

@ -31,6 +31,29 @@ __podman_containers() {
__podman_q ps --format "$format" "$@"
}
# __podman_pods returns a list of pods. Additional options to
# `podman pod ps` may be specified in order to filter the list, e.g.
# `__podman_containers --filter status=running`
# By default, only names are returned.
# Set PODMAN_COMPLETION_SHOW_CONTAINER_IDS=yes to also complete IDs.
# An optional first option `--id|--name` may be used to limit the
# output to the IDs or names of matching items. This setting takes
# precedence over the environment setting.
__podman_pods() {
local format
if [ "$1" = "--id" ] ; then
format='{{.ID}}'
shift
elif [ "$1" = "--name" ] ; then
format='{{.Names}}'
shift
else
format='{{.Names}}'
fi
__podman_q pod ps --format "$format" "$@"
}
# __podman_complete_containers applies completion of containers based on the current
# value of `$cur` or the value of the optional first option `--cur`, if given.
# Additional filters may be appended, see `__podman_containers`.
@ -43,6 +66,23 @@ __podman_complete_containers() {
COMPREPLY=( $(compgen -W "$(__podman_containers "$@")" -- "$current") )
}
# __podman_complete_pods applies completion of pods based on the current
# value of `$cur` or the value of the optional first option `--cur`, if given.
# Additional filters may be appended, see `__podman_pods`.
__podman_complete_pods() {
local current="$cur"
if [ "$1" = "--cur" ] ; then
current="$2"
shift 2
fi
COMPREPLY=( $(compgen -W "$(__podman_pods "$@")" -- "$current") )
}
__podman_complete_pod_names() {
local names=( $(__podman_q pod ps --format={{.Name}}) )
COMPREPLY=( $(compgen -W "${names[*]}" -- "$cur") )
}
__podman_complete_containers_all() {
__podman_complete_containers "$@" --all
}
@ -1662,10 +1702,12 @@ _podman_container_run() {
esac
}
_podman_create() {
_podman_container_run
}
_podman_run() {
_podman_container_run
}
@ -2013,6 +2055,105 @@ _podman_logout() {
_complete_ "$options_with_args" "$boolean_options"
}
_podman_pod_create() {
local options_with_args="
--cgroup-parent
--podidfile
--label-file
--label
-l
--name
"
local boolean_options="
"
_complete_ "$options_with_args" "$boolean_options"
}
__podman_pod_ps() {
local options_with_args="
-f
--filter
--format
--sort
"
local boolean_options="
--cgroup
--ctr-ids
--ctr-names
--ctr-status
-q
--quiet
--no-trunc
--labels
-l
--latest
"
_complete_ "$options_with_args" "$boolean_options"
}
_podman_pod_ls() {
__podman_pod_ps
}
_podman_pod_list() {
__podman_pod_ps
}
_podman_pod_ps() {
__podman_pod_ps
}
_podman_pod_rm() {
local options_with_args="
"
local boolean_options="
-a
--all
-f
--force
--latest
-l
"
_complete_ "$options_with_args" "$boolean_options"
case "$cur" in
-*)
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
;;
*)
__podman_complete_pod_names
;;
esac
}
_podman_pod() {
local boolean_options="
--help
-h
"
subcommands="
create
ps
rm
"
local aliases="
list
ls
"
__podman_subcommands "$subcommands $aliases" && return
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
;;
*)
COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) )
;;
esac
}
_podman_podman() {
local options_with_args="
--config -c
@ -2049,6 +2190,7 @@ _podman_podman() {
logs
mount
pause
pod
port
ps
pull

View File

@ -0,0 +1,60 @@
% podman-pod-create "1"
## NAME
podman\-pod\-create - Create a new pod
## SYNOPSIS
**podman pod create** [*options*]
## DESCRIPTION
Creates an empty pod, or unit of multiple containers, and prepares it to have
containers added to it. The pod id is printed to STDOUT. You can then use
**podman create --pod <pod_id|pod_name> ...** to add containers to the pod, and
**podman pod start <pod_id|pod_name>** to start the pod.
## OPTIONS
**--cgroup-parent**=*true*|*false*
Path to cgroups under which the cgroup for the pod will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
**--podidfile**=""
Write the pod ID to the file
**--help**
Print usage statement
**-l**, **--label**=[]
Add metadata to a pod (e.g., --label com.example.key=value)
**--label-file**=[]
Read in a line delimited file of labels
**-n**, **--name**=""
Assign a name to the pod
The operator can identify a pod in three ways:
UUID long identifier (“f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778”)
UUID short identifier (“f78375b1c487”)
Name (“jonah”)
podman generates a UUID for each pod, and if a name is not assigned
to the container with **--name** then a random string name will be generated
for it. The name is useful any place you need to identify a pod.
## EXAMPLES
# podman pod create --name test
## SEE ALSO
podman-pod(1)
## HISTORY
July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com>

165
docs/podman-pod-ps.1.md Normal file
View File

@ -0,0 +1,165 @@
% podman-pod-ps "1"
## NAME
podman\-pod\-ps - Prints out information about pods
## SYNOPSIS
**podman pod ps** [*options*]
## DESCRIPTION
**podman pod ps** lists the pods on the system.
By default it lists:
* pod id
* pod name
* number of containers attached to pod
* status of pod as defined by the following table
| **Status** | **Description** |
| ------------ | ------------------------------------------------|
| Created | No containers running nor stopped |
| Running | at least one container is running |
| Stopped | At least one container stopped and none running |
| Exited | All containers stopped in pod |
| Dead | Error retrieving state |
## OPTIONS
**--ctr-names**
Includes the container names in the container info field
**--ctr-ids**
Includes the container IDs in the container info field
**--ctr-status**
Includes the container statuses in the container info field
**--latest, -l**
Show the latest pod created (all states)
**--no-trunc**
Display the extended information
**--quiet, -q**
Print the numeric IDs of the pods 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 |
| .Name | Name of pod |
| .Status | Status of pod |
| .Labels | All the labels assigned to the pod |
| .ContainerInfo | Show the names, ids and/or statuses of containers (only shows 9 unless no-trunc is specified) |
| .NumberOfContainers | Show the number of containers attached to pod |
| .Cgroup | Cgroup path of pod |
| .UsePodCgroup | Whether containers use the Cgroup of the pod |
**--sort**
Sort by created, ID, name, status, or number of containers
Default: created
**--filter, -f**
Filter output based on conditions given
Valid filters are listed below:
| **Filter** | **Description** |
| --------------- | ------------------------------------------------------------------- |
| id | [ID] Pod's ID |
| name | [Name] Pod's name |
| label | [Key] or [Key=Value] Label assigned to a container |
| ctr-names | Container name within the pod |
| ctr-ids | Container ID within the pod |
| ctr-status | Container status within the pod |
| ctr-number | Number of containers in the pod |
**--help**, **-h**
Print usage statement
## EXAMPLES
```
sudo podman pod ps
POD ID NAME STATUS NUMBER OF CONTAINERS
00dfd6fa02c0 jolly_goldstine Running 1
f4df8692e116 nifty_torvalds Created 2
```
```
sudo podman pod ps --ctr-names
POD ID NAME STATUS CONTAINER INFO
00dfd6fa02c0 jolly_goldstine Running [ loving_archimedes ]
f4df8692e116 nifty_torvalds Created [ thirsty_hawking ] [ wizardly_golick ]
```
```
podman pod ps --ctr-status --ctr-names --ctr-ids
POD ID NAME STATUS CONTAINER INFO
00dfd6fa02c0 jolly_goldstine Running [ ba465ab0a3a4 loving_archimedes Running ]
f4df8692e116 nifty_torvalds Created [ 331693bff40a thirsty_hawking Created ] [ 8e428daeb89e wizardly_golick Created ]
```
```
sudo podman pod ps --format "{{.ID}} {{.ContainerInfo}} {{.Cgroup}}" --ctr-names
00dfd6fa02c0 [ loving_archimedes ] /libpod_parent
f4df8692e116 [ thirsty_hawking ] [ wizardly_golick ] /libpod_parent
```
```
sudo podman pod ps --cgroup
POD ID NAME STATUS NUMBER OF CONTAINERS CGROUP USE POD CGROUP
00dfd6fa02c0 jolly_goldstine Running 1 /libpod_parent true
f4df8692e116 nifty_torvalds Created 2 /libpod_parent true
```
```
podman pod ps --sort id --filter ctr-number=2
POD ID NAME STATUS NUMBER OF CONTAINERS
f4df8692e116 nifty_torvalds Created 2
```
```
sudo podman pod ps --ctr-ids
POD ID NAME STATUS CONTAINER INFO
00dfd6fa02c0 jolly_goldstine Running [ ba465ab0a3a4 ]
f4df8692e116 nifty_torvalds Created [ 331693bff40a ] [ 8e428daeb89e ]
```
```
sudo podman pod ps --no-trunc --ctr-ids
POD ID NAME STATUS CONTAINER INFO
00dfd6fa02c0a2daaedfdf8fcecd06f22ad114d46d167d71777224735f701866 jolly_goldstine Running [ ba465ab0a3a4e15e3539a1e79c32d1213a02b0989371e274f98e0f1ae9de7050 ]
f4df8692e116a3e6d1d62572644ed36ca475d933808cc3c93435c45aa139314b nifty_torvalds Created [ 331693bff40a0ef2f05a3aba73ce49e3243108911927fff04d1f7fc44dda8022 ] [ 8e428daeb89e69b71e7916a13accfb87d122889442b5c05c2d99cf94a3230e9d ]
```
```
podman pod ps --ctr-names
POD ID NAME STATUS CONTAINER INFO
314f4da82d74 hi Created [ jovial_jackson ] [ hopeful_archimedes ] [ vibrant_ptolemy ] [ heuristic_jennings ] [ keen_raman ] [ hopeful_newton ] [ mystifying_bose ] [ silly_lalande ] [ serene_lichterman ] ...
```
## pod ps
Print a list of pods
## SEE ALSO
podman-pod(1)
## HISTORY
July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com>

42
docs/podman-pod-rm.1.md Normal file
View File

@ -0,0 +1,42 @@
% podman-pod-rm "1"
## NAME
podman\-pod\-rm - Remove one or more pods
## SYNOPSIS
**podman pod rm** [*options*] *pod*
## DESCRIPTION
**podman pod rm** will remove one or more pods from the host. The pod name or ID can be used. The \-f option stops all containers and then removes them before removing the pod. Without the \-f option, a pod cannot be removed if it has associated containers.
## OPTIONS
**--all, a**
Remove all pods. Can be used in conjunction with \-f as well.
**--latest, -l**
Instead of providing the pod name or ID, use the last created pod.
**--force, f**
Stop running containers and delete all stopped containers before removal of pod.
## EXAMPLE
podman pod rm mywebserverpod
podman pod rm mywebserverpod myflaskserverpod 860a4b23
podman pod rm -f 860a4b23
podman pod rm -f -a
podman pod rm -fa
## SEE ALSO
podman-pod(1)
## HISTORY
July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com>

21
docs/podman-pod.1.md Normal file
View File

@ -0,0 +1,21 @@
% podman-pod "1"
## NAME
podman\-pod - Simple management tool for groups of containers, called pods.
## SYNOPSIS
**podman pod** *subcommand*
# DESCRIPTION
podman pod is a set of subcommands that manage pods, or groups of containers.
## SUBCOMMANDS
| Subcommand | Description |
| ------------------------------------------------- | ------------------------------------------------------------------------------ |
| [podman-pod-create(1)](podman-pod-create.1.md) | Create a new pod. |
| [podman-pod-ps(1)](podman-pod-ps.1.md) | Prints out information about pods. |
| [podman-pod-rm(1)](podman-pod-rm.1.md) | Remove one or more pods. |
## HISTORY
July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com>

View File

@ -74,7 +74,7 @@ func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
return nil, errors.Wrapf(err, "error adding pod to state")
}
return nil, ErrNotImplemented
return pod, nil
}
func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {

View File

@ -318,6 +318,14 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
logrus.Debugf("appending name %s", c.Name)
options = append(options, libpod.WithName(c.Name))
}
if c.Pod != "" {
logrus.Debugf("adding container to pod %s", c.Pod)
pod, err := runtime.LookupPod(c.Pod)
if err != nil {
return nil, errors.Wrapf(err, "unable to add container to pod %s", c.Pod)
}
options = append(options, runtime.WithPod(pod))
}
if len(c.PortBindings) > 0 {
portBindings, err = c.CreatePortBindings()

View File

@ -224,6 +224,17 @@ func (p *PodmanTest) Cleanup() {
}
}
// CleanupPod cleans up the temporary store
func (p *PodmanTest) CleanupPod() {
// Remove all containers
session := p.Podman([]string{"pod", "rm", "-fa"})
session.Wait(90)
// Nuke tempdir
if err := os.RemoveAll(p.TempDir); err != nil {
fmt.Printf("%q\n", err)
}
}
// GrepString takes session output and behaves like grep. it returns a bool
// if successful and an array of strings on positive matches
func (s *PodmanSession) GrepString(term string) (bool, []string) {
@ -459,6 +470,15 @@ func (p *PodmanTest) RunTopContainer(name string) *PodmanSession {
return p.Podman(podmanArgs)
}
func (p *PodmanTest) RunTopContainerInPod(name, pod string) *PodmanSession {
var podmanArgs = []string{"run", "--pod", pod}
if name != "" {
podmanArgs = append(podmanArgs, "--name", name)
}
podmanArgs = append(podmanArgs, "-d", ALPINE, "top")
return p.Podman(podmanArgs)
}
//RunLsContainer runs a simple container in the background that
// simply runs ls. If the name passed != "", it will have a name
func (p *PodmanTest) RunLsContainer(name string) (*PodmanSession, int, string) {
@ -472,6 +492,17 @@ func (p *PodmanTest) RunLsContainer(name string) (*PodmanSession, int, string) {
return session, session.ExitCode(), session.OutputToString()
}
func (p *PodmanTest) RunLsContainerInPod(name, pod string) (*PodmanSession, int, string) {
var podmanArgs = []string{"run", "--pod", pod}
if name != "" {
podmanArgs = append(podmanArgs, "--name", name)
}
podmanArgs = append(podmanArgs, "-d", ALPINE, "ls")
session := p.Podman(podmanArgs)
session.WaitWithDefaultTimeout()
return session, session.ExitCode(), session.OutputToString()
}
//NumberOfContainersRunning returns an int of how many
// containers are currently running.
func (p *PodmanTest) NumberOfContainersRunning() int {
@ -502,6 +533,21 @@ func (p *PodmanTest) NumberOfContainers() int {
return len(containers)
}
// NumberOfPods returns an int of how many
// pods are currently defined.
func (p *PodmanTest) NumberOfPods() int {
var pods []string
ps := p.Podman([]string{"pod", "ps", "-q"})
ps.WaitWithDefaultTimeout()
Expect(ps.ExitCode()).To(Equal(0))
for _, i := range ps.OutputToStringArray() {
if i != "" {
pods = append(pods, i)
}
}
return len(pods)
}
// NumberOfRunningContainers returns an int of how many containers are currently
// running
func (p *PodmanTest) NumberOfRunningContainers() int {

View File

@ -0,0 +1,84 @@
package integration
import (
"os"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Podman pod create", func() {
var (
tempdir string
err error
podmanTest PodmanTest
)
BeforeEach(func() {
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
}
podmanTest = PodmanCreate(tempdir)
podmanTest.RestoreAllArtifacts()
})
AfterEach(func() {
podmanTest.CleanupPod()
})
It("podman create pod", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
cid := session.OutputToString()
Expect(session.ExitCode()).To(Equal(0))
check := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc"})
check.WaitWithDefaultTimeout()
match, _ := check.GrepString(cid)
Expect(match).To(BeTrue())
Expect(len(check.OutputToStringArray())).To(Equal(1))
})
It("podman create pod with name", func() {
name := "test"
session := podmanTest.Podman([]string{"pod", "create", "--name", name})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
check := podmanTest.Podman([]string{"pod", "ps", "--no-trunc"})
check.WaitWithDefaultTimeout()
match, _ := check.GrepString(name)
Expect(match).To(BeTrue())
})
It("podman create pod with doubled name", func() {
name := "test"
session := podmanTest.Podman([]string{"pod", "create", "--name", name})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "create", "--name", name})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(1)))
check := podmanTest.Podman([]string{"pod", "ps", "-q"})
check.WaitWithDefaultTimeout()
Expect(len(check.OutputToStringArray())).To(Equal(1))
})
It("podman create pod with same name as ctr", func() {
name := "test"
session := podmanTest.Podman([]string{"create", "--name", name, ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "create", "--name", name})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(1)))
check := podmanTest.Podman([]string{"pod", "ps", "-q"})
check.WaitWithDefaultTimeout()
Expect(len(check.OutputToStringArray())).To(Equal(1))
})
})

227
test/e2e/pod_ps_test.go Normal file
View File

@ -0,0 +1,227 @@
package integration
import (
"fmt"
"os"
"sort"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Podman ps", func() {
var (
tempdir string
err error
podmanTest PodmanTest
)
BeforeEach(func() {
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
}
podmanTest = PodmanCreate(tempdir)
podmanTest.RestoreAllArtifacts()
})
AfterEach(func() {
podmanTest.CleanupPod()
})
It("podman pod ps no pods", func() {
session := podmanTest.Podman([]string{"pod", "ps"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
It("podman pod ps default", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid := session.OutputToString()
session = podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "ps"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(len(result.OutputToStringArray())).Should(BeNumerically(">", 0))
})
It("podman pod ps quiet flag", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid := session.OutputToString()
_, ec, _ := podmanTest.RunLsContainerInPod("", podid)
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "ps", "-q"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(len(result.OutputToStringArray())).Should(BeNumerically(">", 0))
Expect(podid).To(ContainSubstring(result.OutputToStringArray()[0]))
})
It("podman pod ps no-trunc", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid := session.OutputToString()
_, ec, _ := podmanTest.RunLsContainerInPod("", podid)
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(len(result.OutputToStringArray())).Should(BeNumerically(">", 0))
Expect(podid).To(Equal(result.OutputToStringArray()[0]))
})
It("podman pod ps latest", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid1 := session.OutputToString()
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid2 := session.OutputToString()
result := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--latest"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(result.OutputToString()).To(ContainSubstring(podid2))
Expect(result.OutputToString()).To(Not(ContainSubstring(podid1)))
})
It("podman pod ps id filter flag", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "ps", "--filter", fmt.Sprintf("id=%s", session.OutputToString())})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
})
It("podman pod ps mutually exclusive flags", func() {
session := podmanTest.Podman([]string{"pod", "ps", "-q", "--format", "{{.ID}}"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
})
It("podman pod ps --sort by name", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "ps", "--sort=name", "--format", "{{.Name}}"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
sortedArr := session.OutputToStringArray()
Expect(sort.SliceIsSorted(sortedArr, func(i, j int) bool { return sortedArr[i] < sortedArr[j] })).To(BeTrue())
})
It("podman pod ps --ctr-names", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid := session.OutputToString()
session = podmanTest.RunTopContainerInPod("test1", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
_, ec, _ := podmanTest.RunLsContainerInPod("test2", podid)
Expect(ec).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "ps", "--format={{.ContainerInfo}}", "--ctr-names"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("test1"))
Expect(session.OutputToString()).To(ContainSubstring("test2"))
})
It("podman pod ps filter ctr attributes", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid1 := session.OutputToString()
session = podmanTest.RunTopContainerInPod("test1", podid1)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid2 := session.OutputToString()
_, ec, cid := podmanTest.RunLsContainerInPod("test2", podid2)
Expect(ec).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-names=test1"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(podid1))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid2)))
session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", fmt.Sprintf("ctr-ids=%s", cid)})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(podid2))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid1)))
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid3 := session.OutputToString()
session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-number=1"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(podid1))
Expect(session.OutputToString()).To(ContainSubstring(podid2))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid3)))
session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-status=running"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(podid1))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid2)))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid3)))
session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-status=exited"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(podid2))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid1)))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid3)))
session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-status=created"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(BeEmpty())
})
})

168
test/e2e/pod_rm_test.go Normal file
View File

@ -0,0 +1,168 @@
package integration
import (
"os"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Podman pod rm", func() {
var (
tempdir string
err error
podmanTest PodmanTest
)
BeforeEach(func() {
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
}
podmanTest = PodmanCreate(tempdir)
podmanTest.RestoreAllArtifacts()
})
AfterEach(func() {
podmanTest.CleanupPod()
})
It("podman pod rm empty pod", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
podid := session.OutputToString()
result := podmanTest.Podman([]string{"pod", "rm", podid})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
})
It("podman pod rm latest pod", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
podid := session.OutputToString()
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
podid2 := session.OutputToString()
result := podmanTest.Podman([]string{"pod", "rm", "--latest"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
result = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(result.OutputToString()).To(ContainSubstring(podid))
Expect(result.OutputToString()).To(Not(ContainSubstring(podid2)))
})
It("podman pod rm doesn't remove a pod with a container", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
podid := session.OutputToString()
session = podmanTest.Podman([]string{"create", "--pod", podid, ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "rm", podid})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(125))
result = podmanTest.Podman([]string{"ps", "-qa"})
result.WaitWithDefaultTimeout()
Expect(len(result.OutputToStringArray())).To(Equal(1))
})
It("podman pod rm -f does remove a running container", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
podid := session.OutputToString()
session = podmanTest.Podman([]string{"run", "-d", "--pod", podid, ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "rm", "-f", podid})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
result = podmanTest.Podman([]string{"ps", "-q"})
result.WaitWithDefaultTimeout()
Expect(result.OutputToString()).To(BeEmpty())
})
It("podman pod rm -a doesn't remove a running container", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
podid1 := session.OutputToString()
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
session = podmanTest.Podman([]string{"run", "-d", "--pod", podid1, ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "rm", "-a"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Not(Equal(0)))
result = podmanTest.Podman([]string{"ps", "-q"})
result.WaitWithDefaultTimeout()
Expect(len(result.OutputToStringArray())).To(Equal(1))
// one pod should have been deleted
result = podmanTest.Podman([]string{"pod", "ps", "-q"})
result.WaitWithDefaultTimeout()
Expect(len(result.OutputToStringArray())).To(Equal(1))
})
It("podman pod rm -fa removes everything", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
podid1 := session.OutputToString()
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
podid2 := session.OutputToString()
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
session = podmanTest.Podman([]string{"run", "-d", "--pod", podid1, ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"create", "-d", "--pod", podid1, ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"run", "-d", "--pod", podid2, ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"run", "-d", "--pod", podid2, nginx})
session.WaitWithDefaultTimeout()
result := podmanTest.Podman([]string{"pod", "rm", "-fa"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
result = podmanTest.Podman([]string{"ps", "-q"})
result.WaitWithDefaultTimeout()
Expect(result.OutputToString()).To(BeEmpty())
// one pod should have been deleted
result = podmanTest.Podman([]string{"pod", "ps", "-q"})
result.WaitWithDefaultTimeout()
Expect(result.OutputToString()).To(BeEmpty())
})
})