rm -f now removes a paused container

We now can remove a paused container by sending it a kill signal while it
is paused.  We then unpause the container and it is immediately killed.

Also, reworked how the parallelWorker results are handled to provide a
more consistent approach to how each subcommand implements it. It also
fixes a bug where if one container errors, the error message is duplicated
when printed out.

Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
baude
2018-11-07 13:20:43 -06:00
parent fa8cc1a942
commit 2dd9cae37c
11 changed files with 97 additions and 107 deletions

View File

@ -43,7 +43,6 @@ 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 ( var (
lastError error
killFuncs []shared.ParallelWorkerInput killFuncs []shared.ParallelWorkerInput
killSignal uint = uint(syscall.SIGTERM) killSignal uint = uint(syscall.SIGTERM)
) )
@ -75,8 +74,12 @@ func killCmd(c *cli.Context) error {
containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running")
if err != nil { if err != nil {
return err if len(containers) == 0 {
return err
}
fmt.Println(err.Error())
} }
for _, ctr := range containers { for _, ctr := range containers {
con := ctr con := ctr
f := func() error { f := func() error {
@ -95,18 +98,6 @@ func killCmd(c *cli.Context) error {
} }
logrus.Debugf("Setting maximum workers to %d", maxWorkers) logrus.Debugf("Setting maximum workers to %d", maxWorkers)
killErrors := shared.ParallelExecuteWorkerPool(maxWorkers, killFuncs) killErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, killFuncs)
return printParallelOutput(killErrors, errCount)
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

@ -1,7 +1,6 @@
package main package main
import ( import (
"fmt"
"os" "os"
"github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/libpodruntime"
@ -37,7 +36,6 @@ var (
func pauseCmd(c *cli.Context) error { func pauseCmd(c *cli.Context) error {
var ( var (
lastError error
pauseContainers []*libpod.Container pauseContainers []*libpod.Container
pauseFuncs []shared.ParallelWorkerInput pauseFuncs []shared.ParallelWorkerInput
) )
@ -90,17 +88,6 @@ func pauseCmd(c *cli.Context) error {
} }
logrus.Debugf("Setting maximum workers to %d", maxWorkers) logrus.Debugf("Setting maximum workers to %d", maxWorkers)
pauseErrors := shared.ParallelExecuteWorkerPool(maxWorkers, pauseFuncs) pauseErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, pauseFuncs)
return printParallelOutput(pauseErrors, errCount)
for cid, result := range pauseErrors {
if result != nil {
if len(pauseErrors) > 1 {
fmt.Println(result.Error())
}
lastError = result
continue
}
fmt.Println(cid)
}
return lastError
} }

View File

@ -1,8 +1,6 @@
package main package main
import ( import (
"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/cmd/podman/shared"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
@ -46,7 +44,6 @@ func restartCmd(c *cli.Context) error {
var ( var (
restartFuncs []shared.ParallelWorkerInput restartFuncs []shared.ParallelWorkerInput
containers []*libpod.Container containers []*libpod.Container
lastError error
restartContainers []*libpod.Container restartContainers []*libpod.Container
) )
@ -124,15 +121,6 @@ func restartCmd(c *cli.Context) error {
logrus.Debugf("Setting maximum workers to %d", maxWorkers) logrus.Debugf("Setting maximum workers to %d", maxWorkers)
restartErrors := shared.ParallelExecuteWorkerPool(maxWorkers, restartFuncs) restartErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, restartFuncs)
return printParallelOutput(restartErrors, errCount)
for cid, result := range restartErrors {
if result != nil {
fmt.Println(result.Error())
lastError = result
continue
}
fmt.Println(cid)
}
return lastError
} }

View File

@ -4,7 +4,6 @@ import (
"fmt" "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/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -46,9 +45,7 @@ Running containers will not be removed without the -f option.
// saveCmd saves the image to either docker-archive or oci // saveCmd saves the image to either docker-archive or oci
func rmCmd(c *cli.Context) error { func rmCmd(c *cli.Context) error {
var ( var (
delContainers []*libpod.Container deleteFuncs []shared.ParallelWorkerInput
lastError error
deleteFuncs []shared.ParallelWorkerInput
) )
ctx := getContext() ctx := getContext()
@ -65,7 +62,13 @@ func rmCmd(c *cli.Context) error {
return err return err
} }
delContainers, lastError = getAllOrLatestContainers(c, runtime, -1, "all") delContainers, err := getAllOrLatestContainers(c, runtime, -1, "all")
if err != nil {
if len(delContainers) == 0 {
return err
}
fmt.Println(err.Error())
}
for _, container := range delContainers { for _, container := range delContainers {
con := container con := container
@ -84,14 +87,7 @@ func rmCmd(c *cli.Context) error {
} }
logrus.Debugf("Setting maximum workers to %d", maxWorkers) logrus.Debugf("Setting maximum workers to %d", maxWorkers)
deleteErrors := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs) // Run the parallel funcs
for cid, result := range deleteErrors { deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs)
if result != nil { return printParallelOutput(deleteErrors, errCount)
fmt.Println(result.Error())
lastError = result
continue
}
fmt.Println(cid)
}
return lastError
} }

View File

@ -30,9 +30,10 @@ func ParallelWorker(wg *sync.WaitGroup, jobs <-chan ParallelWorkerInput, results
// ParallelExecuteWorkerPool takes container jobs and performs them in parallel. The worker // ParallelExecuteWorkerPool takes container jobs and performs them in parallel. The worker
// int determines how many workers/threads should be premade. // int determines how many workers/threads should be premade.
func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) map[string]error { func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) (map[string]error, int) {
var ( var (
wg sync.WaitGroup wg sync.WaitGroup
errorCount int
) )
resultChan := make(chan containerError, len(functions)) resultChan := make(chan containerError, len(functions))
@ -62,9 +63,12 @@ func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) map
close(resultChan) close(resultChan)
for ctrError := range resultChan { for ctrError := range resultChan {
results[ctrError.ContainerID] = ctrError.Err results[ctrError.ContainerID] = ctrError.Err
if ctrError.Err != nil {
errorCount += 1
}
} }
return results return results, errorCount
} }
// Parallelize provides the maximum number of parallel workers (int) as calculated by a basic // Parallelize provides the maximum number of parallel workers (int) as calculated by a basic

View File

@ -59,7 +59,13 @@ func stopCmd(c *cli.Context) error {
} }
defer runtime.Shutdown(false) defer runtime.Shutdown(false)
containers, lastError := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running")
if err != nil {
if len(containers) == 0 {
return err
}
fmt.Println(err.Error())
}
var stopFuncs []shared.ParallelWorkerInput var stopFuncs []shared.ParallelWorkerInput
for _, ctr := range containers { for _, ctr := range containers {
@ -85,17 +91,6 @@ func stopCmd(c *cli.Context) error {
} }
logrus.Debugf("Setting maximum workers to %d", maxWorkers) logrus.Debugf("Setting maximum workers to %d", maxWorkers)
stopErrors := shared.ParallelExecuteWorkerPool(maxWorkers, stopFuncs) stopErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, stopFuncs)
return printParallelOutput(stopErrors, errCount)
for cid, result := range stopErrors {
if result != nil && result != libpod.ErrCtrStopped {
if len(stopErrors) > 1 {
fmt.Println(result.Error())
}
lastError = result
continue
}
fmt.Println(cid)
}
return lastError
} }

