From 57bcd2089bfef38890822447661df6205c3a6ea0 Mon Sep 17 00:00:00 2001 From: aonoa <1991849113@qq.com> Date: Thu, 30 Jun 2022 10:12:04 +0800 Subject: [PATCH 1/2] specifying --force,podman exit with 0 Signed-off-by: wufan <1991849113@qq.com> --- cmd/podman/containers/rm.go | 3 +++ cmd/podman/images/rm.go | 5 ++++- cmd/podman/networks/rm.go | 3 +++ cmd/podman/pods/rm.go | 3 +++ cmd/podman/root.go | 3 +++ cmd/podman/volumes/rm.go | 3 +++ libpod/define/exec_codes.go | 2 ++ 7 files changed, 21 insertions(+), 1 deletion(-) diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go index bcbe86947c..525cc5a95f 100644 --- a/cmd/podman/containers/rm.go +++ b/cmd/podman/containers/rm.go @@ -140,6 +140,9 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit } if setExit { setExitCode(r.Err) + if rmOptions.Force && registry.GetExitCode() == 1 { + registry.SetExitCode(define.ExecErrorCodeIgnore) + } } errs = append(errs, r.Err) } else { diff --git a/cmd/podman/images/rm.go b/cmd/podman/images/rm.go index 13dab62d42..7627461ec7 100644 --- a/cmd/podman/images/rm.go +++ b/cmd/podman/images/rm.go @@ -2,9 +2,9 @@ package images import ( "fmt" - "github.com/containers/podman/v4/cmd/podman/common" "github.com/containers/podman/v4/cmd/podman/registry" + "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/errorhandling" "github.com/pkg/errors" @@ -82,6 +82,9 @@ func rm(cmd *cobra.Command, args []string) error { } } registry.SetExitCode(report.ExitCode) + if imageOpts.Force && registry.GetExitCode() == 1 { + registry.SetExitCode(define.ExecErrorCodeIgnore) + } } return errorhandling.JoinErrors(rmErrors) diff --git a/cmd/podman/networks/rm.go b/cmd/podman/networks/rm.go index f71f59eeaf..d3cd393210 100644 --- a/cmd/podman/networks/rm.go +++ b/cmd/podman/networks/rm.go @@ -71,6 +71,9 @@ func networkRm(cmd *cobra.Command, args []string) error { fmt.Println(r.Name) } else { setExitCode(r.Err) + if networkRmOptions.Force && registry.GetExitCode() == 1 { + registry.SetExitCode(define.ExecErrorCodeIgnore) + } errs = append(errs, r.Err) } } diff --git a/cmd/podman/pods/rm.go b/cmd/podman/pods/rm.go index 16b7191c91..495a41a506 100644 --- a/cmd/podman/pods/rm.go +++ b/cmd/podman/pods/rm.go @@ -94,6 +94,9 @@ func removePods(namesOrIDs []string, rmOptions entities.PodRmOptions, printIDs b responses, err := registry.ContainerEngine().PodRm(context.Background(), namesOrIDs, rmOptions) if err != nil { setExitCode(err) + if rmOptions.Force && registry.GetExitCode() == 1 { + registry.SetExitCode(define.ExecErrorCodeIgnore) + } return err } diff --git a/cmd/podman/root.go b/cmd/podman/root.go index b3fba11585..993b1ee293 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -106,6 +106,9 @@ func Execute() { fmt.Fprintln(os.Stderr, "Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM") } } + if registry.GetExitCode() == define.ExecErrorCodeIgnore { + registry.SetExitCode(0) + } fmt.Fprintln(os.Stderr, formatError(err)) } os.Exit(registry.GetExitCode()) diff --git a/cmd/podman/volumes/rm.go b/cmd/podman/volumes/rm.go index 2012b7d3a7..a86b452308 100644 --- a/cmd/podman/volumes/rm.go +++ b/cmd/podman/volumes/rm.go @@ -73,6 +73,9 @@ func rm(cmd *cobra.Command, args []string) error { fmt.Println(r.Id) } else { setExitCode(r.Err) + if rmOptions.Force && registry.GetExitCode() == 1 { + registry.SetExitCode(define.ExecErrorCodeIgnore) + } errs = append(errs, r.Err) } } diff --git a/libpod/define/exec_codes.go b/libpod/define/exec_codes.go index f94616b332..cfb5f1f8dc 100644 --- a/libpod/define/exec_codes.go +++ b/libpod/define/exec_codes.go @@ -17,6 +17,8 @@ const ( ExecErrorCodeCannotInvoke = 126 // ExecErrorCodeNotFound is the error code to return when a command cannot be found ExecErrorCodeNotFound = 127 + // ExecErrorCodeIgnore is the error code to can be simply ignored + ExecErrorCodeIgnore = 128 ) // TranslateExecErrorToExitCode takes an error and checks whether it From f8d21451476fbb1dcd2fb3a2d69a16e6dca4183a Mon Sep 17 00:00:00 2001 From: aonoa <1991849113@qq.com> Date: Wed, 6 Jul 2022 23:14:36 +0800 Subject: [PATCH 2/2] consider more and add test Signed-off-by: aonoa <1991849113@qq.com> --- cmd/podman/containers/rm.go | 60 ++++++++++++++++++++++++------------ cmd/podman/images/rm.go | 1 + cmd/podman/networks/prune.go | 4 +-- cmd/podman/networks/rm.go | 55 ++++++++++++++++++++++++--------- cmd/podman/pods/rm.go | 41 +++++++++++++++++------- cmd/podman/volumes/rm.go | 54 +++++++++++++++++++++++--------- libpod/define/exec_codes.go | 2 +- test/e2e/network_test.go | 4 +++ test/e2e/pod_rm_test.go | 4 +++ test/e2e/rm_test.go | 4 +++ test/e2e/rmi_test.go | 3 ++ test/e2e/volume_rm_test.go | 4 +++ 12 files changed, 175 insertions(+), 61 deletions(-) diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go index 525cc5a95f..2110e1b57f 100644 --- a/cmd/podman/containers/rm.go +++ b/cmd/podman/containers/rm.go @@ -127,7 +127,7 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit responses, err := registry.ContainerEngine().ContainerRm(context.Background(), namesOrIDs, rmOptions) if err != nil { if setExit { - setExitCode(err) + setExitCode(rmOptions.Force, []error{err}) } return err } @@ -138,34 +138,56 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit errors.Cause(r.Err).Error() == define.ErrWillDeadlock.Error() { logrus.Errorf("Potential deadlock detected - please run 'podman system renumber' to resolve") } - if setExit { - setExitCode(r.Err) - if rmOptions.Force && registry.GetExitCode() == 1 { - registry.SetExitCode(define.ExecErrorCodeIgnore) - } - } errs = append(errs, r.Err) } else { fmt.Println(r.Id) } } + if setExit { + setExitCode(rmOptions.Force, errs) + } + return errs.PrintErrors() } -func setExitCode(err error) { - // If error is set to no such container, do not reset - if registry.GetExitCode() == 1 { - return +func setExitCode(force bool, errs []error) { + var ( + // noSuchContainerErrors indicates the requested container does not exist + noSuchContainerErrors bool + // stateInvalidErrors indicates a container is in an improper state + stateInvalidErrors bool + ) + + if len(errs) == 0 { + registry.SetExitCode(0) } - cause := errors.Cause(err) + + for _, err := range errs { + cause := errors.Cause(err) + switch { + case cause == define.ErrNoSuchCtr: + noSuchContainerErrors = true + case strings.Contains(cause.Error(), define.ErrNoSuchCtr.Error()): + noSuchContainerErrors = true + case cause == define.ErrCtrStateInvalid: + stateInvalidErrors = true + case strings.Contains(cause.Error(), define.ErrCtrStateInvalid.Error()): + stateInvalidErrors = true + } + } + switch { - case cause == define.ErrNoSuchCtr: - registry.SetExitCode(1) - case strings.Contains(cause.Error(), define.ErrNoSuchCtr.Error()): - registry.SetExitCode(1) - case cause == define.ErrCtrStateInvalid: - registry.SetExitCode(2) - case strings.Contains(cause.Error(), define.ErrCtrStateInvalid.Error()): + case stateInvalidErrors: registry.SetExitCode(2) + case noSuchContainerErrors: + // One of the specified container did not exist, and no other + // failures. + if force { + registry.SetExitCode(define.ExecErrorCodeIgnore) + } else { + registry.SetExitCode(1) + } + default: + registry.SetExitCode(125) } } diff --git a/cmd/podman/images/rm.go b/cmd/podman/images/rm.go index 7627461ec7..0b4bb3741e 100644 --- a/cmd/podman/images/rm.go +++ b/cmd/podman/images/rm.go @@ -2,6 +2,7 @@ package images import ( "fmt" + "github.com/containers/podman/v4/cmd/podman/common" "github.com/containers/podman/v4/cmd/podman/registry" "github.com/containers/podman/v4/libpod/define" diff --git a/cmd/podman/networks/prune.go b/cmd/podman/networks/prune.go index fa621ebace..74fbc082aa 100644 --- a/cmd/podman/networks/prune.go +++ b/cmd/podman/networks/prune.go @@ -74,16 +74,16 @@ func networkPrune(cmd *cobra.Command, _ []string) error { } responses, err := registry.ContainerEngine().NetworkPrune(registry.Context(), networkPruneOptions) if err != nil { - setExitCode(err) + setExitCode(false, []error{err}) return err } for _, r := range responses { if r.Error == nil { fmt.Println(r.Name) } else { - setExitCode(r.Error) errs = append(errs, r.Error) } } + setExitCode(false, errs) return errs.PrintErrors() } diff --git a/cmd/podman/networks/rm.go b/cmd/podman/networks/rm.go index d3cd393210..1ad59f9fab 100644 --- a/cmd/podman/networks/rm.go +++ b/cmd/podman/networks/rm.go @@ -63,33 +63,60 @@ func networkRm(cmd *cobra.Command, args []string) error { } responses, err := registry.ContainerEngine().NetworkRm(registry.Context(), args, networkRmOptions) if err != nil { - setExitCode(err) + setExitCode(networkRmOptions.Force, []error{err}) return err } for _, r := range responses { if r.Err == nil { fmt.Println(r.Name) } else { - setExitCode(r.Err) - if networkRmOptions.Force && registry.GetExitCode() == 1 { - registry.SetExitCode(define.ExecErrorCodeIgnore) - } errs = append(errs, r.Err) } } + setExitCode(networkRmOptions.Force, errs) + return errs.PrintErrors() } -func setExitCode(err error) { - cause := errors.Cause(err) +func setExitCode(force bool, errs []error) { + var ( + // noSuchNetworkErrors indicates the requested network does not exist. + noSuchNetworkErrors bool + // inUseErrors indicates the requested operation failed because the network was in use + inUseErrors bool + ) + + if len(errs) == 0 { + registry.SetExitCode(0) + } + + for _, err := range errs { + cause := errors.Cause(err) + switch { + case cause == define.ErrNoSuchNetwork: + noSuchNetworkErrors = true + case strings.Contains(cause.Error(), define.ErrNoSuchNetwork.Error()): + noSuchNetworkErrors = true + case cause == define.ErrNetworkInUse: + inUseErrors = true + case strings.Contains(cause.Error(), define.ErrNetworkInUse.Error()): + inUseErrors = true + } + } + switch { - case cause == define.ErrNoSuchNetwork: - registry.SetExitCode(1) - case strings.Contains(cause.Error(), define.ErrNoSuchNetwork.Error()): - registry.SetExitCode(1) - case cause == define.ErrNetworkInUse: - registry.SetExitCode(2) - case strings.Contains(cause.Error(), define.ErrNetworkInUse.Error()): + case inUseErrors: + // network is being used. registry.SetExitCode(2) + case noSuchNetworkErrors && !inUseErrors: + // One of the specified network did not exist, and no other + // failures. + if force { + registry.SetExitCode(define.ExecErrorCodeIgnore) + } else { + registry.SetExitCode(1) + } + default: + registry.SetExitCode(125) } } diff --git a/cmd/podman/pods/rm.go b/cmd/podman/pods/rm.go index 495a41a506..549c1dd7de 100644 --- a/cmd/podman/pods/rm.go +++ b/cmd/podman/pods/rm.go @@ -93,10 +93,7 @@ func removePods(namesOrIDs []string, rmOptions entities.PodRmOptions, printIDs b responses, err := registry.ContainerEngine().PodRm(context.Background(), namesOrIDs, rmOptions) if err != nil { - setExitCode(err) - if rmOptions.Force && registry.GetExitCode() == 1 { - registry.SetExitCode(define.ExecErrorCodeIgnore) - } + setExitCode(rmOptions.Force, []error{err}) return err } @@ -107,19 +104,41 @@ func removePods(namesOrIDs []string, rmOptions entities.PodRmOptions, printIDs b fmt.Println(r.Id) } } else { - setExitCode(r.Err) errs = append(errs, r.Err) } } + setExitCode(rmOptions.Force, errs) return errs.PrintErrors() } -func setExitCode(err error) { - cause := errors.Cause(err) +func setExitCode(force bool, errs []error) { + var ( + // noSuchNetworkErrors indicates the requested pod does not exist. + noSuchPodErrors bool + ) + + if len(errs) == 0 { + registry.SetExitCode(0) + } + + for _, err := range errs { + cause := errors.Cause(err) + switch { + case cause == define.ErrNoSuchPod: + noSuchPodErrors = true + case strings.Contains(cause.Error(), define.ErrNoSuchPod.Error()): + noSuchPodErrors = true + } + } + switch { - case cause == define.ErrNoSuchPod: - registry.SetExitCode(1) - case strings.Contains(cause.Error(), define.ErrNoSuchPod.Error()): - registry.SetExitCode(1) + case noSuchPodErrors: + if force { + registry.SetExitCode(define.ExecErrorCodeIgnore) + } else { + registry.SetExitCode(1) + } + default: + registry.SetExitCode(125) } } diff --git a/cmd/podman/volumes/rm.go b/cmd/podman/volumes/rm.go index a86b452308..6b6a5ad254 100644 --- a/cmd/podman/volumes/rm.go +++ b/cmd/podman/volumes/rm.go @@ -65,33 +65,59 @@ func rm(cmd *cobra.Command, args []string) error { } responses, err := registry.ContainerEngine().VolumeRm(context.Background(), args, rmOptions) if err != nil { - setExitCode(err) + setExitCode(rmOptions.Force, []error{err}) return err } for _, r := range responses { if r.Err == nil { fmt.Println(r.Id) } else { - setExitCode(r.Err) - if rmOptions.Force && registry.GetExitCode() == 1 { - registry.SetExitCode(define.ExecErrorCodeIgnore) - } errs = append(errs, r.Err) } } + setExitCode(rmOptions.Force, errs) return errs.PrintErrors() } -func setExitCode(err error) { - cause := errors.Cause(err) +func setExitCode(force bool, errs []error) { + var ( + // noSuchVolumeErrors indicates the requested volume does not exist + noSuchVolumeErrors bool + // inUseErrors indicates that a volume is being used by at least one container + inUseErrors bool + ) + + if len(errs) == 0 { + registry.SetExitCode(0) + } + + for _, err := range errs { + cause := errors.Cause(err) + switch { + case cause == define.ErrNoSuchVolume: + noSuchVolumeErrors = true + case strings.Contains(cause.Error(), define.ErrNoSuchVolume.Error()): + noSuchVolumeErrors = true + case cause == define.ErrVolumeBeingUsed: + inUseErrors = true + case strings.Contains(cause.Error(), define.ErrVolumeBeingUsed.Error()): + inUseErrors = true + + } + } + switch { - case cause == define.ErrNoSuchVolume: - registry.SetExitCode(1) - case strings.Contains(cause.Error(), define.ErrNoSuchVolume.Error()): - registry.SetExitCode(1) - case cause == define.ErrVolumeBeingUsed: - registry.SetExitCode(2) - case strings.Contains(cause.Error(), define.ErrVolumeBeingUsed.Error()): + case inUseErrors: + // being used by a container. registry.SetExitCode(2) + case noSuchVolumeErrors && !inUseErrors: + // One of the specified volumes did not exist, and no other + if force { + registry.SetExitCode(define.ExecErrorCodeIgnore) + } else { + registry.SetExitCode(1) + } + default: + registry.SetExitCode(125) } } diff --git a/libpod/define/exec_codes.go b/libpod/define/exec_codes.go index cfb5f1f8dc..1b3d26eeaf 100644 --- a/libpod/define/exec_codes.go +++ b/libpod/define/exec_codes.go @@ -18,7 +18,7 @@ const ( // ExecErrorCodeNotFound is the error code to return when a command cannot be found ExecErrorCodeNotFound = 127 // ExecErrorCodeIgnore is the error code to can be simply ignored - ExecErrorCodeIgnore = 128 + ExecErrorCodeIgnore = -128 ) // TranslateExecErrorToExitCode takes an error and checks whether it diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 2fdd62f7e8..53b4753a1d 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -427,6 +427,10 @@ var _ = Describe("Podman network", func() { session := podmanTest.Podman([]string{"network", "rm", "bogus"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(1)) + + session = podmanTest.Podman([]string{"network", "rm", "-t", "0", "-f", "bogus"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(1)) }) It("podman network remove --force with pod", func() { diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go index a5eab7eedc..69fb552598 100644 --- a/test/e2e/pod_rm_test.go +++ b/test/e2e/pod_rm_test.go @@ -197,6 +197,10 @@ var _ = Describe("Podman pod rm", func() { session := podmanTest.Podman([]string{"pod", "rm", "bogus"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(1)) + + session = podmanTest.Podman([]string{"pod", "rm", "-t", "0", "-f", "bogus"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) }) It("podman rm bogus pod and a running pod", func() { diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go index 7dbe5fed81..09cb6bc0bd 100644 --- a/test/e2e/rm_test.go +++ b/test/e2e/rm_test.go @@ -253,6 +253,10 @@ var _ = Describe("Podman rm", func() { session := podmanTest.Podman([]string{"rm", "bogus"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(1)) + + session = podmanTest.Podman([]string{"rm", "-t", "0", "-f", "bogus"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) }) It("podman rm bogus container and a running container", func() { diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go index cc3cceda58..1135b66b19 100644 --- a/test/e2e/rmi_test.go +++ b/test/e2e/rmi_test.go @@ -39,6 +39,9 @@ var _ = Describe("Podman rmi", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(1)) + session = podmanTest.Podman([]string{"rmi", "-f", "debian:6.0.10"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) }) It("podman rmi with fq name", func() { diff --git a/test/e2e/volume_rm_test.go b/test/e2e/volume_rm_test.go index 0180b7a462..d6960a1e6b 100644 --- a/test/e2e/volume_rm_test.go +++ b/test/e2e/volume_rm_test.go @@ -74,6 +74,10 @@ var _ = Describe("Podman volume rm", func() { session := podmanTest.Podman([]string{"volume", "rm", "bogus"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(1)) + + session = podmanTest.Podman([]string{"volume", "rm", "-t", "0", "-f", "bogus"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) }) It("podman rm with --all flag", func() {