summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhaircommander <pehunt@redhat.com>2018-07-23 16:02:46 -0400
committerAtomic Bot <atomic-devel@projectatomic.io>2018-07-25 17:54:27 +0000
commit8ce0e0b2460220fccbb31fced940604b55d8a195 (patch)
tree87af55c87040d4f61424f19e19e778051e184a41
parent7789284cbe8f5068d66c90c257b9784505d4a027 (diff)
downloadpodman-8ce0e0b2460220fccbb31fced940604b55d8a195.tar.gz
podman-8ce0e0b2460220fccbb31fced940604b55d8a195.tar.bz2
podman-8ce0e0b2460220fccbb31fced940604b55d8a195.zip
Added pod restart
With tests, man page and completions. Signed-off-by: haircommander <pehunt@redhat.com> Closes: #1152 Approved by: rhatdan
-rw-r--r--cmd/podman/pod.go1
-rw-r--r--cmd/podman/pod_restart.go98
-rw-r--r--commands.md1
-rw-r--r--completions/bash/podman22
-rw-r--r--docs/podman-pod-restart.1.md50
-rw-r--r--libpod/pod.go118
-rw-r--r--test/e2e/pod_restart_test.go175
7 files changed, 347 insertions, 118 deletions
diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go
index e19fea01b..664af4252 100644
--- a/cmd/podman/pod.go
+++ b/cmd/podman/pod.go
@@ -19,6 +19,7 @@ var (
Subcommands: []cli.Command{
podCreateCommand,
podPsCommand,
+ podRestartCommand,
podRmCommand,
podStartCommand,
podStopCommand,
diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go
new file mode 100644
index 000000000..cd0081c8c
--- /dev/null
+++ b/cmd/podman/pod_restart.go
@@ -0,0 +1,98 @@
+package main
+
+import (
+ "fmt"
+
+ "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 (
+ podRestartFlags = []cli.Flag{
+ cli.BoolFlag{
+ Name: "all, a",
+ Usage: "restart all pods",
+ },
+ LatestFlag,
+ }
+ podRestartDescription = `Restarts one or more pods. The pod ID or name can be used.`
+
+ podRestartCommand = cli.Command{
+ Name: "restart",
+ Usage: "Restart one or more pods",
+ Description: podRestartDescription,
+ Flags: podRestartFlags,
+ Action: podRestartCmd,
+ ArgsUsage: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]",
+ UseShortOptionHandling: true,
+ }
+)
+
+func podRestartCmd(c *cli.Context) error {
+ if err := checkMutuallyExclusiveFlags(c); err != nil {
+ return err
+ }
+
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ args := c.Args()
+ var pods []*libpod.Pod
+ var lastError error
+
+ if c.Bool("all") {
+ pods, err = runtime.Pods()
+ if err != nil {
+ return errors.Wrapf(err, "unable to get running pods")
+ }
+ }
+
+ if c.Bool("latest") {
+ pod, err := runtime.GetLatestPod()
+ if err != nil {
+ return errors.Wrapf(err, "unable to get latest pod")
+ }
+ pods = append(pods, pod)
+ }
+
+ for _, i := range args {
+ pod, err := runtime.LookupPod(i)
+ if err != nil {
+ if lastError != nil {
+ logrus.Errorf("%q", lastError)
+ }
+ lastError = errors.Wrapf(err, "unable to find pod %s", i)
+ continue
+ }
+ pods = append(pods, pod)
+ }
+
+ ctx := getContext()
+ for _, pod := range pods {
+ ctr_errs, err := pod.Restart(ctx)
+ if ctr_errs != nil {
+ for ctr, err := range ctr_errs {
+ if lastError != nil {
+ logrus.Errorf("%q", lastError)
+ }
+ lastError = errors.Wrapf(err, "unable to restart container %q on pod %q", ctr, pod.ID())
+ }
+ continue
+ }
+ if err != nil {
+ if lastError != nil {
+ logrus.Errorf("%q", lastError)
+ }
+ lastError = errors.Wrapf(err, "unable to restart pod %q", pod.ID())
+ continue
+ }
+ fmt.Println(pod.ID())
+ }
+ return lastError
+}
diff --git a/commands.md b/commands.md
index f15ff1c3d..c74998319 100644
--- a/commands.md
+++ b/commands.md
@@ -32,6 +32,7 @@
| [podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods ||
| [podman-pod-create(1)](/docs/podman-pod-create.1.md) | Create a new pod ||
| [podman-pod-ps(1)](/docs/podman-pod-ps.1.md) | List the pods on the system ||
+| [podman-pod-restart](/docs/podman-pod-restart.1.md) | Restart one or more pods ||
| [podman-pod-rm(1)](/docs/podman-pod-rm.1.md) | Remove one or more pods ||
| [podman-pod-start(1)](/docs/podman-pod-start.1.md) | Start one or more pods ||
| [podman-pod-stop(1)](/docs/podman-pod-stop.1.md) | Stop one or more pods ||
diff --git a/completions/bash/podman b/completions/bash/podman
index 5d20bab3e..374a84a4c 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -2121,6 +2121,27 @@ _podman_pod_ps() {
__podman_pod_ps
}
+_podman_pod_restart() {
+ local options_with_args="
+ "
+
+ local boolean_options="
+ --all
+ -a
+ --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_rm() {
local options_with_args="
"
@@ -2195,6 +2216,7 @@ _podman_pod() {
subcommands="
create
ps
+ restart
rm
start
stop
diff --git a/docs/podman-pod-restart.1.md b/docs/podman-pod-restart.1.md
new file mode 100644
index 000000000..0990cf840
--- /dev/null
+++ b/docs/podman-pod-restart.1.md
@@ -0,0 +1,50 @@
+% podman-pod-restart "1"
+
+## NAME
+podman\-pod\-restart - Restart one or more pods
+
+## SYNOPSIS
+**podman pod restart** [*options*] *pod* ...
+
+## DESCRIPTION
+Restart containers in one or more pods. Containers will be stopped if running and then restarted.
+Stopped containers will only be started. You may use pod IDs or names as input.
+The pod ID will be printed upon successful restart.
+When restarting multiple pods, an error from restarting one pod will not effect restarting other pods.
+
+## OPTIONS
+
+**--all, -a**
+
+Restarts all pods
+
+**--latest, -l**
+
+Instead of providing the pod name or ID, restart the last created pod.
+
+## EXAMPLE
+
+podman pod restart mywebserverpod
+cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907
+
+podman pod restart 490eb 3557fb
+490eb241aaf704d4dd2629904410fe4aa31965d9310a735f8755267f4ded1de5
+3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
+
+3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
+
+podman pod restart --latest
+3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
+
+podman pod restart --all
+19456b4cd557eaf9629825113a552681a6013f8c8cad258e36ab825ef536e818
+3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
+490eb241aaf704d4dd2629904410fe4aa31965d9310a735f8755267f4ded1de5
+70c358daecf71ef9be8f62404f926080ca0133277ef7ce4f6aa2d5af6bb2d3e9
+cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907
+
+## SEE ALSO
+podman-pod(1), podman-pod-start(1), podman-restart(1)
+
+## HISTORY
+July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com>
diff --git a/libpod/pod.go b/libpod/pod.go
index 7cb96a270..6e568f2b7 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -435,124 +435,6 @@ func (p *Pod) Restart(ctx context.Context) (map[string]error, error) {
return nil, nil
}
-// Pause pauses all containers within a pod that are running.
-// Only running containers will be paused. Paused, stopped, or created
-// containers will be ignored.
-// All containers are paused independently. An error pausing one container
-// will not prevent other containers being paused.
-// An error and a map[string]error are returned
-// If the error is not nil and the map is nil, an error was encountered before
-// any containers were paused
-// If map is not nil, an error was encountered when pausing one or more
-// containers. The container ID is mapped to the error encountered. The error is
-// set to ErrCtrExists
-// If both error and the map are nil, all containers were paused without error
-func (p *Pod) Pause() (map[string]error, error) {
- p.lock.Lock()
- defer p.lock.Unlock()
-
- if !p.valid {
- return nil, ErrPodRemoved
- }
-
- allCtrs, err := p.runtime.state.PodContainers(p)
- if err != nil {
- return nil, err
- }
-
- ctrErrors := make(map[string]error)
-
- // Pause to all containers
- for _, ctr := range allCtrs {
- ctr.lock.Lock()
-
- if err := ctr.syncContainer(); err != nil {
- ctr.lock.Unlock()
- ctrErrors[ctr.ID()] = err
- continue
- }
-
- // Ignore containers that are not running
- if ctr.state.State != ContainerStateRunning {
- ctr.lock.Unlock()
- continue
- }
-
- if err := ctr.pause(); err != nil {
- ctr.lock.Unlock()
- ctrErrors[ctr.ID()] = err
- continue
- }
-
- ctr.lock.Unlock()
- }
-
- if len(ctrErrors) > 0 {
- return ctrErrors, errors.Wrapf(ErrCtrExists, "error pausing some containers")
- }
-
- return nil, nil
-}
-
-// Unpause unpauses all containers within a pod that are running.
-// Only paused containers will be unpaused. Running, stopped, or created
-// containers will be ignored.
-// All containers are unpaused independently. An error unpausing one container
-// will not prevent other containers being unpaused.
-// An error and a map[string]error are returned
-// If the error is not nil and the map is nil, an error was encountered before
-// any containers were unpaused
-// If map is not nil, an error was encountered when unpausing one or more
-// containers. The container ID is mapped to the error encountered. The error is
-// set to ErrCtrExists
-// If both error and the map are nil, all containers were unpaused without error
-func (p *Pod) Unpause() (map[string]error, error) {
- p.lock.Lock()
- defer p.lock.Unlock()
-
- if !p.valid {
- return nil, ErrPodRemoved
- }
-
- allCtrs, err := p.runtime.state.PodContainers(p)
- if err != nil {
- return nil, err
- }
-
- ctrErrors := make(map[string]error)
-
- // Pause to all containers
- for _, ctr := range allCtrs {
- ctr.lock.Lock()
-
- if err := ctr.syncContainer(); err != nil {
- ctr.lock.Unlock()
- ctrErrors[ctr.ID()] = err
- continue
- }
-
- // Ignore containers that are not paused
- if ctr.state.State != ContainerStatePaused {
- ctr.lock.Unlock()
- continue
- }
-
- if err := ctr.unpause(); err != nil {
- ctr.lock.Unlock()
- ctrErrors[ctr.ID()] = err
- continue
- }
-
- ctr.lock.Unlock()
- }
-
- if len(ctrErrors) > 0 {
- return ctrErrors, errors.Wrapf(ErrCtrExists, "error unpausing some containers")
- }
-
- return nil, nil
-}
-
// Kill sends a signal to all running containers within a pod
// Signals will only be sent to running containers. Containers that are not
// running will be ignored. All signals are sent independently, and sending will
diff --git a/test/e2e/pod_restart_test.go b/test/e2e/pod_restart_test.go
new file mode 100644
index 000000000..8de3a05b1
--- /dev/null
+++ b/test/e2e/pod_restart_test.go
@@ -0,0 +1,175 @@
+package integration
+
+import (
+ "os"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman pod restart", 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 restart bogus pod", func() {
+ session := podmanTest.Podman([]string{"pod", "restart", "123"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ })
+
+ It("podman pod restart single empty pod", func() {
+ session := podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "restart", cid})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ })
+
+ It("podman pod restart single pod by name", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.RunTopContainerInPod("test1", "foobar99")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1"})
+ startTime.WaitWithDefaultTimeout()
+
+ session = podmanTest.Podman([]string{"pod", "restart", "foobar99"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ restartTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1"})
+ restartTime.WaitWithDefaultTimeout()
+ Expect(restartTime.OutputToString()).To(Not(Equal(startTime.OutputToString())))
+ })
+
+ It("podman pod restart multiple pods", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
+ session.WaitWithDefaultTimeout()
+
+ session = podmanTest.RunTopContainerInPod("test1", "foobar99")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
+ session2.WaitWithDefaultTimeout()
+
+ session = podmanTest.RunTopContainerInPod("test2", "foobar100")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.RunTopContainerInPod("test3", "foobar100")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.RunTopContainerInPod("test4", "foobar100")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2", "test3", "test4"})
+ startTime.WaitWithDefaultTimeout()
+
+ session = podmanTest.Podman([]string{"pod", "restart", "foobar99", "foobar100"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ restartTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2", "test3", "test4"})
+ restartTime.WaitWithDefaultTimeout()
+ Expect(restartTime.OutputToStringArray()[0]).To(Not(Equal(startTime.OutputToStringArray()[0])))
+ Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1])))
+ Expect(restartTime.OutputToStringArray()[2]).To(Not(Equal(startTime.OutputToStringArray()[2])))
+ Expect(restartTime.OutputToStringArray()[3]).To(Not(Equal(startTime.OutputToStringArray()[3])))
+ })
+
+ It("podman pod restart all pods", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
+ session.WaitWithDefaultTimeout()
+
+ session = podmanTest.RunTopContainerInPod("test1", "foobar99")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
+ session2.WaitWithDefaultTimeout()
+
+ session = podmanTest.RunTopContainerInPod("test2", "foobar100")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"})
+ startTime.WaitWithDefaultTimeout()
+
+ session = podmanTest.Podman([]string{"pod", "restart", "-a"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ restartTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"})
+ restartTime.WaitWithDefaultTimeout()
+ Expect(restartTime.OutputToStringArray()[0]).To(Not(Equal(startTime.OutputToStringArray()[0])))
+ Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1])))
+ })
+
+ It("podman pod restart latest pod", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
+ session.WaitWithDefaultTimeout()
+
+ session = podmanTest.RunTopContainerInPod("test1", "foobar99")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
+ session2.WaitWithDefaultTimeout()
+
+ session = podmanTest.RunTopContainerInPod("test2", "foobar100")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"})
+ startTime.WaitWithDefaultTimeout()
+
+ session = podmanTest.Podman([]string{"pod", "restart", "-l"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ restartTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"})
+ restartTime.WaitWithDefaultTimeout()
+ Expect(restartTime.OutputToStringArray()[0]).To(Equal(startTime.OutputToStringArray()[0]))
+ Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1])))
+ })
+
+ It("podman pod restart multiple pods with bogus", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
+ session.WaitWithDefaultTimeout()
+ cid1 := session.OutputToString()
+
+ session = podmanTest.RunTopContainerInPod("", "foobar99")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"pod", "restart", cid1, "doesnotexist"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ })
+})