diff options
-rw-r--r-- | cmd/podman/pod.go | 1 | ||||
-rw-r--r-- | cmd/podman/pod_restart.go | 98 | ||||
-rw-r--r-- | commands.md | 1 | ||||
-rw-r--r-- | completions/bash/podman | 22 | ||||
-rw-r--r-- | docs/podman-pod-restart.1.md | 50 | ||||
-rw-r--r-- | libpod/pod.go | 118 | ||||
-rw-r--r-- | test/e2e/pod_restart_test.go | 175 |
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)) + }) +}) |