Merge pull request #1738 from baude/pararestart

Make restart parallel and add --all
This commit is contained in:
OpenShift Merge Robot
2018-11-01 12:19:14 -07:00
committed by GitHub
5 changed files with 147 additions and 41 deletions

View File

@ -1,18 +1,26 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"os"
"github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
var ( var (
restartFlags = []cli.Flag{ 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{ cli.UintFlag{
Name: "timeout, time, t", Name: "timeout, time, t",
Usage: "Seconds to wait for stop before killing the container", Usage: "Seconds to wait for stop before killing the container",
@ -35,11 +43,19 @@ var (
) )
func restartCmd(c *cli.Context) error { func restartCmd(c *cli.Context) error {
var (
restartFuncs []shared.ParallelWorkerInput
containers []*libpod.Container
lastError error
restartContainers []*libpod.Container
)
args := c.Args() 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") return errors.Wrapf(libpod.ErrInvalidArg, "you must provide at least one container name or ID")
} }
if err := validateFlags(c, restartFlags); err != nil { if err := validateFlags(c, restartFlags); err != nil {
return err return err
} }
@ -50,8 +66,6 @@ func restartCmd(c *cli.Context) error {
} }
defer runtime.Shutdown(false) defer runtime.Shutdown(false)
var lastError error
timeout := c.Uint("timeout") timeout := c.Uint("timeout")
useTimeout := c.IsSet("timeout") useTimeout := c.IsSet("timeout")
@ -59,39 +73,66 @@ func restartCmd(c *cli.Context) error {
if c.Bool("latest") { if c.Bool("latest") {
lastCtr, err := runtime.GetLatestContainer() lastCtr, err := runtime.GetLatestContainer()
if err != nil { if err != nil {
lastError = errors.Wrapf(err, "unable to get latest container") return errors.Wrapf(err, "unable to get latest container")
}
restartContainers = append(restartContainers, lastCtr)
} else if runOnly {
containers, err = getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running")
if err != nil {
return err
}
restartContainers = append(restartContainers, containers...)
} else if all {
containers, err = runtime.GetAllContainers()
if err != nil {
return err
}
restartContainers = append(restartContainers, containers...)
} else { } else {
ctrTimeout := lastCtr.StopTimeout()
if useTimeout {
ctrTimeout = timeout
}
lastError = lastCtr.RestartWithTimeout(context.TODO(), ctrTimeout)
}
}
for _, id := range args { for _, id := range args {
ctr, err := runtime.LookupContainer(id) ctr, err := runtime.LookupContainer(id)
if err != nil { if err != nil {
if lastError != nil { return err
fmt.Fprintln(os.Stderr, lastError) }
restartContainers = append(restartContainers, ctr)
} }
lastError = errors.Wrapf(err, "unable to find container %s", id)
continue
} }
// 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() ctrTimeout := ctr.StopTimeout()
if useTimeout { if useTimeout {
ctrTimeout = timeout ctrTimeout = timeout
} }
if err := ctr.RestartWithTimeout(context.TODO(), ctrTimeout); err != nil { f := func() error {
if lastError != nil { return con.RestartWithTimeout(getContext(), ctrTimeout)
fmt.Fprintln(os.Stderr, lastError)
}
lastError = errors.Wrapf(err, "error restarting container %s", ctr.ID())
}
} }
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 return lastError
} }

View File

@ -72,20 +72,22 @@ func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) map
func Parallelize(job string) int { func Parallelize(job string) int {
numCpus := runtime.NumCPU() numCpus := runtime.NumCPU()
switch job { switch job {
case "stop": case "ps":
if numCpus <= 2 { return 8
return 4 case "restart":
} else { return numCpus * 2
return numCpus * 3
}
case "rm": case "rm":
if numCpus <= 3 { if numCpus <= 3 {
return numCpus * 3 return numCpus * 3
} else { } else {
return numCpus * 4 return numCpus * 4
} }
case "ps": case "stop":
return 8 if numCpus <= 2 {
return 4
} else {
return numCpus * 3
}
} }
return 3 return 3
} }

View File

@ -1770,8 +1770,13 @@ _podman_restart() {
--timeout -t --timeout -t
" "
local boolean_options=" local boolean_options="
--all
-a
--latest --latest
-l" -l
--running
--timeout
-t"
case "$cur" in case "$cur" in
-*) -*)
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))

View File

@ -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. containers will not be stopped and will only be started.
## OPTIONS ## OPTIONS
**--timeout** **--all, -a**
Restart all containers regardless of their current state.
Timeout to wait before forcibly stopping the container
**--latest, -l** **--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman 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. 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 ## ## EXAMPLES ##
Restart the latest container
``` ```
$ podman restart -l $ podman restart -l
ec588fc80b05e19d3006bf2e8aa325f0a2e2ff1f609b7afb39176ca8e3e13467 ec588fc80b05e19d3006bf2e8aa325f0a2e2ff1f609b7afb39176ca8e3e13467
``` ```
Restart a specific container by partial container ID
``` ```
$ podman restart ff6cf1 $ podman restart ff6cf1
ff6cf1e5e77e6dba1efc7f3fcdb20e8b89ad8947bc0518be1fcb2c78681f226f ff6cf1e5e77e6dba1efc7f3fcdb20e8b89ad8947bc0518be1fcb2c78681f226f
``` ```
Restart two containers by name with a timeout of 4 seconds
``` ```
$ podman restart --timeout 4 test1 test2 $ podman restart --timeout 4 test1 test2
c3bb026838c30e5097f079fa365c9a4769d52e1017588278fa00d5c68ebc1502 c3bb026838c30e5097f079fa365c9a4769d52e1017588278fa00d5c68ebc1502
17e13a63081a995136f907024bcfe50ff532917988a152da229db9d894c5a9ec 17e13a63081a995136f907024bcfe50ff532917988a152da229db9d894c5a9ec
``` ```
Restart all running containers
```
$ podman restart --running
```
Restart all containers
```
$ podman restart --all
```
## SEE ALSO ## SEE ALSO
podman(1), podman-run(1), podman-start(1), podman-create(1) podman(1), podman-run(1), podman-start(1), podman-create(1)

View File

@ -136,4 +136,44 @@ var _ = Describe("Podman restart", func() {
Expect(timeSince < 10*time.Second).To(BeTrue()) Expect(timeSince < 10*time.Second).To(BeTrue())
Expect(timeSince > 2*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])))
})
}) })