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 package main
import ( import (
"os" "fmt"
"syscall" "syscall"
"fmt"
"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/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/rootless"
"github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/signal"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -41,6 +42,12 @@ var (
// killCmd kills one or more containers with a signal // killCmd kills one or more containers with a signal
func killCmd(c *cli.Context) error { func killCmd(c *cli.Context) error {
var (
lastError error
killFuncs []shared.ParallelWorkerInput
killSignal uint = uint(syscall.SIGTERM)
)
if err := checkAllAndLatest(c); err != nil { if err := checkAllAndLatest(c); err != nil {
return err return err
} }
@ -56,7 +63,6 @@ func killCmd(c *cli.Context) error {
} }
defer runtime.Shutdown(false) defer runtime.Shutdown(false)
var killSignal uint = uint(syscall.SIGTERM)
if c.String("signal") != "" { if c.String("signal") != "" {
// Check if the signalString provided by the user is valid // Check if the signalString provided by the user is valid
// Invalid signals will return err // Invalid signals will return err
@ -67,17 +73,40 @@ func killCmd(c *cli.Context) error {
killSignal = uint(sysSignal) killSignal = uint(sysSignal)
} }
containers, lastError := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running")
if err != nil {
return err
}
for _, ctr := range containers { for _, ctr := range containers {
if err := ctr.Kill(killSignal); err != nil { con := ctr
if lastError != nil { f := func() error {
fmt.Fprintln(os.Stderr, lastError) return con.Kill(killSignal)
} }
lastError = errors.Wrapf(err, "unable to find container %v", ctr.ID())
} else { killFuncs = append(killFuncs, shared.ParallelWorkerInput{
fmt.Println(ctr.ID()) 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 return lastError
} }

View File

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

View File

@ -72,6 +72,16 @@ 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 "kill":
if numCpus <= 3 {
return numCpus * 3
}
return numCpus * 4
case "pause":
if numCpus <= 3 {
return numCpus * 3
}
return numCpus * 4
case "ps": case "ps":
return 8 return 8
case "restart": case "restart":
@ -88,6 +98,11 @@ func Parallelize(job string) int {
} else { } else {
return numCpus * 3 return numCpus * 3
} }
case "unpause":
if numCpus <= 3 {
return numCpus * 3
}
return numCpus * 4
} }
return 3 return 3
} }

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@
podman\-kill - Kills one or more containers with a signal podman\-kill - Kills one or more containers with a signal
## SYNOPSIS ## SYNOPSIS
**podman kill** [*options*] *container* ... **podman kill** [*options*] [*container* ...]
## DESCRIPTION ## DESCRIPTION
The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal. 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 podman\-pause - Pause one or more containers
## SYNOPSIS ## SYNOPSIS
**podman pause** [*options*] *container* ... **podman pause** [*options*] [*container*...]
## DESCRIPTION ## DESCRIPTION
Pauses all the processes in one or more containers. You may use container IDs or names as input. 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 ## EXAMPLE
Pause a container named 'mywebserver'
```
podman pause mywebserver podman pause mywebserver
```
Pause a container by partial container ID.
```
podman pause 860a4b23 podman pause 860a4b23
```
Pause all **running** containers.
```
podman stop -a
```
## SEE ALSO ## SEE ALSO
podman(1), podman-unpause(1) podman(1), podman-unpause(1)

View File

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

View File

@ -213,4 +213,66 @@ var _ = Describe("Podman pause", func() {
result.WaitWithDefaultTimeout() 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))
})
}) })