From 2011782d9d52958546e481f84892d00a548b9e12 Mon Sep 17 00:00:00 2001 From: baude Date: Mon, 29 Oct 2018 12:06:48 -0500 Subject: Make restart parallel and add --all When attempting to restart many containers, we can benefit from making the restarts parallel. For convenience, two new options are added: --all attempts to restart all containers --run-only when used with --all will attempt to restart only running containers Signed-off-by: baude --- completions/bash/podman | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'completions/bash') diff --git a/completions/bash/podman b/completions/bash/podman index 5cfed348f..ed4e080c9 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1770,8 +1770,13 @@ _podman_restart() { --timeout -t " local boolean_options=" + --all + -a --latest - -l" + -l + --running + --timeout + -t" case "$cur" in -*) COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) -- cgit v1.2.3-54-g00ecf From b559c19c2fa739cf1c8ede50eab8f5acf74f6bf3 Mon Sep 17 00:00:00 2001 From: baude Date: Mon, 29 Oct 2018 13:53:39 -0500 Subject: Make kill, pause, and unpause parallel. Operations like kill, pause, and unpause -- which can operation on one or more containers -- can greatly benefit from parallizing its main job (eq kill). In the case of pauseand unpause, an --all option as was added. pause --all will pause all **running** containers. And unpause --all will unpause all **paused** containers. Signed-off-by: baude --- cmd/podman/kill.go | 51 +++++++++++++++++++++++------- cmd/podman/pause.go | 72 +++++++++++++++++++++++++++++++++--------- cmd/podman/shared/parallel.go | 15 +++++++++ cmd/podman/stop.go | 4 ++- cmd/podman/unpause.go | 73 ++++++++++++++++++++++++++++++++++--------- completions/bash/podman | 9 ++++++ docs/podman-kill.1.md | 2 +- docs/podman-pause.1.md | 19 ++++++++++- docs/podman-unpause.1.md | 20 +++++++++++- test/e2e/pause_test.go | 62 ++++++++++++++++++++++++++++++++++++ 10 files changed, 282 insertions(+), 45 deletions(-) (limited to 'completions/bash') diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go index 7ca5bd7c5..27882aeee 100644 --- a/cmd/podman/kill.go +++ b/cmd/podman/kill.go @@ -1,15 +1,16 @@ package main import ( - "os" + "fmt" "syscall" - "fmt" "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/rootless" "github.com/docker/docker/pkg/signal" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -41,6 +42,12 @@ var ( // killCmd kills one or more containers with a signal func killCmd(c *cli.Context) error { + var ( + lastError error + killFuncs []shared.ParallelWorkerInput + killSignal uint = uint(syscall.SIGTERM) + ) + if err := checkAllAndLatest(c); err != nil { return err } @@ -56,7 +63,6 @@ func killCmd(c *cli.Context) error { } defer runtime.Shutdown(false) - var killSignal uint = uint(syscall.SIGTERM) if c.String("signal") != "" { // Check if the signalString provided by the user is valid // Invalid signals will return err @@ -67,17 +73,40 @@ func killCmd(c *cli.Context) error { killSignal = uint(sysSignal) } - containers, lastError := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") - + containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") + if err != nil { + return err + } for _, ctr := range containers { - if err := ctr.Kill(killSignal); err != nil { - if lastError != nil { - fmt.Fprintln(os.Stderr, lastError) + con := ctr + f := func() error { + return con.Kill(killSignal) + } + + killFuncs = append(killFuncs, shared.ParallelWorkerInput{ + ContainerID: con.ID(), + ParallelFunc: f, + }) + } + + maxWorkers := shared.Parallelize("kill") + if c.GlobalIsSet("max-workers") { + maxWorkers = c.GlobalInt("max-workers") + } + logrus.Debugf("Setting maximum workers to %d", maxWorkers) + + killErrors := shared.ParallelExecuteWorkerPool(maxWorkers, killFuncs) + + for cid, result := range killErrors { + if result != nil { + if len(killErrors) > 1 { + fmt.Println(result.Error()) } - lastError = errors.Wrapf(err, "unable to find container %v", ctr.ID()) - } else { - fmt.Println(ctr.ID()) + lastError = result + continue } + fmt.Println(cid) } + return lastError } diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go index 203fa6070..1e1585216 100644 --- a/cmd/podman/pause.go +++ b/cmd/podman/pause.go @@ -5,11 +5,20 @@ import ( "os" "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/cmd/podman/shared" + "github.com/containers/libpod/libpod" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/urfave/cli" ) var ( + pauseFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "pause all running containers", + }, + } pauseDescription = ` podman pause @@ -19,6 +28,7 @@ var ( Name: "pause", Usage: "Pauses all the processes in one or more containers", Description: pauseDescription, + Flags: pauseFlags, Action: pauseCmd, ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]", OnUsageError: usageErrorHandler, @@ -26,6 +36,11 @@ var ( ) func pauseCmd(c *cli.Context) error { + var ( + lastError error + pauseContainers []*libpod.Container + pauseFuncs []shared.ParallelWorkerInput + ) if os.Geteuid() != 0 { return errors.New("pause is not supported for rootless containers") } @@ -37,28 +52,55 @@ func pauseCmd(c *cli.Context) error { defer runtime.Shutdown(false) args := c.Args() - if len(args) < 1 { + if len(args) < 1 && !c.Bool("all") { return errors.Errorf("you must provide at least one container name or id") } - - var lastError error - for _, arg := range args { - ctr, err := runtime.LookupContainer(arg) + if c.Bool("all") { + containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") if err != nil { - if lastError != nil { - fmt.Fprintln(os.Stderr, lastError) + return err + } + pauseContainers = append(pauseContainers, containers...) + } else { + for _, arg := range args { + ctr, err := runtime.LookupContainer(arg) + if err != nil { + return err } - lastError = errors.Wrapf(err, "error looking up container %q", arg) - continue + pauseContainers = append(pauseContainers, ctr) + } + } + + // Now assemble the slice of pauseFuncs + for _, ctr := range pauseContainers { + con := ctr + + f := func() error { + return con.Pause() } - if err = ctr.Pause(); err != nil { - if lastError != nil { - fmt.Fprintln(os.Stderr, lastError) + pauseFuncs = append(pauseFuncs, shared.ParallelWorkerInput{ + ContainerID: con.ID(), + ParallelFunc: f, + }) + } + + maxWorkers := shared.Parallelize("pause") + if c.GlobalIsSet("max-workers") { + maxWorkers = c.GlobalInt("max-workers") + } + logrus.Debugf("Setting maximum workers to %d", maxWorkers) + + pauseErrors := shared.ParallelExecuteWorkerPool(maxWorkers, pauseFuncs) + + for cid, result := range pauseErrors { + if result != nil { + if len(pauseErrors) > 1 { + fmt.Println(result.Error()) } - lastError = errors.Wrapf(err, "failed to pause container %v", ctr.ID()) - } else { - fmt.Println(ctr.ID()) + lastError = result + continue } + fmt.Println(cid) } return lastError } diff --git a/cmd/podman/shared/parallel.go b/cmd/podman/shared/parallel.go index dbf43a982..633781a45 100644 --- a/cmd/podman/shared/parallel.go +++ b/cmd/podman/shared/parallel.go @@ -72,6 +72,16 @@ func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) map func Parallelize(job string) int { numCpus := runtime.NumCPU() switch job { + case "kill": + if numCpus <= 3 { + return numCpus * 3 + } + return numCpus * 4 + case "pause": + if numCpus <= 3 { + return numCpus * 3 + } + return numCpus * 4 case "ps": return 8 case "restart": @@ -88,6 +98,11 @@ func Parallelize(job string) int { } else { return numCpus * 3 } + case "unpause": + if numCpus <= 3 { + return numCpus * 3 + } + return numCpus * 4 } return 3 } diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go index afeb49f76..cb36fd5cd 100644 --- a/cmd/podman/stop.go +++ b/cmd/podman/stop.go @@ -89,7 +89,9 @@ func stopCmd(c *cli.Context) error { for cid, result := range stopErrors { if result != nil && result != libpod.ErrCtrStopped { - fmt.Println(result.Error()) + if len(stopErrors) > 1 { + fmt.Println(result.Error()) + } lastError = result continue } diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go index a792aaf6d..648fc9d3d 100644 --- a/cmd/podman/unpause.go +++ b/cmd/podman/unpause.go @@ -5,11 +5,20 @@ import ( "os" "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/cmd/podman/shared" + "github.com/containers/libpod/libpod" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/urfave/cli" ) var ( + unpauseFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "unpause all paused containers", + }, + } unpauseDescription = ` podman unpause @@ -19,6 +28,7 @@ var ( Name: "unpause", Usage: "Unpause the processes in one or more containers", Description: unpauseDescription, + Flags: unpauseFlags, Action: unpauseCmd, ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]", OnUsageError: usageErrorHandler, @@ -26,6 +36,11 @@ var ( ) func unpauseCmd(c *cli.Context) error { + var ( + lastError error + unpauseContainers []*libpod.Container + unpauseFuncs []shared.ParallelWorkerInput + ) if os.Geteuid() != 0 { return errors.New("unpause is not supported for rootless containers") } @@ -37,28 +52,56 @@ func unpauseCmd(c *cli.Context) error { defer runtime.Shutdown(false) args := c.Args() - if len(args) < 1 { + if len(args) < 1 && !c.Bool("all") { return errors.Errorf("you must provide at least one container name or id") } - - var lastError error - for _, arg := range args { - ctr, err := runtime.LookupContainer(arg) + if c.Bool("all") { + cs, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStatePaused, "paused") if err != nil { - if lastError != nil { - fmt.Fprintln(os.Stderr, lastError) + return err + } + unpauseContainers = append(unpauseContainers, cs...) + } else { + for _, arg := range args { + ctr, err := runtime.LookupContainer(arg) + if err != nil { + return err } - lastError = errors.Wrapf(err, "error looking up container %q", arg) - continue + unpauseContainers = append(unpauseContainers, ctr) } - if err = ctr.Unpause(); err != nil { - if lastError != nil { - fmt.Fprintln(os.Stderr, lastError) + } + + // Assemble the unpause funcs + for _, ctr := range unpauseContainers { + con := ctr + f := func() error { + return con.Unpause() + } + + unpauseFuncs = append(unpauseFuncs, shared.ParallelWorkerInput{ + ContainerID: con.ID(), + ParallelFunc: f, + }) + } + + maxWorkers := shared.Parallelize("unpause") + if c.GlobalIsSet("max-workers") { + maxWorkers = c.GlobalInt("max-workers") + } + logrus.Debugf("Setting maximum workers to %d", maxWorkers) + + unpauseErrors := shared.ParallelExecuteWorkerPool(maxWorkers, unpauseFuncs) + + for cid, result := range unpauseErrors { + if result != nil && result != libpod.ErrCtrStopped { + if len(unpauseErrors) > 1 { + fmt.Println(result.Error()) } - lastError = errors.Wrapf(err, "failed to unpause container %v", ctr.ID()) - } else { - fmt.Println(ctr.ID()) + lastError = result + continue } + fmt.Println(cid) } + return lastError } diff --git a/completions/bash/podman b/completions/bash/podman index ed4e080c9..c029f893a 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1,5 +1,6 @@ : ${PROG:=$(basename ${BASH_SOURCE})} + __podman_previous_extglob_setting=$(shopt -p extglob) shopt -s extglob @@ -1934,6 +1935,10 @@ _podman_save() { } _podman_pause() { + local boolean_options=" + -a + --all + " local options_with_args=" --help -h " @@ -2035,6 +2040,10 @@ _podman_stop() { } _podman_unpause() { + local boolean_options=" + -a + --all + " local options_with_args=" --help -h " diff --git a/docs/podman-kill.1.md b/docs/podman-kill.1.md index 14066d151..85f68a73d 100644 --- a/docs/podman-kill.1.md +++ b/docs/podman-kill.1.md @@ -4,7 +4,7 @@ podman\-kill - Kills one or more containers with a signal ## SYNOPSIS -**podman kill** [*options*] *container* ... +**podman kill** [*options*] [*container* ...] ## DESCRIPTION The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal. diff --git a/docs/podman-pause.1.md b/docs/podman-pause.1.md index b4930de8d..f19fa5d6a 100644 --- a/docs/podman-pause.1.md +++ b/docs/podman-pause.1.md @@ -4,16 +4,33 @@ podman\-pause - Pause one or more containers ## SYNOPSIS -**podman pause** [*options*] *container* ... +**podman pause** [*options*] [*container*...] ## DESCRIPTION Pauses all the processes in one or more containers. You may use container IDs or names as input. +## OPTIONS + +**--all, -a** + +Pause all running containers. + ## EXAMPLE +Pause a container named 'mywebserver' +``` podman pause mywebserver +``` +Pause a container by partial container ID. +``` podman pause 860a4b23 +``` + +Pause all **running** containers. +``` +podman stop -a +``` ## SEE ALSO podman(1), podman-unpause(1) diff --git a/docs/podman-unpause.1.md b/docs/podman-unpause.1.md index 9404e7648..acfab0930 100644 --- a/docs/podman-unpause.1.md +++ b/docs/podman-unpause.1.md @@ -4,16 +4,34 @@ podman\-unpause - Unpause one or more containers ## SYNOPSIS -**podman unpause** [*options*] *container* ... +**podman unpause** [*options*] [*container*...] ## DESCRIPTION Unpauses the processes in one or more containers. You may use container IDs or names as input. +## OPTIONS + +**--all, -a** + +Unpause all paused containers. + ## EXAMPLE +Unpause a container called 'mywebserver' +``` podman unpause mywebserver +``` +Unpause a container by a partial container ID. + +``` podman unpause 860a4b23 +``` + +Unpause all **paused** containers. +``` +podman unpause -a +``` ## SEE ALSO podman(1), podman-pause(1) diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go index c34964f59..24876b6d6 100644 --- a/test/e2e/pause_test.go +++ b/test/e2e/pause_test.go @@ -213,4 +213,66 @@ var _ = Describe("Podman pause", func() { result.WaitWithDefaultTimeout() }) + It("Pause all containers (no containers exist)", func() { + result := podmanTest.Podman([]string{"pause", "--all"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + + }) + + It("Unpause all containers (no paused containers exist)", func() { + result := podmanTest.Podman([]string{"unpause", "--all"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) + + It("Pause a bunch of running containers", func() { + podmanTest.RestoreArtifact(nginx) + for i := 0; i < 3; i++ { + name := fmt.Sprintf("test%d", i) + run := podmanTest.Podman([]string{"run", "-dt", "--name", name, nginx}) + run.WaitWithDefaultTimeout() + Expect(run.ExitCode()).To(Equal(0)) + + } + running := podmanTest.Podman([]string{"ps", "-q"}) + running.WaitWithDefaultTimeout() + Expect(running.ExitCode()).To(Equal(0)) + Expect(len(running.OutputToStringArray())).To(Equal(3)) + + pause := podmanTest.Podman([]string{"pause", "--all"}) + pause.WaitWithDefaultTimeout() + Expect(pause.ExitCode()).To(Equal(0)) + + running = podmanTest.Podman([]string{"ps", "-q"}) + running.WaitWithDefaultTimeout() + Expect(running.ExitCode()).To(Equal(0)) + Expect(len(running.OutputToStringArray())).To(Equal(0)) + }) + + It("Unpause a bunch of running containers", func() { + podmanTest.RestoreArtifact(nginx) + for i := 0; i < 3; i++ { + name := fmt.Sprintf("test%d", i) + run := podmanTest.Podman([]string{"run", "-dt", "--name", name, nginx}) + run.WaitWithDefaultTimeout() + Expect(run.ExitCode()).To(Equal(0)) + + } + pause := podmanTest.Podman([]string{"pause", "--all"}) + pause.WaitWithDefaultTimeout() + Expect(pause.ExitCode()).To(Equal(0)) + + unpause := podmanTest.Podman([]string{"unpause", "--all"}) + unpause.WaitWithDefaultTimeout() + Expect(unpause.ExitCode()).To(Equal(0)) + + running := podmanTest.Podman([]string{"ps", "-q"}) + running.WaitWithDefaultTimeout() + Expect(running.ExitCode()).To(Equal(0)) + Expect(len(running.OutputToStringArray())).To(Equal(3)) + }) + }) -- cgit v1.2.3-54-g00ecf From 690c52a113124efcedccb84e44198e7602f064ec Mon Sep 17 00:00:00 2001 From: baude Date: Mon, 19 Nov 2018 13:20:56 -0600 Subject: Allow users to expose ports from the pod to the host we need to allow users to expose ports to the host for the purposes of networking, like a webserver. the port exposure must be done at the time the pod is created. strictly speaking, the port exposure occurs on the infra container. Signed-off-by: baude --- cmd/podman/pod_create.go | 59 ++++++++++++++++++ completions/bash/podman | 6 +- docs/podman-pod-create.1.md | 9 +++ libpod/options.go | 11 ++++ libpod/pod.go | 4 +- libpod/pod_easyjson.go | 128 ++++++++++++++++++++++++++++++++++++++ libpod/runtime_pod_infra_linux.go | 4 +- pkg/spec/createconfig.go | 1 - test/e2e/pod_create_test.go | 39 ++++++++++++ 9 files changed, 254 insertions(+), 7 deletions(-) (limited to 'completions/bash') diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go index 63fa6b294..a3364ac4b 100644 --- a/cmd/podman/pod_create.go +++ b/cmd/podman/pod_create.go @@ -3,11 +3,15 @@ package main import ( "fmt" "os" + "strconv" "strings" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/rootless" + "github.com/cri-o/ocicni/pkg/ocicni" + "github.com/docker/go-connections/nat" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -58,6 +62,10 @@ var podCreateFlags = []cli.Flag{ Name: "pod-id-file", Usage: "Write the pod ID to the file", }, + cli.StringSliceFlag{ + Name: "publish, p", + Usage: "Publish a container's port, or a range of ports, to the host (default [])", + }, cli.StringFlag{ Name: "share", Usage: "A comma delimited list of kernel namespaces the pod will share", @@ -102,6 +110,16 @@ func podCreateCmd(c *cli.Context) error { defer podIdFile.Close() defer podIdFile.Sync() } + + if len(c.StringSlice("publish")) > 0 { + if !c.BoolT("infra") { + return errors.Errorf("you must have an infra container to publish port bindings to the host") + } + if rootless.IsRootless() { + return errors.Errorf("rootless networking does not allow port binding to the host") + } + } + if !c.BoolT("infra") && c.IsSet("share") && c.String("share") != "none" && c.String("share") != "" { return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container") } @@ -131,6 +149,14 @@ func podCreateCmd(c *cli.Context) error { options = append(options, nsOptions...) } + if len(c.StringSlice("publish")) > 0 { + portBindings, err := CreatePortBindings(c.StringSlice("publish")) + if err != nil { + return err + } + options = append(options, libpod.WithInfraContainerPorts(portBindings)) + + } // always have containers use pod cgroups // User Opt out is not yet supported options = append(options, libpod.WithPodCgroups()) @@ -152,3 +178,36 @@ func podCreateCmd(c *cli.Context) error { return nil } + +// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands +func CreatePortBindings(ports []string) ([]ocicni.PortMapping, error) { + var portBindings []ocicni.PortMapping + // The conversion from []string to natBindings is temporary while mheon reworks the port + // deduplication code. Eventually that step will not be required. + _, natBindings, err := nat.ParsePortSpecs(ports) + if err != nil { + return nil, err + } + for containerPb, hostPb := range natBindings { + var pm ocicni.PortMapping + pm.ContainerPort = int32(containerPb.Int()) + for _, i := range hostPb { + var hostPort int + var err error + pm.HostIP = i.HostIP + if i.HostPort == "" { + hostPort = containerPb.Int() + } else { + hostPort, err = strconv.Atoi(i.HostPort) + if err != nil { + return nil, errors.Wrapf(err, "unable to convert host port to integer") + } + } + + pm.HostPort = int32(hostPort) + pm.Protocol = containerPb.Proto() + portBindings = append(portBindings, pm) + } + } + return portBindings, nil +} diff --git a/completions/bash/podman b/completions/bash/podman index c029f893a..222511a3c 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -2178,12 +2178,14 @@ _podman_pod_create() { --cgroup-parent --infra-command --infra-image - --share - --podidfile --label-file --label -l --name + --podidfile + --publish + -p + --share " local boolean_options=" diff --git a/docs/podman-pod-create.1.md b/docs/podman-pod-create.1.md index 673ad9a8c..a63b12d73 100644 --- a/docs/podman-pod-create.1.md +++ b/docs/podman-pod-create.1.md @@ -51,6 +51,15 @@ Assign a name to the pod Write the pod ID to the file +**-p**, **--publish**=[] + +Publish a port or range of ports from the pod to the host + +Format: `ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort` +Both hostPort and containerPort can be specified as a range of ports. +When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range. +Use `podman port` to see the actual mapping: `podman port CONTAINER $CONTAINERPORT` + **--share**="" A comma deliminated list of kernel namespaces to share. If none or "" is specified, no namespaces will be shared. The namespaces to choose from are ipc, net, pid, user, uts. diff --git a/libpod/options.go b/libpod/options.go index 8d044313b..507847d65 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1295,3 +1295,14 @@ func WithInfraContainer() PodCreateOption { return nil } } + +// WithInfraContainerPorts tells the pod to add port bindings to the pause container +func WithInfraContainerPorts(bindings []ocicni.PortMapping) PodCreateOption { + return func(pod *Pod) error { + if pod.valid { + return ErrPodFinalized + } + pod.config.InfraContainer.PortBindings = bindings + return nil + } +} diff --git a/libpod/pod.go b/libpod/pod.go index 8ac976f6a..07f41f5c6 100644 --- a/libpod/pod.go +++ b/libpod/pod.go @@ -4,6 +4,7 @@ import ( "time" "github.com/containers/storage" + "github.com/cri-o/ocicni/pkg/ocicni" "github.com/pkg/errors" ) @@ -96,7 +97,8 @@ type PodContainerInfo struct { // InfraContainerConfig is the configuration for the pod's infra container type InfraContainerConfig struct { - HasInfraContainer bool `json:"makeInfraContainer"` + HasInfraContainer bool `json:"makeInfraContainer"` + PortBindings []ocicni.PortMapping `json:"infraPortBindings"` } // ID retrieves the pod's ID diff --git a/libpod/pod_easyjson.go b/libpod/pod_easyjson.go index 6c1c939f3..8ea9a5e72 100644 --- a/libpod/pod_easyjson.go +++ b/libpod/pod_easyjson.go @@ -6,6 +6,7 @@ package libpod import ( json "encoding/json" + ocicni "github.com/cri-o/ocicni/pkg/ocicni" easyjson "github.com/mailru/easyjson" jlexer "github.com/mailru/easyjson/jlexer" jwriter "github.com/mailru/easyjson/jwriter" @@ -721,6 +722,29 @@ func easyjsonBe091417DecodeGithubComContainersLibpodLibpod5(in *jlexer.Lexer, ou switch key { case "makeInfraContainer": out.HasInfraContainer = bool(in.Bool()) + case "infraPortBindings": + if in.IsNull() { + in.Skip() + out.PortBindings = nil + } else { + in.Delim('[') + if out.PortBindings == nil { + if !in.IsDelim(']') { + out.PortBindings = make([]ocicni.PortMapping, 0, 1) + } else { + out.PortBindings = []ocicni.PortMapping{} + } + } else { + out.PortBindings = (out.PortBindings)[:0] + } + for !in.IsDelim(']') { + var v6 ocicni.PortMapping + easyjsonBe091417DecodeGithubComContainersLibpodVendorGithubComCriOOcicniPkgOcicni(in, &v6) + out.PortBindings = append(out.PortBindings, v6) + in.WantComma() + } + in.Delim(']') + } default: in.SkipRecursive() } @@ -745,5 +769,109 @@ func easyjsonBe091417EncodeGithubComContainersLibpodLibpod5(out *jwriter.Writer, } out.Bool(bool(in.HasInfraContainer)) } + { + const prefix string = ",\"infraPortBindings\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + if in.PortBindings == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v7, v8 := range in.PortBindings { + if v7 > 0 { + out.RawByte(',') + } + easyjsonBe091417EncodeGithubComContainersLibpodVendorGithubComCriOOcicniPkgOcicni(out, v8) + } + out.RawByte(']') + } + } + out.RawByte('}') +} +func easyjsonBe091417DecodeGithubComContainersLibpodVendorGithubComCriOOcicniPkgOcicni(in *jlexer.Lexer, out *ocicni.PortMapping) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "hostPort": + out.HostPort = int32(in.Int32()) + case "containerPort": + out.ContainerPort = int32(in.Int32()) + case "protocol": + out.Protocol = string(in.String()) + case "hostIP": + out.HostIP = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonBe091417EncodeGithubComContainersLibpodVendorGithubComCriOOcicniPkgOcicni(out *jwriter.Writer, in ocicni.PortMapping) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"hostPort\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.Int32(int32(in.HostPort)) + } + { + const prefix string = ",\"containerPort\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.Int32(int32(in.ContainerPort)) + } + { + const prefix string = ",\"protocol\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.Protocol)) + } + { + const prefix string = ",\"hostIP\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.HostIP)) + } out.RawByte('}') } diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go index fea79e994..450a2fb32 100644 --- a/libpod/runtime_pod_infra_linux.go +++ b/libpod/runtime_pod_infra_linux.go @@ -7,7 +7,6 @@ import ( "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/rootless" - "github.com/cri-o/ocicni/pkg/ocicni" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" ) @@ -50,9 +49,8 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID options = append(options, withIsInfra()) // Since user namespace sharing is not implemented, we only need to check if it's rootless - portMappings := make([]ocicni.PortMapping, 0) networks := make([]string, 0) - options = append(options, WithNetNS(portMappings, isRootless, networks)) + options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, isRootless, networks)) return r.newContainer(ctx, g.Config, options...) } diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index 6ac9d82da..6a0642ee7 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -335,7 +335,6 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib } options = append(options, runtime.WithPod(pod)) } - if len(c.PortBindings) > 0 { portBindings, err = c.CreatePortBindings() if err != nil { diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 51522ffd1..5abf9613b 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -80,4 +80,43 @@ var _ = Describe("Podman pod create", func() { check.WaitWithDefaultTimeout() Expect(len(check.OutputToStringArray())).To(Equal(0)) }) + + It("podman create pod without network portbindings", func() { + name := "test" + session := podmanTest.Podman([]string{"pod", "create", "--name", name}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + pod := session.OutputToString() + + webserver := podmanTest.Podman([]string{"run", "--pod", pod, "-dt", nginx}) + webserver.WaitWithDefaultTimeout() + Expect(webserver.ExitCode()).To(Equal(0)) + + check := SystemExec("nc", []string{"-z", "localhost", "80"}) + check.WaitWithDefaultTimeout() + Expect(check.ExitCode()).To(Equal(1)) + }) + + It("podman create pod with network portbindings", func() { + name := "test" + session := podmanTest.Podman([]string{"pod", "create", "--name", name, "-p", "80:80"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + pod := session.OutputToString() + + webserver := podmanTest.Podman([]string{"run", "--pod", pod, "-dt", nginx}) + webserver.WaitWithDefaultTimeout() + Expect(webserver.ExitCode()).To(Equal(0)) + + check := SystemExec("nc", []string{"-z", "localhost", "80"}) + check.WaitWithDefaultTimeout() + Expect(check.ExitCode()).To(Equal(0)) + }) + + It("podman create pod with no infra but portbindings should fail", func() { + name := "test" + session := podmanTest.Podman([]string{"pod", "create", "--infra=false", "--name", name, "-p", "80:80"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(125)) + }) }) -- cgit v1.2.3-54-g00ecf From 43c20d02006fb83d05414a2f868b1c0a4dd4346b Mon Sep 17 00:00:00 2001 From: Tomas Tomecek Date: Fri, 23 Nov 2018 22:25:45 +0100 Subject: implement --format for version command Signed-off-by: Tomas Tomecek --- cmd/podman/version.go | 33 ++++++++++++++++++++++++++++----- completions/bash/podman | 15 ++++++++++----- docs/podman-version.1.md | 23 +++++++++++++++++++++++ 3 files changed, 61 insertions(+), 10 deletions(-) (limited to 'completions/bash') diff --git a/cmd/podman/version.go b/cmd/podman/version.go index d80f24a14..d81deb696 100644 --- a/cmd/podman/version.go +++ b/cmd/podman/version.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/containers/libpod/cmd/podman/formats" "github.com/containers/libpod/libpod" "github.com/pkg/errors" "github.com/urfave/cli" @@ -15,6 +16,19 @@ func versionCmd(c *cli.Context) error { if err != nil { errors.Wrapf(err, "unable to determine version") } + + versionOutputFormat := c.String("format") + if versionOutputFormat != "" { + var out formats.Writer + switch versionOutputFormat { + case formats.JSONString: + out = formats.JSONStruct{Output: output} + default: + out = formats.StdoutTemplate{Output: output, Template: versionOutputFormat} + } + formats.Writer(out).Out() + return nil + } fmt.Println("Version: ", output.Version) fmt.Println("Go Version: ", output.GoVersion) if output.GitCommit != "" { @@ -30,8 +44,17 @@ func versionCmd(c *cli.Context) error { } // Cli command to print out the full version of podman -var versionCommand = cli.Command{ - Name: "version", - Usage: "Display the PODMAN Version Information", - Action: versionCmd, -} +var ( + versionCommand = cli.Command{ + Name: "version", + Usage: "Display the Podman Version Information", + Action: versionCmd, + Flags: versionFlags, + } + versionFlags = []cli.Flag{ + cli.StringFlag{ + Name: "format", + Usage: "Change the output format to JSON or a Go template", + }, + } +) diff --git a/completions/bash/podman b/completions/bash/podman index 222511a3c..8eaa1e6a9 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1906,11 +1906,16 @@ _podman_top() { } _podman_version() { - local options_with_args=" - " - local boolean_options=" - " - _complete_ "$options_with_args" "$boolean_options" + local boolean_options=" + --help + -h + " + local options_with_args=" + --format + " + local all_options="$options_with_args $boolean_options" + + _complete_ "$options_with_args" "$boolean_options" } _podman_save() { diff --git a/docs/podman-version.1.md b/docs/podman-version.1.md index 0c9b9ceed..749a33afd 100644 --- a/docs/podman-version.1.md +++ b/docs/podman-version.1.md @@ -16,8 +16,31 @@ OS, and Architecture. Print usage statement +**--format** + +Change output format to "json" or a Go template. + +## Example + +A sample output of the `version` command: +``` +$ podman version +Version: 0.11.1 +Go Version: go1.11 +Git Commit: "8967a1d691ed44896b81ad48c863033f23c65eb0-dirty" +Built: Thu Nov 8 22:35:40 2018 +OS/Arch: linux/amd64 +``` + +Filtering out only the version: +``` +$ podman version --format '{{.Version}}' +0.11.2 +``` + ## SEE ALSO podman(1), crio(8) ## HISTORY +November 2018, Added --format flag by Tomas Tomecek July 2017, Originally compiled by Urvashi Mohnani -- cgit v1.2.3-54-g00ecf From 9d883d2032b112d5c65040629313cfba0de6c479 Mon Sep 17 00:00:00 2001 From: baude Date: Sun, 25 Nov 2018 16:26:39 -0600 Subject: add podman container|image exists Add an exists subcommand to podman container and podman image that allows users to verify the existence of a container or image by ID or name. The return code can be 0 (success), 1 (failed to find), or 125 (failed to work with runtime). Issue #1845 Signed-off-by: baude --- cmd/podman/container.go | 1 + cmd/podman/exists.go | 83 ++++++++++++++++++++++++++++++++++++++ cmd/podman/image.go | 1 + completions/bash/podman | 16 ++++++++ docs/podman-container-exists.1.md | 40 ++++++++++++++++++ docs/podman-container.1.md | 1 + docs/podman-image-exists.1.md | 40 ++++++++++++++++++ docs/podman-image.1.md | 1 + libpod/image/errors.go | 15 +++++++ libpod/image/image.go | 4 +- test/e2e/exists_test.go | 85 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 cmd/podman/exists.go create mode 100644 docs/podman-container-exists.1.md create mode 100644 docs/podman-image-exists.1.md create mode 100644 libpod/image/errors.go create mode 100644 test/e2e/exists_test.go (limited to 'completions/bash') diff --git a/cmd/podman/container.go b/cmd/podman/container.go index ff634278f..b6262f890 100644 --- a/cmd/podman/container.go +++ b/cmd/podman/container.go @@ -9,6 +9,7 @@ var ( attachCommand, checkpointCommand, cleanupCommand, + containerExistsCommand, commitCommand, createCommand, diffCommand, diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go new file mode 100644 index 000000000..2f7b7c185 --- /dev/null +++ b/cmd/podman/exists.go @@ -0,0 +1,83 @@ +package main + +import ( + "os" + + "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/image" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var ( + imageExistsDescription = ` + podman image exists + + Check if an image exists in local storage +` + + imageExistsCommand = cli.Command{ + Name: "exists", + Usage: "Check if an image exists in local storage", + Description: imageExistsDescription, + Action: imageExistsCmd, + ArgsUsage: "IMAGE-NAME", + OnUsageError: usageErrorHandler, + } +) + +var ( + containerExistsDescription = ` + podman container exists + + Check if a container exists in local storage +` + + containerExistsCommand = cli.Command{ + Name: "exists", + Usage: "Check if a container exists in local storage", + Description: containerExistsDescription, + Action: containerExistsCmd, + ArgsUsage: "CONTAINER-NAME", + OnUsageError: usageErrorHandler, + } +) + +func imageExistsCmd(c *cli.Context) error { + args := c.Args() + if len(args) > 1 || len(args) < 1 { + return errors.New("you may only check for the existence of one image at a time") + } + runtime, err := libpodruntime.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + if _, err := runtime.ImageRuntime().NewFromLocal(args[0]); err != nil { + if errors.Cause(err) == image.ErrNoSuchImage { + os.Exit(1) + } + return err + } + return nil +} + +func containerExistsCmd(c *cli.Context) error { + args := c.Args() + if len(args) > 1 || len(args) < 1 { + return errors.New("you may only check for the existence of one container at a time") + } + runtime, err := libpodruntime.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + if _, err := runtime.LookupContainer(args[0]); err != nil { + if errors.Cause(err) == libpod.ErrNoSuchCtr { + os.Exit(1) + } + return err + } + return nil +} diff --git a/cmd/podman/image.go b/cmd/podman/image.go index e67f61799..418b442e3 100644 --- a/cmd/podman/image.go +++ b/cmd/podman/image.go @@ -9,6 +9,7 @@ var ( buildCommand, historyCommand, importCommand, + imageExistsCommand, inspectCommand, loadCommand, lsImagesCommand, diff --git a/completions/bash/podman b/completions/bash/podman index 8eaa1e6a9..3c6b6ec50 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -2178,6 +2178,22 @@ _podman_container_runlabel() { esac } +_podman_container_exists() { + local options_with_args=" + " + + local boolean_options=" + " +} + +_podman_image_exists() { + local options_with_args=" + " + + local boolean_options=" + " +} + _podman_pod_create() { local options_with_args=" --cgroup-parent diff --git a/docs/podman-container-exists.1.md b/docs/podman-container-exists.1.md new file mode 100644 index 000000000..76701e2c2 --- /dev/null +++ b/docs/podman-container-exists.1.md @@ -0,0 +1,40 @@ +% PODMAN(1) Podman Man Pages +% Brent Baude +% November 2018 +# NAME +podman-container-exists- Check if a container exists in local storage + +# SYNOPSIS +**podman container exists** +[**-h**|**--help**] +CONTAINER + +# DESCRIPTION +**podman container exists** checks if a container exists in local storage. The **ID** or **Name** +of the container may be used as input. Podman will return an exit code +of `0` when the container is found. A `1` will be returned otherwise. An exit code of `125` indicates there +was an issue accessing the local storage. + +## Examples ## + +Check if an container called `webclient` exists in local storage (the container does actually exist). +``` +$ sudo podman container exists webclient +$ echo $? +0 +$ +``` + +Check if an container called `webbackend` exists in local storage (the container does not actually exist). +``` +$ sudo podman container exists webbackend +$ echo $? +1 +$ +``` + +## SEE ALSO +podman(1) + +# HISTORY +November 2018, Originally compiled by Brent Baude (bbaude at redhat dot com) diff --git a/docs/podman-container.1.md b/docs/podman-container.1.md index 67d42bfef..aa5dfa82c 100644 --- a/docs/podman-container.1.md +++ b/docs/podman-container.1.md @@ -20,6 +20,7 @@ The container command allows you to manage containers | create | [podman-create(1)](podman-create.1.md) | Create a new container. | | diff | [podman-diff(1)](podman-diff.1.md) | Inspect changes on a container or image's filesystem. | | exec | [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. | +| exists | [podman-exists(1)](podman-container-exists.1.md) | Check if a container exists in local storage | | export | [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. | | inspect | [podman-inspect(1)](podman-inspect.1.md) | Display a container or image's configuration. | | kill | [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. | diff --git a/docs/podman-image-exists.1.md b/docs/podman-image-exists.1.md new file mode 100644 index 000000000..e04c23721 --- /dev/null +++ b/docs/podman-image-exists.1.md @@ -0,0 +1,40 @@ +% PODMAN(1) Podman Man Pages +% Brent Baude +% November 2018 +# NAME +podman-image-exists- Check if an image exists in local storage + +# SYNOPSIS +**podman image exists** +[**-h**|**--help**] +IMAGE + +# DESCRIPTION +**podman image exists** checks if an image exists in local storage. The **ID** or **Name** +of the image may be used as input. Podman will return an exit code +of `0` when the image is found. A `1` will be returned otherwise. An exit code of `125` indicates there +was an issue accessing the local storage. + +## Examples ## + +Check if an image called `webclient` exists in local storage (the image does actually exist). +``` +$ sudo podman image exists webclient +$ echo $? +0 +$ +``` + +Check if an image called `webbackend` exists in local storage (the image does not actually exist). +``` +$ sudo podman image exists webbackend +$ echo $? +1 +$ +``` + +## SEE ALSO +podman(1) + +# HISTORY +November 2018, Originally compiled by Brent Baude (bbaude at redhat dot com) diff --git a/docs/podman-image.1.md b/docs/podman-image.1.md index 33de0456f..446f8667d 100644 --- a/docs/podman-image.1.md +++ b/docs/podman-image.1.md @@ -14,6 +14,7 @@ The image command allows you to manage images | Command | Man Page | Description | | -------- | ----------------------------------------- | ------------------------------------------------------------------------------ | | build | [podman-build(1)](podman-build.1.md) | Build a container using a Dockerfile. | +| exists | [podman-exists(1)](podman-image-exists.1.md) | Check if a image exists in local storage | | history | [podman-history(1)](podman-history.1.md) | Show the history of an image. | | import | [podman-import(1)](podman-import.1.md) | Import a tarball and save it as a filesystem image. | | inspect | [podman-inspect(1)](podman-inspect.1.md) | Display a image or image's configuration. | diff --git a/libpod/image/errors.go b/libpod/image/errors.go new file mode 100644 index 000000000..4088946cb --- /dev/null +++ b/libpod/image/errors.go @@ -0,0 +1,15 @@ +package image + +import ( + "errors" +) + +// Copied directly from libpod errors to avoid circular imports +var ( + // ErrNoSuchCtr indicates the requested container does not exist + ErrNoSuchCtr = errors.New("no such container") + // ErrNoSuchPod indicates the requested pod does not exist + ErrNoSuchPod = errors.New("no such pod") + // ErrNoSuchImage indicates the requested image does not exist + ErrNoSuchImage = errors.New("no such image") +) diff --git a/libpod/image/image.go b/libpod/image/image.go index 7e520d97e..a05c15160 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -252,7 +252,7 @@ func (i *Image) getLocalImage() (*storage.Image, error) { // The image has a registry name in it and we made sure we looked for it locally // with a tag. It cannot be local. if decomposedImage.hasRegistry { - return nil, errors.Errorf("%s", imageError) + return nil, errors.Wrapf(ErrNoSuchImage, imageError) } @@ -275,7 +275,7 @@ func (i *Image) getLocalImage() (*storage.Image, error) { return repoImage, nil } - return nil, errors.Wrapf(err, imageError) + return nil, errors.Wrapf(ErrNoSuchImage, err.Error()) } // ID returns the image ID as a string diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go new file mode 100644 index 000000000..9165e8902 --- /dev/null +++ b/test/e2e/exists_test.go @@ -0,0 +1,85 @@ +package integration + +import ( + "fmt" + "os" + + . "github.com/containers/libpod/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman image|container exists", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.RestoreAllArtifacts() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds()) + GinkgoWriter.Write([]byte(timedResult)) + + }) + It("podman image exists in local storage by fq name", func() { + session := podmanTest.Podman([]string{"image", "exists", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman image exists in local storage by short name", func() { + session := podmanTest.Podman([]string{"image", "exists", "alpine"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman image does not exist in local storage", func() { + session := podmanTest.Podman([]string{"image", "exists", "alpine9999"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + }) + It("podman container exists in local storage by name", func() { + setup := podmanTest.RunTopContainer("foobar") + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + + session := podmanTest.Podman([]string{"container", "exists", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman container exists in local storage by container ID", func() { + setup := podmanTest.RunTopContainer("") + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + cid := setup.OutputToString() + + session := podmanTest.Podman([]string{"container", "exists", cid}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman container exists in local storage by short container ID", func() { + setup := podmanTest.RunTopContainer("") + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + cid := setup.OutputToString()[0:12] + + session := podmanTest.Podman([]string{"container", "exists", cid}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman container does not exist in local storage", func() { + session := podmanTest.Podman([]string{"container", "exists", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + }) + +}) -- cgit v1.2.3-54-g00ecf From 4ed10c5c7aafbbc49555a82b3ac96df6653c6e90 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 21 Nov 2018 15:37:11 +0000 Subject: Update bash completion for checkpoint/restore This brings all the recent changes to checkpoint/restore to the bash completion. Signed-off-by: Adrian Reber --- completions/bash/podman | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'completions/bash') diff --git a/completions/bash/podman b/completions/bash/podman index 3c6b6ec50..c34381e2b 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -716,16 +716,22 @@ _podman_container_attach() { } _podman_container_checkpoint() { - local options_with_args=" - --help -h - " local boolean_options=" - --keep + -a + --all + -h + --help -k + --keep + -l + --latest + -R + --leave-running + --tcp-established " case "$cur" in -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + COMPREPLY=($(compgen -W "$boolean_options" -- "$cur")) ;; *) __podman_complete_containers_running @@ -794,16 +800,20 @@ _podman_container_restart() { } _podman_container_restore() { - local options_with_args=" - --help -h - " local boolean_options=" - --keep + -a + --all + -h + --help -k + --keep + -l + --latest + --tcp-established " case "$cur" in -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + COMPREPLY=($(compgen -W "$boolean_options" -- "$cur")) ;; *) __podman_complete_containers_created -- cgit v1.2.3-54-g00ecf From 6e0f10f19be142df6e5db23871106b67fcfa8be4 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Wed, 28 Nov 2018 14:03:12 -0500 Subject: Fix completions to work with podman run command Also add missing --help and -h and add some consistency to the usage of boolean_options. Signed-off-by: Daniel J Walsh --- completions/bash/podman | 1057 +++++++++++++++++++++++++---------------------- 1 file changed, 558 insertions(+), 499 deletions(-) (limited to 'completions/bash') diff --git a/completions/bash/podman b/completions/bash/podman index c34381e2b..076ec7ab4 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -5,7 +5,7 @@ __podman_previous_extglob_setting=$(shopt -p extglob) shopt -s extglob __podman_q() { - podman ${host:+-H "$host"} ${config:+--config "$config"} 2>/dev/null "$@" + podman ${host:+-H "$host"} ${config:+--config "$config"} 2>/dev/null "$@" } # __podman_containers returns a list of containers. Additional options to @@ -232,7 +232,7 @@ __podman_services() { fields='$2' # names only shift fi - __podman_q service ls "$@" | awk "NR>1 {print $fields}" + __podman_q service ls "$@" | awk "NR>1 {print $fields}" } # __podman_complete_services applies completion of services based on the current @@ -694,20 +694,20 @@ _podman_attach() { --detach-keys " local boolean_options=" - --help - -h - --latest - -l - --no-stdin - --sig-proxy + --help + -h + --latest + -l + --no-stdin + --sig-proxy " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_containers_running + ;; esac } @@ -730,12 +730,12 @@ _podman_container_checkpoint() { --tcp-established " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options" -- "$cur")) + ;; + *) + __podman_complete_containers_running + ;; esac } @@ -791,6 +791,8 @@ _podman_container_refresh() { local options_with_args=" " local boolean_options=" + --help + -h " _complete_ "$options_with_args" "$boolean_options" } @@ -801,23 +803,23 @@ _podman_container_restart() { _podman_container_restore() { local boolean_options=" - -a - --all - -h - --help - -k - --keep - -l - --latest - --tcp-established + -a + --all + -h + --help + -k + --keep + -l + --latest + --tcp-established " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options" -- "$cur")) - ;; - *) - __podman_complete_containers_created - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options" -- "$cur")) + ;; + *) + __podman_complete_containers_created + ;; esac } @@ -825,10 +827,6 @@ _podman_container_rm() { _podman_rm } -_podman_container_run() { - _podman_run -} - _podman_container_start() { _podman_start } @@ -931,29 +929,29 @@ _podman_commit() { _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_container_names + ;; esac } _podman_build() { local boolean_options=" - --force-rm - --help - -h - --layers - --no-cache - --pull - --pull-always - --quiet - -q - --rm - --squash - --tls-verify + --force-rm + --help + -h + --layers + --no-cache + --pull + --pull-always + --quiet + -q + --rm + --squash + --tls-verify " local options_with_args=" @@ -1006,18 +1004,18 @@ _podman_build() { local all_options="$options_with_args $boolean_options" case "$prev" in - --runtime) - COMPREPLY=($(compgen -W 'runc runv' -- "$cur")) - ;; - $(__podman_to_extglob "$options_with_args")) + --runtime) + COMPREPLY=($(compgen -W 'runc runv' -- "$cur")) + ;; + $(__podman_to_extglob "$options_with_args")) return ;; esac case "$cur" in -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; esac } @@ -1026,16 +1024,18 @@ _podman_diff() { --format " local boolean_options=" - " + --help + -h + " _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_container_names + ;; esac } @@ -1047,19 +1047,21 @@ _podman_exec() { -u " local boolean_options=" - --latest - -l - --privileged - --tty - -t + --help + -h + --latest + -l + --privileged + --tty + -t " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_containers_running + ;; esac } @@ -1069,14 +1071,16 @@ _podman_export() { -o " local boolean_options=" + --help + -h " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; + -*) + COMPREPLY=($(compgen -W "$options_with_args" -- "$cur")) + ;; + *) + __podman_complete_container_names + ;; esac } @@ -1085,19 +1089,21 @@ _podman_history() { --format " local boolean_options=" - --human -H - --no-trunc - --quiet -q + --help + -h + --human -H + --no-trunc + --quiet -q " _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_images --id + ;; esac } @@ -1118,20 +1124,20 @@ _podman_import() { _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_list_images - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_list_images + ;; esac } _podman_info() { local boolean_options=" - --help - -h - --debug + --help + -h + --debug " local options_with_args=" --format @@ -1140,12 +1146,12 @@ _podman_info() { local all_options="$options_with_args $boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_list_images - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_list_images + ;; esac } @@ -1201,7 +1207,7 @@ _podman_image() { local boolean_options=" --help -h - " + " subcommands=" build history @@ -1232,20 +1238,20 @@ _podman_image() { _podman_images() { local boolean_options=" - -a - --all - --digests - --digests - -f - --filter - -h - --help - --no-trunc - --notruncate - -n - --noheading - -q - --quiet + -a + --all + --digests + --digests + -f + --filter + -h + --help + --no-trunc + --notruncate + -n + --noheading + -q + --quiet " local options_with_args=" --format @@ -1255,22 +1261,22 @@ _podman_images() { local all_options="$options_with_args $boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_images --id + ;; esac } _podman_inspect() { local boolean_options=" - --help - -h - --latest - -l - " + --help + -h + --latest + -l + " local options_with_args=" --format -f @@ -1335,20 +1341,20 @@ _podman_kill() { --signal -s " local boolean_options=" - --all - -a - --help - -h - --latest - -l + --all + -a + --help + -h + --latest + -l " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_containers_running + ;; esac } @@ -1358,22 +1364,24 @@ _podman_logs() { --tail " local boolean_options=" - --follow - -f - --latest - -l - --timestamps - -t + --follow + -f + --help + -h + --latest + -l + --timestamps + -t " _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_list_containers - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_list_containers + ;; esac } @@ -1385,10 +1393,13 @@ _podman_pull() { --signature-policy " local boolean_options=" - --all-tags -a - --quiet - -q - --tls-verify + --all-tags + -a + --help + -h + --quiet + -q + --tls-verify " _complete_ "$options_with_args" "$boolean_options" } @@ -1401,7 +1412,9 @@ _podman_search() { --limit " local boolean_options=" - --no-trunc + --help + -h + --no-trunc " _complete_ "$options_with_args" "$boolean_options" } @@ -1412,56 +1425,58 @@ _podman_unmount() { _podman_umount() { local boolean_options=" - --all - -a - --force - -f - --help - -h - " + --all + -a + --help + -h + --force + -f + " local options_with_args=" - " + " local all_options="$options_with_args $boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_container_names + ;; esac } _podman_mount() { local boolean_options=" - --help - -h - --notruncate - " + --help + -h + --notruncate + " local options_with_args=" - --format - " + --format + " local all_options="$options_with_args $boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_container_names + ;; esac } _podman_push() { local boolean_options=" - --compress - --quiet - -q - --remove-signatures - --tls-verify + --compress + --help + -h + --quiet + -q + --remove-signatures + --tls-verify " local options_with_args=" @@ -1476,12 +1491,12 @@ _podman_push() { local all_options="$options_with_args $boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_images --id + ;; esac } @@ -1563,16 +1578,17 @@ _podman_container_run() { " local boolean_options=" - --disable-content-trust=false - --help - --init - --interactive -i - --oom-kill-disable - --privileged - --publish-all -P - --quiet - --read-only - --tty -t + --disable-content-trust=false + --help + -h + --init + --interactive -i + --oom-kill-disable + --privileged + --publish-all -P + --quiet + --read-only + --tty -t " if [ "$command" = "run" -o "$subcommand" = "run" ] ; then @@ -1593,12 +1609,13 @@ _podman_container_run() { fi case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + return + ;; + *) + __podman_complete_images --id + ;; esac @@ -1781,33 +1798,38 @@ _podman_restart() { --timeout -t " local boolean_options=" - --all - -a - --latest - -l - --running - --timeout - -t" + --all + -a + --help + -h + --latest + -l + --running + --timeout + -t + " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_containers_running + ;; esac } _podman_rm() { local boolean_options=" - --all - -a - --force - -f - --latest - -l - --volumes - -v + --all + -a + --force + -f + --help + -h + --latest + -l + --volumes + -v " local options_with_args=" @@ -1816,52 +1838,53 @@ _podman_rm() { local all_options="$options_with_args $boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_container_names + ;; esac } _podman_rmi() { local boolean_options=" - --help - -h - --force - -f - -a - --all + --all + -a + --force + -f + --help + -h " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_images --id + ;; esac } _podman_stats() { local boolean_options=" - --help - --all - -a - --no-stream - --format - --no-reset + --all + -a + --help + -h + --no-stream + --format + --no-reset " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_containers_running + ;; esac } @@ -1869,49 +1892,51 @@ _podman_tag() { local options_with_args=" " local boolean_options=" + --help + -h " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_images + ;; esac } __podman_top_descriptors() { - podman top --list-descriptors + podman top --list-descriptors } __podman_complete_top_descriptors() { - COMPREPLY=($(compgen -W "$(__podman_top_descriptors)" -- "$cur")) + COMPREPLY=($(compgen -W "$(__podman_top_descriptors)" -- "$cur")) } _podman_top() { local options_with_args=" " local boolean_options=" - --help - -h - --latest - -l + --help + -h + --latest + -l " # podman-top works on only *one* container, which means that when we have # three or more arguments, we can complete with top descriptors. if [[ "${COMP_CWORD}" -ge 3 ]]; then - __podman_complete_top_descriptors - return + __podman_complete_top_descriptors + return fi case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_containers_running + ;; esac } @@ -1934,56 +1959,61 @@ _podman_save() { --format " local boolean_options=" - --compress - -q - --quiet + --compress + --help + -h + -q + --quiet " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_images --id + ;; esac } _podman_pause() { local boolean_options=" - -a - --all + --all + -a + --help + -h " local options_with_args=" - --help -h " local boolean_options="" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_containers_running + ;; esac } _podman_port() { local options_with_args=" - --help -h " local boolean_options=" - --all - -a - -l - --latest" + --all + -a + --help + -h + -l + --latest + " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_container_names + ;; esac } @@ -1999,13 +2029,14 @@ _podman_ps() { --sort " local boolean_options=" - --all -a - --latest -l - --no-trunc - --pod - --quiet -q - --size -s - --namespace --ns + --all -a + --help -h + --latest -l + --no-trunc + --pod + --quiet -q + --size -s + --namespace --ns " _complete_ "$options_with_args" "$boolean_options" } @@ -2016,23 +2047,23 @@ _podman_start() { " local boolean_options=" - -h - --help - -a - --attach - -i - --interactive - --latest - -l - --sig-proxy + --attach + -a + -h + --help + -i + --interactive + --latest + -l + --sig-proxy " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_container_names + ;; esac } _podman_stop() { @@ -2040,64 +2071,70 @@ _podman_stop() { --timeout -t " local boolean_options=" - --all - -a - --latest - -l" + --all + -a + -h + --help + --latest + -l + " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_containers_running + ;; esac } _podman_unpause() { local boolean_options=" - -a - --all + --all + -a + --help + -h " local options_with_args=" - --help -h " - local boolean_options="" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_unpauseable - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_containers_unpauseable + ;; esac } _podman_varlink() { local options_with_args=" - --help -h --timeout -t " - local boolean_options="" + local boolean_options=" + --help + -h + " _complete_ "$options_with_args" "$boolean_options" } _podman_wait() { local options_with_args="" local boolean_options=" - --help - -h - -i + --help + -h + -i -l - --interval - --latest" + --interval + --latest + " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_container_names + ;; esac } @@ -2124,8 +2161,10 @@ _podman_load() { --signature-policy " local boolean_options=" - --quiet - -q + --help + -h + --quiet + -q " _complete_ "$options_with_args" "$boolean_options" } @@ -2139,8 +2178,8 @@ _podman_login() { --authfile " local boolean_options=" - --help - -h + --help + -h " _complete_ "$options_with_args" "$boolean_options" } @@ -2150,10 +2189,10 @@ _podman_logout() { --authfile " local boolean_options=" - --all - -a - --help - -h + --all + -a + --help + -h " _complete_ "$options_with_args" "$boolean_options" } @@ -2168,23 +2207,23 @@ _podman_container_runlabel() { " local boolean_options=" - --display - --help - -h - -p - --pull - -q - --quiet - --tls-verify + --display + --help + -h + -p + --pull + -q + --quiet + --tls-verify " case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_images --id + ;; esac } @@ -2220,7 +2259,9 @@ _podman_pod_create() { " local boolean_options=" - --infra + --help + -h + --infra " _complete_ "$options_with_args" "$boolean_options" } @@ -2230,21 +2271,23 @@ _podman_pod_kill() { " local boolean_options=" - --all - -a - --signal - -s - --latest - -l + --all + -a + --help + -h + --signal + -s + --latest + -l " _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_pod_names + ;; esac } @@ -2257,16 +2300,18 @@ __podman_pod_ps() { " local boolean_options=" - --cgroup - --ctr-ids - --ctr-names - --ctr-status - -q - --quiet - --no-trunc - --labels - -l - --latest + --cgroup + --ctr-ids + --ctr-names + --ctr-status + --help + -h + -q + --quiet + --no-trunc + --labels + -l + --latest " _complete_ "$options_with_args" "$boolean_options" } @@ -2288,19 +2333,21 @@ _podman_pod_restart() { " local boolean_options=" - --all - -a - --latest - -l + --all + -a + --help + -h + --latest + -l " _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_pod_names + ;; esac } @@ -2309,21 +2356,23 @@ _podman_pod_rm() { " local boolean_options=" - -a - --all - -f - --force - --latest - -l + -a + --all + --help + -h + -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 - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_pod_names + ;; esac } @@ -2332,19 +2381,21 @@ _podman_pod_start() { " local boolean_options=" - --all - -a - --latest - -l + --all + -a + --help + -h + --latest + -l " _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_pod_names + ;; esac } @@ -2353,20 +2404,22 @@ _podman_pod_stop() { " local boolean_options=" - --all - -a - --cleanup - --latest - -l + --all + -a + --cleanup + --help + -h + --latest + -l " _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_pod_names + ;; esac } @@ -2375,19 +2428,21 @@ _podman_pod_pause() { " local boolean_options=" - --all - -a - --latest - -l + --all + -a + --help + -h + --latest + -l " _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_pod_names + ;; esac } @@ -2396,26 +2451,28 @@ _podman_pod_unpause() { " local boolean_options=" - --all - -a - --latest - -l + --all + -a + --help + -h + --latest + -l " _complete_ "$options_with_args" "$boolean_options" case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_pod_names + ;; esac } _podman_pod() { local boolean_options=" - --help - -h + --help + -h " subcommands=" create @@ -2438,29 +2495,31 @@ _podman_pod() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; esac } _podman_podman() { local options_with_args=" - --config -c - --cpu-profile - --root - --runroot - --storage-driver - --storage-opt - --log-level - --namespace + --config -c + --cpu-profile + --root + --runroot + --storage-driver + --storage-opt + --log-level + --namespace " local boolean_options=" - --help -h - --version -v - --syslog + --help + -h + --version + -v + --syslog " commands=" attach -- cgit v1.2.3-54-g00ecf From 82bcef38954b4d03b7e047d7843e77bc94647c82 Mon Sep 17 00:00:00 2001 From: baude Date: Fri, 30 Nov 2018 09:15:11 -0600 Subject: add pod short option to ps podman ps has a flag --pod; simply adding a short option of -p Signed-off-by: baude --- cmd/podman/ps.go | 2 +- completions/bash/podman | 2 +- docs/podman-ps.1.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'completions/bash') diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go index 83274c9a8..0b03388a2 100644 --- a/cmd/podman/ps.go +++ b/cmd/podman/ps.go @@ -184,7 +184,7 @@ var ( Usage: "Display the extended information", }, cli.BoolFlag{ - Name: "pod", + Name: "pod, p", Usage: "Print the ID and name of the pod the containers are associated with", }, cli.BoolFlag{ diff --git a/completions/bash/podman b/completions/bash/podman index 076ec7ab4..3cccf2192 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -2033,7 +2033,7 @@ _podman_ps() { --help -h --latest -l --no-trunc - --pod + --pod -p --quiet -q --size -s --namespace --ns diff --git a/docs/podman-ps.1.md b/docs/podman-ps.1.md index 2cb77ffed..7333a1095 100644 --- a/docs/podman-ps.1.md +++ b/docs/podman-ps.1.md @@ -24,7 +24,7 @@ all the containers information. By default it lists: Show all the containers, default is only running containers -**--pod** +**--pod, -p** Display the pods the containers are associated with -- cgit v1.2.3-54-g00ecf From 318bf7017bcb82da9f73cfce9e3a963b61252788 Mon Sep 17 00:00:00 2001 From: baude Date: Sat, 1 Dec 2018 13:51:58 -0600 Subject: podman pod exists like containers and images, users would benefit from being able to check if a pod exists in local storage. if the pod exists, the return code is 0. if the pod does not exists, the return code is 1. Any other return code indicates a real errors, such as permissions or runtime. Signed-off-by: baude --- cmd/podman/exists.go | 37 +++++++++++++++++++++++++++++++++++++ cmd/podman/pod.go | 1 + completions/bash/podman | 8 ++++++++ docs/podman-pod-exists.1.md | 40 ++++++++++++++++++++++++++++++++++++++++ test/e2e/exists_test.go | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 docs/podman-pod-exists.1.md (limited to 'completions/bash') diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go index 2f7b7c185..2e2559ec7 100644 --- a/cmd/podman/exists.go +++ b/cmd/podman/exists.go @@ -44,6 +44,23 @@ var ( } ) +var ( + podExistsDescription = ` + podman pod exists + + Check if a pod exists in local storage +` + + podExistsCommand = cli.Command{ + Name: "exists", + Usage: "Check if a pod exists in local storage", + Description: podExistsDescription, + Action: podExistsCmd, + ArgsUsage: "POD-NAME", + OnUsageError: usageErrorHandler, + } +) + func imageExistsCmd(c *cli.Context) error { args := c.Args() if len(args) > 1 || len(args) < 1 { @@ -81,3 +98,23 @@ func containerExistsCmd(c *cli.Context) error { } return nil } + +func podExistsCmd(c *cli.Context) error { + args := c.Args() + if len(args) > 1 || len(args) < 1 { + return errors.New("you may only check for the existence of one pod at a time") + } + runtime, err := libpodruntime.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + + if _, err := runtime.LookupPod(args[0]); err != nil { + if errors.Cause(err) == libpod.ErrNoSuchPod { + os.Exit(1) + } + return err + } + return nil +} diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go index 0c6ec5e8c..a30361134 100644 --- a/cmd/podman/pod.go +++ b/cmd/podman/pod.go @@ -11,6 +11,7 @@ Pods are a group of one or more containers sharing the same network, pid and ipc ` podSubCommands = []cli.Command{ podCreateCommand, + podExistsCommand, podInspectCommand, podKillCommand, podPauseCommand, diff --git a/completions/bash/podman b/completions/bash/podman index 3cccf2192..9518cfa22 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -2235,6 +2235,14 @@ _podman_container_exists() { " } +_podman_pod_exists() { + local options_with_args=" + " + + local boolean_options=" + " +} + _podman_image_exists() { local options_with_args=" " diff --git a/docs/podman-pod-exists.1.md b/docs/podman-pod-exists.1.md new file mode 100644 index 000000000..8fb2fc90e --- /dev/null +++ b/docs/podman-pod-exists.1.md @@ -0,0 +1,40 @@ +% podman-pod-exits(1) Podman Man Pages +% Brent Baude +% December 2018 +# NAME +podman-pod-exists- Check if a pod exists in local storage + +# SYNOPSIS +**podman pod exists** +[**-h**|**--help**] +POD + +# DESCRIPTION +**podman pod exists** checks if a pod exists in local storage. The **ID** or **Name** +of the pod may be used as input. Podman will return an exit code +of `0` when the pod is found. A `1` will be returned otherwise. An exit code of `125` indicates there +was an issue accessing the local storage. + +## Examples ## + +Check if a pod called `web` exists in local storage (the pod does actually exist). +``` +$ sudo podman pod exists web +$ echo $? +0 +$ +``` + +Check if a pod called `backend` exists in local storage (the pod does not actually exist). +``` +$ sudo podman pod exists backend +$ echo $? +1 +$ +``` + +## SEE ALSO +podman-pod(1), podman(1) + +# HISTORY +December 2018, Originally compiled by Brent Baude (bbaude at redhat dot com) diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go index 9165e8902..d9652de4b 100644 --- a/test/e2e/exists_test.go +++ b/test/e2e/exists_test.go @@ -82,4 +82,36 @@ var _ = Describe("Podman image|container exists", func() { Expect(session.ExitCode()).To(Equal(1)) }) + It("podman pod exists in local storage by name", func() { + setup, rc, _ := podmanTest.CreatePod("foobar") + setup.WaitWithDefaultTimeout() + Expect(rc).To(Equal(0)) + + session := podmanTest.Podman([]string{"pod", "exists", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman pod exists in local storage by container ID", func() { + setup, rc, podID := podmanTest.CreatePod("") + setup.WaitWithDefaultTimeout() + Expect(rc).To(Equal(0)) + + session := podmanTest.Podman([]string{"pod", "exists", podID}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman pod exists in local storage by short container ID", func() { + setup, rc, podID := podmanTest.CreatePod("") + setup.WaitWithDefaultTimeout() + Expect(rc).To(Equal(0)) + + session := podmanTest.Podman([]string{"pod", "exists", podID[0:12]}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman pod does not exist in local storage", func() { + session := podmanTest.Podman([]string{"pod", "exists", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + }) }) -- cgit v1.2.3-54-g00ecf