diff options
-rw-r--r-- | cmd/podman/kube/down.go | 39 | ||||
-rw-r--r-- | cmd/podman/kube/play.go | 69 | ||||
-rw-r--r-- | docs/source/markdown/podman-kube-down.1.md | 43 | ||||
-rw-r--r-- | docs/source/markdown/podman-kube-play.1.md | 12 | ||||
-rw-r--r-- | docs/source/markdown/podman-kube.1.md | 5 | ||||
-rw-r--r-- | test/e2e/mount_rootless_test.go | 22 | ||||
-rw-r--r-- | test/system/700-play.bats | 15 |
7 files changed, 163 insertions, 42 deletions
diff --git a/cmd/podman/kube/down.go b/cmd/podman/kube/down.go new file mode 100644 index 000000000..b8c025928 --- /dev/null +++ b/cmd/podman/kube/down.go @@ -0,0 +1,39 @@ +package pods + +import ( + "github.com/containers/podman/v4/cmd/podman/common" + "github.com/containers/podman/v4/cmd/podman/registry" + "github.com/spf13/cobra" +) + +var ( + downDescription = `Reads in a structured file of Kubernetes YAML. + + Removes pods that have been based on the Kubernetes kind described in the YAML.` + + downCmd = &cobra.Command{ + Use: "down KUBEFILE|-", + Short: "Remove pods based on Kubernetes YAML.", + Long: downDescription, + RunE: down, + Args: cobra.ExactArgs(1), + ValidArgsFunction: common.AutocompleteDefaultOneArg, + Example: `podman kube down nginx.yml + cat nginx.yml | podman kube down -`, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Command: downCmd, + Parent: kubeCmd, + }) +} + +func down(cmd *cobra.Command, args []string) error { + reader, err := readerFromArg(args[0]) + if err != nil { + return err + } + return teardown(reader) +} diff --git a/cmd/podman/kube/play.go b/cmd/podman/kube/play.go index 6e0050cbf..4811bcf4b 100644 --- a/cmd/podman/kube/play.go +++ b/cmd/podman/kube/play.go @@ -1,8 +1,10 @@ package pods import ( + "bytes" "errors" "fmt" + "io" "net" "os" "strings" @@ -37,9 +39,9 @@ var ( // https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/ defaultSeccompRoot = "/var/lib/kubelet/seccomp" playOptions = playKubeOptionsWrapper{} - playDescription = `Command reads in a structured file of Kubernetes YAML. + playDescription = `Reads in a structured file of Kubernetes YAML. - It creates pods or volumes based on the Kubernetes kind described in the YAML. Supported kinds are Pods, Deployments and PersistentVolumeClaims.` + Creates pods or volumes based on the Kubernetes kind described in the YAML. Supported kinds are Pods, Deployments and PersistentVolumeClaims.` playCmd = &cobra.Command{ Use: "play [options] KUBEFILE|-", @@ -139,6 +141,7 @@ func playFlags(cmd *cobra.Command) { downFlagName := "down" flags.BoolVar(&playOptions.Down, downFlagName, false, "Stop pods defined in the YAML file") + _ = flags.MarkHidden("down") replaceFlagName := "replace" flags.BoolVar(&playOptions.Replace, replaceFlagName, false, "Delete and recreate pods defined in the YAML file") @@ -164,7 +167,7 @@ func playFlags(cmd *cobra.Command) { _ = cmd.RegisterFlagCompletionFunc(contextDirFlagName, completion.AutocompleteDefault) // NOTE: The service-container flag is marked as hidden as it - // is purely designed for running kube-play or play-kube in systemd units. + // is purely designed for running kube-play in systemd units. // It is not something users should need to know or care about. // // Having a flag rather than an env variable is cleaner. @@ -223,10 +226,6 @@ func Play(cmd *cobra.Command, args []string) error { } playOptions.Annotations[splitN[0]] = annotation } - yamlfile := args[0] - if yamlfile == "-" { - yamlfile = "/dev/stdin" - } for _, mac := range playOptions.macs { m, err := net.ParseMAC(mac) @@ -235,36 +234,62 @@ func Play(cmd *cobra.Command, args []string) error { } playOptions.StaticMACs = append(playOptions.StaticMACs, m) } + + reader, err := readerFromArg(args[0]) + if err != nil { + return err + } + if playOptions.Down { - return teardown(yamlfile) + return teardown(reader) } + if playOptions.Replace { - if err := teardown(yamlfile); err != nil && !errorhandling.Contains(err, define.ErrNoSuchPod) { + if err := teardown(reader); err != nil && !errorhandling.Contains(err, define.ErrNoSuchPod) { + return err + } + if _, err := reader.Seek(0, 0); err != nil { return err } } - return kubeplay(yamlfile) + return kubeplay(reader) } func playKube(cmd *cobra.Command, args []string) error { return Play(cmd, args) } -func teardown(yamlfile string) error { +func readerFromArg(fileName string) (*bytes.Reader, error) { + if fileName == "-" { // Read from stdin + data, err := io.ReadAll(os.Stdin) + if err != nil { + return nil, err + } + return bytes.NewReader(data), nil + } + f, err := os.Open(fileName) + if err != nil { + return nil, err + } + defer f.Close() + + data, err := io.ReadAll(f) + if err != nil { + return nil, err + } + return bytes.NewReader(data), nil +} + +func teardown(body io.Reader) error { var ( podStopErrors utils.OutputErrors podRmErrors utils.OutputErrors ) options := new(entities.PlayKubeDownOptions) - f, err := os.Open(yamlfile) + reports, err := registry.ContainerEngine().PlayKubeDown(registry.GetContext(), body, *options) if err != nil { return err } - defer f.Close() - reports, err := registry.ContainerEngine().PlayKubeDown(registry.GetContext(), f, *options) - if err != nil { - return fmt.Errorf("%v: %w", yamlfile, err) - } // Output stopped pods fmt.Println("Pods stopped:") @@ -290,19 +315,15 @@ func teardown(yamlfile string) error { podRmErrors = append(podRmErrors, removed.Err) } } + return podRmErrors.PrintErrors() } -func kubeplay(yamlfile string) error { - f, err := os.Open(yamlfile) +func kubeplay(body io.Reader) error { + report, err := registry.ContainerEngine().PlayKube(registry.GetContext(), body, playOptions.PlayKubeOptions) if err != nil { return err } - defer f.Close() - report, err := registry.ContainerEngine().PlayKube(registry.GetContext(), f, playOptions.PlayKubeOptions) - if err != nil { - return fmt.Errorf("%s: %w", yamlfile, err) - } // Print volumes report for i, volume := range report.Volumes { if i == 0 { diff --git a/docs/source/markdown/podman-kube-down.1.md b/docs/source/markdown/podman-kube-down.1.md new file mode 100644 index 000000000..35725043b --- /dev/null +++ b/docs/source/markdown/podman-kube-down.1.md @@ -0,0 +1,43 @@ +% podman-kube-down(1) + +## NAME +podman-kube-down - Remove containers and pods based on Kubernetes YAML + +## SYNOPSIS +**podman kube down** *file.yml|-* + +## DESCRIPTION +**podman kube down** reads a specified Kubernetes YAML file, tearing down pods that were created by the `podman kube play` command via the same Kubernetes YAML file. Any volumes that were created by the previous `podman kube play` command remain intact. If the YAML file is specified as `-`, `podman kube down` reads the YAML from stdin. + +## EXAMPLES + +Example YAML file `demo.yml`: +``` +apiVersion: v1 +kind: Pod +metadata: +... +spec: + containers: + - command: + - top + - name: container + value: podman + image: foobar +... +``` + +Remove the pod and containers as described in the `demo.yml` file +``` +$ podman kube down demo.yml +52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 +``` + +Remove the pod and containers as described in the`demo.yml` file YAML sent to stdin +``` +$ cat demo.yml | podman kube play - +52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 +``` + +## SEE ALSO +**[podman(1)](podman.1.md)**, **[podman-kube(1)](podman-kube.1.md)**, **[podman-kube-play(1)](podman-kube-play.1.md)**, **[podman-generate-kube(1)](podman-generate-kube.1.md)**, **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)** diff --git a/docs/source/markdown/podman-kube-play.1.md b/docs/source/markdown/podman-kube-play.1.md index 25248ce99..b3c385fe9 100644 --- a/docs/source/markdown/podman-kube-play.1.md +++ b/docs/source/markdown/podman-kube-play.1.md @@ -1,7 +1,7 @@ % podman-kube-play(1) ## NAME -podman-kube-play - Create containers, pods or volumes based on Kubernetes YAML +podman-kube-play - Create containers, pods and volumes based on Kubernetes YAML ## SYNOPSIS **podman kube play** [*options*] *file.yml|-* @@ -30,6 +30,9 @@ Note: If the `:latest` tag is used, Podman will attempt to pull the image from a Note: The command `podman play kube` is an alias of `podman kube play`, and will perform the same function. +Note: The command `podman kube down` can be used to stop and remove pods or containers based on the same Kubernetes YAML used +by `podman kube play` to create them. + `Kubernetes PersistentVolumeClaims` A Kubernetes PersistentVolumeClaim represents a Podman named volume. Only the PersistentVolumeClaim name is required by Podman to create a volume. Kubernetes annotations can be used to make use of the available options for Podman volumes. @@ -145,11 +148,6 @@ The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. -#### **--down** - -Tears down the pods that were created by a previous run of `kube play`. The pods are stopped and then -removed. Any volumes created are left intact. - #### **--help**, **-h** Print usage statement @@ -325,7 +323,7 @@ $ podman kube play demo.yml --network net1:ip=10.89.1.5 --network net2:ip=10.89. Please take into account that networks must be created first using podman-network-create(1). ## SEE ALSO -**[podman(1)](podman.1.md)**, **[podman-kube(1)](podman-kube.1.md)**, **[podman-network-create(1)](podman-network-create.1.md)**, **[podman-generate-kube(1)](podman-generate-kube.1.md)**, **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)** +**[podman(1)](podman.1.md)**, **[podman-kube(1)](podman-kube.1.md)**, **[podman-kube-down(1)](podman-kube-down.1.md)**, **[podman-network-create(1)](podman-network-create.1.md)**, **[podman-generate-kube(1)](podman-generate-kube.1.md)**, **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)** ## HISTORY December 2018, Originally compiled by Brent Baude (bbaude at redhat dot com) diff --git a/docs/source/markdown/podman-kube.1.md b/docs/source/markdown/podman-kube.1.md index f815ffae2..7a6978a2b 100644 --- a/docs/source/markdown/podman-kube.1.md +++ b/docs/source/markdown/podman-kube.1.md @@ -14,7 +14,8 @@ file input. Containers will be automatically started. | Command | Man Page | Description | | ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- | -| play | [podman-kube-play(1)](podman-kube-play.1.md) | Create containers, pods or volumes based on Kubernetes YAML. | +| down | [podman-kube-down(1)](podman-kube-down.1.md) | Remove containers and pods based on Kubernetes YAML. | +| play | [podman-kube-play(1)](podman-kube-play.1.md) | Create containers, pods and volumes based on Kubernetes YAML. | ## SEE ALSO -**[podman(1)](podman.1.md)**, **[podman-pod(1)](podman-pod.1.md)**, **[podman-container(1)](podman-container.1.md)**, **[podman-generate(1)](podman-generate.1.md)**, **[podman-kube-play(1)](podman-kube-play.1.md)** +**[podman(1)](podman.1.md)**, **[podman-pod(1)](podman-pod.1.md)**, **[podman-container(1)](podman-container.1.md)**, **[podman-generate(1)](podman-generate.1.md)**, **[podman-kube-play(1)](podman-kube-play.1.md)**, **[podman-kube-down(1)](podman-kube-down.1.md)** diff --git a/test/e2e/mount_rootless_test.go b/test/e2e/mount_rootless_test.go index 994a5899b..b0452deda 100644 --- a/test/e2e/mount_rootless_test.go +++ b/test/e2e/mount_rootless_test.go @@ -52,9 +52,16 @@ var _ = Describe("Podman mount", func() { Expect(setup).Should(Exit(0)) cid := setup.OutputToString() - session := podmanTest.Podman([]string{"unshare", PODMAN_BINARY, "mount", cid}) + // command: podman <options> unshare podman <options> mount cid + args := []string{"unshare", podmanTest.PodmanBinary} + opts := podmanTest.PodmanMakeOptions([]string{"mount", cid}, false, false) + args = append(args, opts...) + + // container root file system location is /tmp/... because "--root /tmp/..." + session := podmanTest.Podman(args) session.WaitWithDefaultTimeout() - Expect(setup).Should(Exit(0)) + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("/tmp")) }) It("podman image mount", func() { @@ -71,8 +78,15 @@ var _ = Describe("Podman mount", func() { setup.WaitWithDefaultTimeout() Expect(setup).Should(Exit(0)) - session := podmanTest.Podman([]string{"unshare", PODMAN_BINARY, "image", "mount", ALPINE}) + // command: podman <options> unshare podman <options> image mount ALPINE + args := []string{"unshare", podmanTest.PodmanBinary} + opts := podmanTest.PodmanMakeOptions([]string{"image", "mount", ALPINE}, false, false) + args = append(args, opts...) + + // image location is /tmp/... because "--root /tmp/..." + session := podmanTest.Podman(args) session.WaitWithDefaultTimeout() - Expect(setup).Should(Exit(0)) + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("/tmp")) }) }) diff --git a/test/system/700-play.bats b/test/system/700-play.bats index 72602a9e6..e1955cfd1 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -182,8 +182,11 @@ EOF run_podman container inspect --format "{{.HostConfig.NetworkMode}}" $infraID is "$output" "none" "network mode none is set for the container" - run_podman stop -a -t 0 - run_podman pod rm -t 0 -f test_pod + run_podman kube down - < $PODMAN_TMPDIR/test.yaml + run_podman 125 inspect test_pod-test + is "$output" ".*Error: inspecting object: no such object: \"test_pod-test\"" + run_podman pod rm -a + run_podman rm -a } @test "podman play with user from image" { @@ -325,7 +328,6 @@ spec: - name: TERM value: xterm - name: container - value: podman image: quay.io/libpod/userimage name: test @@ -353,6 +355,9 @@ status: {} run_podman inspect --format "{{.HostConfig.LogConfig.Type}}" test_pod-test is "$output" "$default_driver" "play kube uses default log driver" - run_podman stop -a -t 0 - run_podman pod rm -t 0 -f test_pod + run_podman kube down $PODMAN_TMPDIR/test.yaml + run_podman 125 inspect test_pod-test + is "$output" ".*Error: inspecting object: no such object: \"test_pod-test\"" + run_podman pod rm -a + run_podman rm -a } |