diff options
-rw-r--r-- | cmd/podman/restart.go | 95 | ||||
-rw-r--r-- | cmd/podman/shared/parallel.go | 18 | ||||
-rw-r--r-- | completions/bash/podman | 7 | ||||
-rw-r--r-- | docs/podman-restart.1.md | 26 | ||||
-rw-r--r-- | test/e2e/restart_test.go | 40 |
5 files changed, 146 insertions, 40 deletions
diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go index 7b48ef24e..2e264db79 100644 --- a/cmd/podman/restart.go +++ b/cmd/podman/restart.go @@ -1,18 +1,26 @@ package main import ( - "context" "fmt" - "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 ( restartFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "restart all non-running containers", + }, + cli.BoolFlag{ + Name: "running", + Usage: "restart only running containers when --all is used", + }, cli.UintFlag{ Name: "timeout, time, t", Usage: "Seconds to wait for stop before killing the container", @@ -35,11 +43,19 @@ var ( ) func restartCmd(c *cli.Context) error { + var ( + restartFuncs []shared.ParallelWorkerInput + containers []*libpod.Container + lastError error + restartContainers []*libpod.Container + ) + args := c.Args() - if len(args) < 1 && !c.Bool("latest") { + runOnly := c.Bool("running") + all := c.Bool("all") + if len(args) < 1 && !c.Bool("latest") && !all { return errors.Wrapf(libpod.ErrInvalidArg, "you must provide at least one container name or ID") } - if err := validateFlags(c, restartFlags); err != nil { return err } @@ -50,8 +66,6 @@ func restartCmd(c *cli.Context) error { } defer runtime.Shutdown(false) - var lastError error - timeout := c.Uint("timeout") useTimeout := c.IsSet("timeout") @@ -59,39 +73,66 @@ func restartCmd(c *cli.Context) error { if c.Bool("latest") { lastCtr, err := runtime.GetLatestContainer() if err != nil { - lastError = errors.Wrapf(err, "unable to get latest container") - } else { - ctrTimeout := lastCtr.StopTimeout() - if useTimeout { - ctrTimeout = timeout - } - - lastError = lastCtr.RestartWithTimeout(context.TODO(), ctrTimeout) + return errors.Wrapf(err, "unable to get latest container") } - } - - for _, id := range args { - ctr, err := runtime.LookupContainer(id) + restartContainers = append(restartContainers, lastCtr) + } else if runOnly { + containers, err = getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") if err != nil { - if lastError != nil { - fmt.Fprintln(os.Stderr, lastError) + return err + } + restartContainers = append(restartContainers, containers...) + } else if all { + containers, err = runtime.GetAllContainers() + if err != nil { + return err + } + restartContainers = append(restartContainers, containers...) + } else { + for _, id := range args { + ctr, err := runtime.LookupContainer(id) + if err != nil { + return err } - lastError = errors.Wrapf(err, "unable to find container %s", id) - continue + restartContainers = append(restartContainers, ctr) } + } + // We now have a slice of all the containers to be restarted. Iterate them to + // create restart Funcs with a timeout as needed + for _, ctr := range restartContainers { + con := ctr ctrTimeout := ctr.StopTimeout() if useTimeout { ctrTimeout = timeout } - if err := ctr.RestartWithTimeout(context.TODO(), ctrTimeout); err != nil { - if lastError != nil { - fmt.Fprintln(os.Stderr, lastError) - } - lastError = errors.Wrapf(err, "error restarting container %s", ctr.ID()) + f := func() error { + return con.RestartWithTimeout(getContext(), ctrTimeout) } + + restartFuncs = append(restartFuncs, shared.ParallelWorkerInput{ + ContainerID: con.ID(), + ParallelFunc: f, + }) + } + + maxWorkers := shared.Parallelize("restart") + if c.GlobalIsSet("max-workers") { + maxWorkers = c.GlobalInt("max-workers") } + logrus.Debugf("Setting maximum workers to %d", maxWorkers) + + restartErrors := shared.ParallelExecuteWorkerPool(maxWorkers, restartFuncs) + + for cid, result := range restartErrors { + if result != nil { + fmt.Println(result.Error()) + lastError = result + continue + } + fmt.Println(cid) + } return lastError } diff --git a/cmd/podman/shared/parallel.go b/cmd/podman/shared/parallel.go index 03eba2f0b..dbf43a982 100644 --- a/cmd/podman/shared/parallel.go +++ b/cmd/podman/shared/parallel.go @@ -72,20 +72,22 @@ func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) map func Parallelize(job string) int { numCpus := runtime.NumCPU() switch job { - case "stop": - if numCpus <= 2 { - return 4 - } else { - return numCpus * 3 - } + case "ps": + return 8 + case "restart": + return numCpus * 2 case "rm": if numCpus <= 3 { return numCpus * 3 } else { return numCpus * 4 } - case "ps": - return 8 + case "stop": + if numCpus <= 2 { + return 4 + } else { + return numCpus * 3 + } } return 3 } 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")) diff --git a/docs/podman-restart.1.md b/docs/podman-restart.1.md index caacaf31d..875afa385 100644 --- a/docs/podman-restart.1.md +++ b/docs/podman-restart.1.md @@ -12,33 +12,51 @@ Containers will be stopped if they are running and then restarted. Stopped containers will not be stopped and will only be started. ## OPTIONS -**--timeout** - -Timeout to wait before forcibly stopping the container +**--all, -a** +Restart all containers regardless of their current state. **--latest, -l** - Instead of providing the container name or ID, use the last created container. If you use methods other than Podman to run containers such as CRI-O, the last started container could be from either of those methods. +**--running** +Restart all containers that are already in the *running* state. + +**--timeout** +Timeout to wait before forcibly stopping the container. + + ## EXAMPLES ## +Restart the latest container ``` $ podman restart -l ec588fc80b05e19d3006bf2e8aa325f0a2e2ff1f609b7afb39176ca8e3e13467 ``` +Restart a specific container by partial container ID ``` $ podman restart ff6cf1 ff6cf1e5e77e6dba1efc7f3fcdb20e8b89ad8947bc0518be1fcb2c78681f226f ``` +Restart two containers by name with a timeout of 4 seconds ``` $ podman restart --timeout 4 test1 test2 c3bb026838c30e5097f079fa365c9a4769d52e1017588278fa00d5c68ebc1502 17e13a63081a995136f907024bcfe50ff532917988a152da229db9d894c5a9ec ``` +Restart all running containers +``` +$ podman restart --running +``` + +Restart all containers +``` +$ podman restart --all +``` + ## SEE ALSO podman(1), podman-run(1), podman-start(1), podman-create(1) diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go index d2fc35485..eca2bbcda 100644 --- a/test/e2e/restart_test.go +++ b/test/e2e/restart_test.go @@ -136,4 +136,44 @@ var _ = Describe("Podman restart", func() { Expect(timeSince < 10*time.Second).To(BeTrue()) Expect(timeSince > 2*time.Second).To(BeTrue()) }) + + It("Podman restart --all", func() { + _, exitCode, _ := podmanTest.RunLsContainer("test1") + Expect(exitCode).To(Equal(0)) + + test2 := podmanTest.RunTopContainer("test2") + test2.WaitWithDefaultTimeout() + Expect(test2.ExitCode()).To(Equal(0)) + + startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"}) + startTime.WaitWithDefaultTimeout() + + session := podmanTest.Podman([]string{"restart", "-all"}) + 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 restart --all --running", func() { + _, exitCode, _ := podmanTest.RunLsContainer("test1") + Expect(exitCode).To(Equal(0)) + + test2 := podmanTest.RunTopContainer("test2") + test2.WaitWithDefaultTimeout() + Expect(test2.ExitCode()).To(Equal(0)) + + startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"}) + startTime.WaitWithDefaultTimeout() + + session := podmanTest.Podman([]string{"restart", "-a", "--running"}) + 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]))) + }) }) |