Merge pull request #1737 from baude/parakill

Make kill, pause, and unpause parallel.
This commit is contained in:
OpenShift Merge Robot
2018-11-01 13:04:10 -07:00
committed by GitHub
10 changed files with 287 additions and 50 deletions

View File

@ -1,15 +1,16 @@
package main
import (
"os"
"fmt"
"syscall"
"fmt"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/rootless"
"github.com/docker/docker/pkg/signal"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
@ -41,6 +42,12 @@ var (
// killCmd kills one or more containers with a signal
func killCmd(c *cli.Context) error {
var (
lastError error
killFuncs []shared.ParallelWorkerInput
killSignal uint = uint(syscall.SIGTERM)
)
if err := checkAllAndLatest(c); err != nil {
return err
}
@ -56,7 +63,6 @@ func killCmd(c *cli.Context) error {
}
defer runtime.Shutdown(false)
var killSignal uint = uint(syscall.SIGTERM)
if c.String("signal") != "" {
// Check if the signalString provided by the user is valid
// Invalid signals will return err
@ -67,17 +73,40 @@ func killCmd(c *cli.Context) error {
killSignal = uint(sysSignal)
}
containers, lastError := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running")
for _, ctr := range containers {
if err := ctr.Kill(killSignal); err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
}
lastError = errors.Wrapf(err, "unable to find container %v", ctr.ID())
} else {
fmt.Println(ctr.ID())
}
containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running")
if err != nil {
return err
}
for _, ctr := range containers {
con := ctr
f := func() error {
return con.Kill(killSignal)
}
killFuncs = append(killFuncs, shared.ParallelWorkerInput{
ContainerID: con.ID(),
ParallelFunc: f,
})
}
maxWorkers := shared.Parallelize("kill")
if c.GlobalIsSet("max-workers") {
maxWorkers = c.GlobalInt("max-workers")
}
logrus.Debugf("Setting maximum workers to %d", maxWorkers)
killErrors := shared.ParallelExecuteWorkerPool(maxWorkers, killFuncs)
for cid, result := range killErrors {
if result != nil {
if len(killErrors) > 1 {
fmt.Println(result.Error())
}
lastError = result
continue
}
fmt.Println(cid)
}
return lastError
}

View File

@ -5,11 +5,20 @@ import (
"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 (
pauseFlags = []cli.Flag{
cli.BoolFlag{
Name: "all, a",
Usage: "pause all running containers",
},
}
pauseDescription = `
podman pause
@ -19,6 +28,7 @@ var (
Name: "pause",
Usage: "Pauses all the processes in one or more containers",
Description: pauseDescription,
Flags: pauseFlags,
Action: pauseCmd,
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
OnUsageError: usageErrorHandler,
@ -26,6 +36,11 @@ var (
)
func pauseCmd(c *cli.Context) error {
var (
lastError error
pauseContainers []*libpod.Container
pauseFuncs []shared.ParallelWorkerInput
)
if os.Geteuid() != 0 {
return errors.New("pause is not supported for rootless containers")
}
@ -37,28 +52,55 @@ func pauseCmd(c *cli.Context) error {
defer runtime.Shutdown(false)
args := c.Args()
if len(args) < 1 {
if len(args) < 1 && !c.Bool("all") {
return errors.Errorf("you must provide at least one container name or id")
}
var lastError error
for _, arg := range args {
ctr, err := runtime.LookupContainer(arg)
if c.Bool("all") {
containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running")
if err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
return err
}
pauseContainers = append(pauseContainers, containers...)
} else {
for _, arg := range args {
ctr, err := runtime.LookupContainer(arg)
if err != nil {
return err
}
lastError = errors.Wrapf(err, "error looking up container %q", arg)
pauseContainers = append(pauseContainers, ctr)
}
}
// Now assemble the slice of pauseFuncs
for _, ctr := range pauseContainers {
con := ctr
f := func() error {
return con.Pause()
}
pauseFuncs = append(pauseFuncs, shared.ParallelWorkerInput{
ContainerID: con.ID(),
ParallelFunc: f,
})
}
maxWorkers := shared.Parallelize("pause")
if c.GlobalIsSet("max-workers") {
maxWorkers = c.GlobalInt("max-workers")
}
logrus.Debugf("Setting maximum workers to %d", maxWorkers)
pauseErrors := shared.ParallelExecuteWorkerPool(maxWorkers, pauseFuncs)
for cid, result := range pauseErrors {
if result != nil {
if len(pauseErrors) > 1 {
fmt.Println(result.Error())
}
lastError = result
continue
}
if err = ctr.Pause(); err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
}
lastError = errors.Wrapf(err, "failed to pause container %v", ctr.ID())
} else {
fmt.Println(ctr.ID())
}
fmt.Println(cid)
}
return lastError
}

View File

@ -72,6 +72,16 @@ func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) map
func Parallelize(job string) int {
numCpus := runtime.NumCPU()
switch job {
case "kill":
if numCpus <= 3 {
return numCpus * 3
}
return numCpus * 4
case "pause":
if numCpus <= 3 {
return numCpus * 3
}
return numCpus * 4
case "ps":
return 8
case "restart":
@ -88,6 +98,11 @@ func Parallelize(job string) int {
} else {
return numCpus * 3
}
case "unpause":
if numCpus <= 3 {
return numCpus * 3
}
return numCpus * 4
}
return 3
}

View File

@ -89,7 +89,9 @@ func stopCmd(c *cli.Context) error {
for cid, result := range stopErrors {
if result != nil && result != libpod.ErrCtrStopped {
fmt.Println(result.Error())
if len(stopErrors) > 1 {
fmt.Println(result.Error())
}
lastError = result
continue
}

View File

@ -5,11 +5,20 @@ import (
"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 (
unpauseFlags = []cli.Flag{
cli.BoolFlag{
Name: "all, a",
Usage: "unpause all paused containers",
},
}
unpauseDescription = `
podman unpause
@ -19,6 +28,7 @@ var (
Name: "unpause",
Usage: "Unpause the processes in one or more containers",
Description: unpauseDescription,
Flags: unpauseFlags,
Action: unpauseCmd,
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
OnUsageError: usageErrorHandler,
@ -26,6 +36,11 @@ var (
)
func unpauseCmd(c *cli.Context) error {
var (
lastError error
unpauseContainers []*libpod.Container
unpauseFuncs []shared.ParallelWorkerInput
)
if os.Geteuid() != 0 {
return errors.New("unpause is not supported for rootless containers")
}
@ -37,28 +52,56 @@ func unpauseCmd(c *cli.Context) error {
defer runtime.Shutdown(false)
args := c.Args()
if len(args) < 1 {
if len(args) < 1 && !c.Bool("all") {
return errors.Errorf("you must provide at least one container name or id")
}
var lastError error
for _, arg := range args {
ctr, err := runtime.LookupContainer(arg)
if c.Bool("all") {
cs, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStatePaused, "paused")
if err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
}
lastError = errors.Wrapf(err, "error looking up container %q", arg)
continue
return err
}
if err = ctr.Unpause(); err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
unpauseContainers = append(unpauseContainers, cs...)
} else {
for _, arg := range args {
ctr, err := runtime.LookupContainer(arg)
if err != nil {
return err
}
lastError = errors.Wrapf(err, "failed to unpause container %v", ctr.ID())
} else {
fmt.Println(ctr.ID())
unpauseContainers = append(unpauseContainers, ctr)
}
}
// Assemble the unpause funcs
for _, ctr := range unpauseContainers {
con := ctr
f := func() error {
return con.Unpause()
}
unpauseFuncs = append(unpauseFuncs, shared.ParallelWorkerInput{
ContainerID: con.ID(),
ParallelFunc: f,
})
}
maxWorkers := shared.Parallelize("unpause")
if c.GlobalIsSet("max-workers") {
maxWorkers = c.GlobalInt("max-workers")
}
logrus.Debugf("Setting maximum workers to %d", maxWorkers)
unpauseErrors := shared.ParallelExecuteWorkerPool(maxWorkers, unpauseFuncs)
for cid, result := range unpauseErrors {
if result != nil && result != libpod.ErrCtrStopped {
if len(unpauseErrors) > 1 {
fmt.Println(result.Error())
}
lastError = result
continue
}
fmt.Println(cid)
}
return lastError
}

View File

@ -1,5 +1,6 @@
: ${PROG:=$(basename ${BASH_SOURCE})}
__podman_previous_extglob_setting=$(shopt -p extglob)
shopt -s extglob
@ -1934,6 +1935,10 @@ _podman_save() {
}
_podman_pause() {
local boolean_options="
-a
--all
"
local options_with_args="
--help -h
"
@ -2035,6 +2040,10 @@ _podman_stop() {
}
_podman_unpause() {
local boolean_options="
-a
--all
"
local options_with_args="
--help -h
"

View File

@ -4,7 +4,7 @@
podman\-kill - Kills one or more containers with a signal
## SYNOPSIS
**podman kill** [*options*] *container* ...
**podman kill** [*options*] [*container* ...]
## DESCRIPTION
The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal.

View File

@ -4,16 +4,33 @@
podman\-pause - Pause one or more containers
## SYNOPSIS
**podman pause** [*options*] *container* ...
**podman pause** [*options*] [*container*...]
## DESCRIPTION
Pauses all the processes in one or more containers. You may use container IDs or names as input.
## OPTIONS
**--all, -a**
Pause all running containers.
## EXAMPLE
Pause a container named 'mywebserver'
```
podman pause mywebserver
```
Pause a container by partial container ID.
```
podman pause 860a4b23
```
Pause all **running** containers.
```
podman stop -a
```
## SEE ALSO
podman(1), podman-unpause(1)

View File

@ -4,16 +4,34 @@
podman\-unpause - Unpause one or more containers
## SYNOPSIS
**podman unpause** [*options*] *container* ...
**podman unpause** [*options*] [*container*...]
## DESCRIPTION
Unpauses the processes in one or more containers. You may use container IDs or names as input.
## OPTIONS
**--all, -a**
Unpause all paused containers.
## EXAMPLE
Unpause a container called 'mywebserver'
```
podman unpause mywebserver
```
Unpause a container by a partial container ID.
```
podman unpause 860a4b23
```
Unpause all **paused** containers.
```
podman unpause -a
```
## SEE ALSO
podman(1), podman-pause(1)

View File

@ -213,4 +213,66 @@ var _ = Describe("Podman pause", func() {
result.WaitWithDefaultTimeout()
})
It("Pause all containers (no containers exist)", func() {
result := podmanTest.Podman([]string{"pause", "--all"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
It("Unpause all containers (no paused containers exist)", func() {
result := podmanTest.Podman([]string{"unpause", "--all"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
It("Pause a bunch of running containers", func() {
podmanTest.RestoreArtifact(nginx)
for i := 0; i < 3; i++ {
name := fmt.Sprintf("test%d", i)
run := podmanTest.Podman([]string{"run", "-dt", "--name", name, nginx})
run.WaitWithDefaultTimeout()
Expect(run.ExitCode()).To(Equal(0))
}
running := podmanTest.Podman([]string{"ps", "-q"})
running.WaitWithDefaultTimeout()
Expect(running.ExitCode()).To(Equal(0))
Expect(len(running.OutputToStringArray())).To(Equal(3))
pause := podmanTest.Podman([]string{"pause", "--all"})
pause.WaitWithDefaultTimeout()
Expect(pause.ExitCode()).To(Equal(0))
running = podmanTest.Podman([]string{"ps", "-q"})
running.WaitWithDefaultTimeout()
Expect(running.ExitCode()).To(Equal(0))
Expect(len(running.OutputToStringArray())).To(Equal(0))
})
It("Unpause a bunch of running containers", func() {
podmanTest.RestoreArtifact(nginx)
for i := 0; i < 3; i++ {
name := fmt.Sprintf("test%d", i)
run := podmanTest.Podman([]string{"run", "-dt", "--name", name, nginx})
run.WaitWithDefaultTimeout()
Expect(run.ExitCode()).To(Equal(0))
}
pause := podmanTest.Podman([]string{"pause", "--all"})
pause.WaitWithDefaultTimeout()
Expect(pause.ExitCode()).To(Equal(0))
unpause := podmanTest.Podman([]string{"unpause", "--all"})
unpause.WaitWithDefaultTimeout()
Expect(unpause.ExitCode()).To(Equal(0))
running := podmanTest.Podman([]string{"ps", "-q"})
running.WaitWithDefaultTimeout()
Expect(running.ExitCode()).To(Equal(0))
Expect(len(running.OutputToStringArray())).To(Equal(3))
})
})