View File

@ -1,7 +1,6 @@
package main package main
import ( import (
"fmt"
"os" "os"
"github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/libpodruntime"
@ -37,7 +36,6 @@ var (
func unpauseCmd(c *cli.Context) error { func unpauseCmd(c *cli.Context) error {
var ( var (
lastError error
unpauseContainers []*libpod.Container unpauseContainers []*libpod.Container
unpauseFuncs []shared.ParallelWorkerInput unpauseFuncs []shared.ParallelWorkerInput
) )
@ -90,18 +88,6 @@ func unpauseCmd(c *cli.Context) error {
} }
logrus.Debugf("Setting maximum workers to %d", maxWorkers) logrus.Debugf("Setting maximum workers to %d", maxWorkers)
unpauseErrors := shared.ParallelExecuteWorkerPool(maxWorkers, unpauseFuncs) unpauseErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, unpauseFuncs)
return printParallelOutput(unpauseErrors, errCount)
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

@ -207,3 +207,20 @@ func getPodsFromContext(c *cli.Context, r *libpod.Runtime) ([]*libpod.Pod, error
} }
return pods, lastError return pods, lastError
} }
//printParallelOutput takes the map of parallel worker results and outputs them
// to stdout
func printParallelOutput(m map[string]error, errCount int) error {
var lastError error
for cid, result := range m {
if result != nil {
if errCount > 1 {
fmt.Println(result.Error())
}
lastError = result
continue
}
fmt.Println(cid)
}
return lastError
}

