diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go index 85e0c279c4..e6869efd3c 100644 --- a/cmd/podman/play/kube.go +++ b/cmd/podman/play/kube.go @@ -11,7 +11,9 @@ import ( "github.com/containers/podman/v3/cmd/podman/common" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/cmd/podman/utils" + "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/podman/v3/pkg/util" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -90,6 +92,9 @@ func init() { downFlagName := "down" flags.BoolVar(&kubeOptions.Down, downFlagName, false, "Stop pods defined in the YAML file") + replaceFlagName := "replace" + flags.BoolVar(&kubeOptions.Replace, replaceFlagName, false, "Delete and recreate pods defined in the YAML file") + if !registry.IsRemote() { certDirFlagName := "cert-dir" flags.StringVar(&kubeOptions.CertDir, certDirFlagName, "", "`Pathname` of a directory containing TLS certificates and keys") @@ -151,6 +156,11 @@ func kube(cmd *cobra.Command, args []string) error { if kubeOptions.Down { return teardown(yamlfile) } + if kubeOptions.Replace { + if err := teardown(yamlfile); err != nil && !errorhandling.Contains(err, define.ErrNoSuchPod) { + return err + } + } return playkube(yamlfile) } diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md index a4b9722b86..d4770a538b 100644 --- a/docs/source/markdown/podman-play-kube.1.md +++ b/docs/source/markdown/podman-play-kube.1.md @@ -9,6 +9,7 @@ podman-play-kube - Create containers, pods or volumes based on Kubernetes YAML ## DESCRIPTION **podman play kube** will read in a structured file of Kubernetes YAML. It will then recreate the containers, pods or volumes described in the YAML. Containers within a pod are then started and the ID of the new Pod or the name of the new Volume is output. If the yaml file is specified as "-" then `podman play kube` will read the YAML file from stdin. Using the `--down` command line option, it is also capable of tearing down the pods created by a previous run of `podman play kube`. +Using the `--replace` command line option, it will tear down the pods(if any) created by a previous run of `podman play kube` and recreate the pods with the Kubernetes YAML file. Ideally the input file would be one created by Podman (see podman-generate-kube(1)). This would guarantee a smooth import and expected results. Currently, the supported Kubernetes kinds are: @@ -146,6 +147,10 @@ Do not create /etc/hosts within the pod's containers, instead use the version fr Suppress output information when pulling images +#### **--replace** + +Tears down the pods created by a previous run of `play kube` and recreates the pods. This option is used to keep the existing pods up to date based upon the Kubernetes YAML. + #### **--seccomp-profile-root**=*path* Directory path for seccomp profiles (default: "/var/lib/kubelet/seccomp"). (This option is not available with the remote Podman client) diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index af4b0fc350..715d8acaff 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -17,6 +17,8 @@ type PlayKubeOptions struct { // Down indicates whether to bring contents of a yaml file "down" // as in stop Down bool + // Replace indicates whether to delete and recreate a yaml file + Replace bool // Do not create /etc/hosts within the pod's containers, // instead use the version from the image NoHosts bool diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index a29d0ad460..079bb53b5f 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -2798,4 +2798,58 @@ invalid kube kind exists.WaitWithDefaultTimeout() Expect(exists).To(Exit(0)) }) + + It("podman play kube replace", func() { + pod := getPod() + err := generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + ls := podmanTest.Podman([]string{"pod", "ps", "--format", "'{{.ID}}'"}) + ls.WaitWithDefaultTimeout() + Expect(ls).Should(Exit(0)) + Expect(len(ls.OutputToStringArray())).To(Equal(1)) + + containerLen := podmanTest.Podman([]string{"pod", "inspect", pod.Name, "--format", "'{{len .Containers}}'"}) + + ctr01Name := "ctr01" + ctr02Name := "ctr02" + + ctr01 := getCtr(withName(ctr01Name)) + ctr02 := getCtr(withName(ctr02Name)) + + newPod := getPod( + withCtr(ctr01), + withCtr(ctr02), + ) + err = generateKubeYaml("pod", newPod, kubeYaml) + Expect(err).To(BeNil()) + + replace := podmanTest.Podman([]string{"play", "kube", "--replace", kubeYaml}) + replace.WaitWithDefaultTimeout() + Expect(replace).Should(Exit(0)) + + newContainerLen := podmanTest.Podman([]string{"pod", "inspect", newPod.Name, "--format", "'{{len .Containers}}'"}) + newContainerLen.WaitWithDefaultTimeout() + Expect(newContainerLen).Should(Exit(0)) + Expect(newContainerLen.OutputToString()).NotTo(Equal(containerLen.OutputToString())) + }) + + It("podman play kube replace non-existing pod", func() { + pod := getPod() + err := generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + replace := podmanTest.Podman([]string{"play", "kube", "--replace", kubeYaml}) + replace.WaitWithDefaultTimeout() + Expect(replace).Should(Exit(0)) + + ls := podmanTest.Podman([]string{"pod", "ps", "--format", "'{{.ID}}'"}) + ls.WaitWithDefaultTimeout() + Expect(ls).Should(Exit(0)) + Expect(len(ls.OutputToStringArray())).To(Equal(1)) + }) })