aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-10-29 12:06:48 -0500
committerbaude <bbaude@redhat.com>2018-11-01 13:14:12 -0500
commit2011782d9d52958546e481f84892d00a548b9e12 (patch)
tree208158661ad4089007f9124d0eeecefcba1b7d42
parent9c1985fc4ee0a30a5a852dfbeae742e64978ed25 (diff)
downloadpodman-2011782d9d52958546e481f84892d00a548b9e12.tar.gz
podman-2011782d9d52958546e481f84892d00a548b9e12.tar.bz2
podman-2011782d9d52958546e481f84892d00a548b9e12.zip
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 <bbaude@redhat.com>
-rw-r--r--cmd/podman/restart.go95
-rw-r--r--cmd/podman/shared/parallel.go18
-rw-r--r--completions/bash/podman7
-rw-r--r--docs/podman-restart.1.md26
-rw-r--r--test/e2e/restart_test.go40
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])))
+ })
})