View File

@ -13,7 +13,7 @@ podman\-rm - Remove one or more containers
**--force, f** **--force, f**
Force the removal of a running container Force the removal of a running and paused containers
**--all, a** **--all, a**
@ -29,16 +29,29 @@ to run containers such as CRI-O, the last started container could be from either
Remove the volumes associated with the container. (Not yet implemented) Remove the volumes associated with the container. (Not yet implemented)
## EXAMPLE ## EXAMPLE
Remove a container by its name *mywebserver*
```
podman rm mywebserver podman rm mywebserver
```
Remove several containers by name and container id.
```
podman rm mywebserver myflaskserver 860a4b23 podman rm mywebserver myflaskserver 860a4b23
```
Forcibly remove a container by container ID.
```
podman rm -f 860a4b23 podman rm -f 860a4b23
```
Remove all containers regardless of its run state.
```
podman rm -f -a podman rm -f -a
```
Forcibly remove the latest container created.
```
podman rm -f --latest podman rm -f --latest
```
## SEE ALSO ## SEE ALSO
podman(1), podman-rmi(1) podman(1), podman-rmi(1)

View File

@ -246,7 +246,19 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool)
} }
if c.state.State == ContainerStatePaused { if c.state.State == ContainerStatePaused {
return errors.Wrapf(ErrCtrStateInvalid, "container %s is paused, cannot remove until unpaused", c.ID()) if !force {
return errors.Wrapf(ErrCtrStateInvalid, "container %s is paused, cannot remove until unpaused", c.ID())
}
if err := c.runtime.ociRuntime.killContainer(c, 9); err != nil {
return err
}
if err := c.unpause(); err != nil {
return err
}
// Need to update container state to make sure we know it's stopped
if err := c.waitForExitFileAndSync(); err != nil {
return err
}
} }
// Check that the container's in a good state to be removed // Check that the container's in a good state to be removed

View File

@ -91,7 +91,7 @@ var _ = Describe("Podman pause", func() {
}) })
It("podman remove a paused container by id", func() { It("podman remove a paused container by id without force", func() {
session := podmanTest.RunTopContainer("") session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0)) Expect(session.ExitCode()).To(Equal(0))
@ -111,25 +111,26 @@ var _ = Describe("Podman pause", func() {
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState)) Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState))
result = podmanTest.Podman([]string{"rm", "--force", cid}) })
It("podman remove a paused container by id with force", func() {
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
cid := session.OutputToString()
result := podmanTest.Podman([]string{"pause", cid})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(125)) Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState)) Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState))
result = podmanTest.Podman([]string{"unpause", cid})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
result = podmanTest.Podman([]string{"rm", "--force", cid}) result = podmanTest.Podman([]string{"rm", "--force", cid})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0)) Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
}) })
It("podman stop a paused container by id", func() { It("podman stop a paused container by id", func() {