diff --git a/cmd/podman/kube/down.go b/cmd/podman/kube/down.go index 6904df488b..b027454781 100644 --- a/cmd/podman/kube/down.go +++ b/cmd/podman/kube/down.go @@ -52,5 +52,5 @@ func down(cmd *cobra.Command, args []string) error { if err != nil { return err } - return teardown(reader, entities.PlayKubeDownOptions{Force: downOptions.Force}) + return teardown(reader, entities.PlayKubeDownOptions{Force: downOptions.Force}, false) } diff --git a/cmd/podman/kube/play.go b/cmd/podman/kube/play.go index e9c2c9234c..946eb29602 100644 --- a/cmd/podman/kube/play.go +++ b/cmd/podman/kube/play.go @@ -253,11 +253,11 @@ func play(cmd *cobra.Command, args []string) error { } if playOptions.Down { - return teardown(reader, entities.PlayKubeDownOptions{Force: playOptions.Force}) + return teardown(reader, entities.PlayKubeDownOptions{Force: playOptions.Force}, false) } if playOptions.Replace { - if err := teardown(reader, entities.PlayKubeDownOptions{Force: playOptions.Force}); err != nil && !errorhandling.Contains(err, define.ErrNoSuchPod) { + if err := teardown(reader, entities.PlayKubeDownOptions{Force: playOptions.Force}, false); err != nil && !errorhandling.Contains(err, define.ErrNoSuchPod) { return err } if _, err := reader.Seek(0, 0); err != nil { @@ -265,7 +265,19 @@ func play(cmd *cobra.Command, args []string) error { } } - return kubeplay(reader) + if err := kubeplay(reader); err != nil { + // teardown any containers, pods, and volumes that might have created before we hit the error + teardownReader, trErr := readerFromArg(args[0]) + if trErr != nil { + return trErr + } + if tErr := teardown(teardownReader, entities.PlayKubeDownOptions{Force: true}, true); tErr != nil && !errorhandling.Contains(tErr, define.ErrNoSuchPod) { + return fmt.Errorf("error tearing down workloads %q after kube play error %q", tErr, err) + } + return err + } + + return nil } func playKube(cmd *cobra.Command, args []string) error { @@ -307,7 +319,7 @@ func readerFromArg(fileName string) (*bytes.Reader, error) { return bytes.NewReader(data), nil } -func teardown(body io.Reader, options entities.PlayKubeDownOptions) error { +func teardown(body io.Reader, options entities.PlayKubeDownOptions, quiet bool) error { var ( podStopErrors utils.OutputErrors podRmErrors utils.OutputErrors @@ -319,9 +331,11 @@ func teardown(body io.Reader, options entities.PlayKubeDownOptions) error { } // Output stopped pods - fmt.Println("Pods stopped:") + if !quiet { + fmt.Println("Pods stopped:") + } for _, stopped := range reports.StopReport { - if len(stopped.Errs) == 0 { + if len(stopped.Errs) == 0 && !quiet { fmt.Println(stopped.Id) } else { podStopErrors = append(podStopErrors, stopped.Errs...) @@ -334,9 +348,11 @@ func teardown(body io.Reader, options entities.PlayKubeDownOptions) error { } // Output rm'd pods - fmt.Println("Pods removed:") + if !quiet { + fmt.Println("Pods removed:") + } for _, removed := range reports.RmReport { - if removed.Err == nil { + if removed.Err == nil && !quiet { fmt.Println(removed.Id) } else { podRmErrors = append(podRmErrors, removed.Err) @@ -349,9 +365,11 @@ func teardown(body io.Reader, options entities.PlayKubeDownOptions) error { } // Output rm'd volumes - fmt.Println("Volumes removed:") + if !quiet { + fmt.Println("Volumes removed:") + } for _, removed := range reports.VolumeRmReport { - if removed.Err == nil { + if removed.Err == nil && !quiet { fmt.Println(removed.Id) } else { volRmErrors = append(volRmErrors, removed.Err) diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 7aa3122a5c..f0f1fd6fc3 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -4406,4 +4406,40 @@ cgroups="disabled"`), 0644) kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) }) + + It("podman kube play invalid yaml should clean up pod that was created before failure", func() { + podTemplate := `--- +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: "2022-08-02T04:05:53Z" + labels: + app: vol-test-3-pod + name: vol-test-3 +spec: + containers: + - command: + - sleep + - "1000" + image: non-existing-image + name: vol-test-3 + securityContext: + capabilities: + drop: + - CAP_MKNOD + - CAP_NET_RAW + - CAP_AUDIT_WRITE +` + + // the image is incorrect so the kube play will fail, but it will clean up the pod that was created for it before the failure happened + kube := podmanTest.Podman([]string{"kube", "play", podTemplate}) + kube.WaitWithDefaultTimeout() + Expect(kube).To(ExitWithError()) + + ps := podmanTest.Podman([]string{"pod", "ps", "-q"}) + ps.WaitWithDefaultTimeout() + Expect(ps).Should(Exit(0)) + Expect(ps.OutputToStringArray()).To(HaveLen(0)) + }) + })