Add new exit codes to rm & rmi for running containers & dependencies

This enables programs and scripts wrapping the podman command to handle
'podman rm' and 'podman rmi' failures caused by paused or running
containers or due to images having other child images or dependent
containers. These errors are common enough that it makes sense to have
a more machine readable way of detecting them than parsing the standard
error output.

Signed-off-by: Ondrej Zoder <ozoder@redhat.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh
2019-06-15 06:24:42 -04:00
parent a622f8d345
commit 5370d9cb76
11 changed files with 54 additions and 15 deletions

View File

@ -8,6 +8,8 @@ import (
"os/exec" "os/exec"
"syscall" "syscall"
"github.com/containers/libpod/libpod/define"
"github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -24,3 +26,14 @@ func outputError(err error) {
fmt.Fprintln(os.Stderr, "Error:", err.Error()) fmt.Fprintln(os.Stderr, "Error:", err.Error())
} }
} }
func setExitCode(err error) int {
cause := errors.Cause(err)
switch cause {
case define.ErrNoSuchCtr:
return 1
case define.ErrCtrStateInvalid:
return 2
}
return exitCode
}

View File

@ -9,6 +9,7 @@ import (
"syscall" "syscall"
"github.com/containers/libpod/cmd/podman/varlink" "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod/define"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -43,3 +44,22 @@ func outputError(err error) {
fmt.Fprintln(os.Stderr, "Error:", ne.Error()) fmt.Fprintln(os.Stderr, "Error:", ne.Error())
} }
} }
func setExitCode(err error) int {
cause := errors.Cause(err)
switch e := cause.(type) {
// For some reason golang wont let me list them with commas so listing them all.
case *iopodman.ContainerNotFound:
return 1
case *iopodman.InvalidState:
return 2
default:
switch e {
case define.ErrNoSuchCtr:
return 1
case define.ErrCtrStateInvalid:
return 2
}
}
return exitCode
}

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -65,18 +64,16 @@ func rmCmd(c *cliconfig.RmValues) error {
ok, failures, err := runtime.RemoveContainers(getContext(), c) ok, failures, err := runtime.RemoveContainers(getContext(), c)
if err != nil { if err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr { if len(c.InputArgs) < 2 {
if len(c.InputArgs) > 1 { exitCode = setExitCode(err)
exitCode = 125
} else {
exitCode = 1
}
} }
return err return err
} }
if len(failures) > 0 { if len(failures) > 0 {
exitCode = 125 for _, err := range failures {
exitCode = setExitCode(err)
}
} }
return printCmdResults(ok, failures) return printCmdResults(ok, failures)

View File

@ -74,6 +74,7 @@ func rmiCmd(c *cliconfig.RmiValues) error {
fmt.Printf("A container associated with containers/storage, i.e. via Buildah, CRI-O, etc., may be associated with this image: %-12.12s\n", img.ID()) fmt.Printf("A container associated with containers/storage, i.e. via Buildah, CRI-O, etc., may be associated with this image: %-12.12s\n", img.ID())
} }
if !adapter.IsImageNotFound(err) { if !adapter.IsImageNotFound(err) {
exitCode = 2
failureCnt++ failureCnt++
} }
if lastError != nil { if lastError != nil {

View File

@ -69,7 +69,8 @@ podman rm -f --latest
## Exit Status ## Exit Status
**_0_** if all specified containers removed **_0_** if all specified containers removed
**_1_** if one of the specified containers did not exist, and no other failures **_1_** if one of the specified containers did not exist, and no other failures
**_125_** if command fails for a reason other then an container did not exist **_2_** if one of the specified containers is paused or running
**_125_** if the command fails for a reason other than container did not exist or is paused/running
## SEE ALSO ## SEE ALSO
podman(1), podman-image-rm(1) podman(1), podman-image-rm(1)

View File

@ -43,7 +43,8 @@ podman rmi -a -f
## Exit Status ## Exit Status
**_0_** if all specified images removed **_0_** if all specified images removed
**_1_** if one of the specified images did not exist, and no other failures **_1_** if one of the specified images did not exist, and no other failures
**_125_** if command fails for a reason other then an image did not exist **_2_** if one of the specified images has child images or is being used by a container
**_125_** if the command fails for a reason other than an image did not exist or is in use
## SEE ALSO ## SEE ALSO
podman(1) podman(1)

View File

@ -488,6 +488,12 @@ func (i *LibpodAPI) RemoveContainer(call iopodman.VarlinkCall, name string, forc
return call.ReplyContainerNotFound(name, err.Error()) return call.ReplyContainerNotFound(name, err.Error())
} }
if err := i.Runtime.RemoveContainer(ctx, ctr, force, removeVolumes); err != nil { if err := i.Runtime.RemoveContainer(ctx, ctr, force, removeVolumes); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
return call.ReplyContainerExists(1)
}
if errors.Cause(err) == define.ErrCtrStateInvalid {
return call.ReplyInvalidState(ctr.ID(), err.Error())
}
return call.ReplyErrorOccurred(err.Error()) return call.ReplyErrorOccurred(err.Error())
} }
return call.ReplyRemoveContainer(ctr.ID()) return call.ReplyRemoveContainer(ctr.ID())

View File

@ -147,7 +147,7 @@ var _ = Describe("Podman checkpoint", func() {
result = podmanTest.Podman([]string{"rm", cid}) result = podmanTest.Podman([]string{"rm", cid})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(125)) Expect(result.ExitCode()).To(Equal(2))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
result = podmanTest.Podman([]string{"rm", "-f", cid}) result = podmanTest.Podman([]string{"rm", "-f", cid})

View File

@ -126,7 +126,7 @@ var _ = Describe("Podman pause", func() {
result = podmanTest.Podman([]string{"rm", cid}) result = podmanTest.Podman([]string{"rm", cid})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(125)) Expect(result.ExitCode()).To(Equal(2))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState)) Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState))
@ -179,7 +179,7 @@ var _ = Describe("Podman pause", func() {
result = podmanTest.Podman([]string{"rm", cid}) result = podmanTest.Podman([]string{"rm", cid})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(125)) Expect(result.ExitCode()).To(Equal(2))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
result = podmanTest.Podman([]string{"rm", "-f", cid}) result = podmanTest.Podman([]string{"rm", "-f", cid})

View File

@ -49,7 +49,7 @@ var _ = Describe("Podman rm", func() {
result := podmanTest.Podman([]string{"rm", cid}) result := podmanTest.Podman([]string{"rm", cid})
result.WaitWithDefaultTimeout() result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(125)) Expect(result.ExitCode()).To(Equal(2))
}) })
It("podman rm created container", func() { It("podman rm created container", func() {

View File

@ -145,7 +145,7 @@ var _ = Describe("Podman rmi", func() {
session = podmanTest.PodmanNoCache([]string{"rmi", "-f", untaggedImg}) session = podmanTest.PodmanNoCache([]string{"rmi", "-f", untaggedImg})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0))) Expect(session.ExitCode()).To(Equal(2))
}) })
It("podman rmi image that is created from another named imaged", func() { It("podman rmi image that is created from another named imaged", func() {