From b469bf5c05ce05e7b77852fa686f1e26dd59ec3e Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 22 Mar 2022 11:04:46 +0100 Subject: container: allow clone to an existing pod Closes: https://github.com/containers/podman/issues/3979 Signed-off-by: Giuseppe Scrivano --- cmd/podman/common/create.go | 16 +++++----- docs/source/markdown/podman-container-clone.1.md | 6 ++++ pkg/domain/infra/abi/containers.go | 29 +++++++++++++++++++ test/e2e/container_clone_test.go | 37 ++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 8d9a255ec..afaa1942e 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -394,14 +394,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, ) _ = cmd.RegisterFlagCompletionFunc(platformFlagName, completion.AutocompleteNone) - podFlagName := "pod" - createFlags.StringVar( - &cf.Pod, - podFlagName, "", - "Run container in an existing pod", - ) - _ = cmd.RegisterFlagCompletionFunc(podFlagName, AutocompletePods) - podIDFileFlagName := "pod-id-file" createFlags.StringVar( &cf.PodIDFile, @@ -837,6 +829,14 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, ) _ = cmd.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone) + podFlagName := "pod" + createFlags.StringVar( + &cf.Pod, + podFlagName, "", + "Run container in an existing pod", + ) + _ = cmd.RegisterFlagCompletionFunc(podFlagName, AutocompletePods) + cpuPeriodFlagName := "cpu-period" createFlags.Uint64Var( &cf.CPUPeriod, diff --git a/docs/source/markdown/podman-container-clone.1.md b/docs/source/markdown/podman-container-clone.1.md index 870bf077c..eaf330373 100644 --- a/docs/source/markdown/podman-container-clone.1.md +++ b/docs/source/markdown/podman-container-clone.1.md @@ -141,6 +141,12 @@ If no memory limits are specified, the original container's will be used. Set a custom name for the cloned container. The default if not specified is of the syntax: **-clone** +#### **--pod**=*name* + +Clone the container in an existing pod. It is helpful to move a container to an +existing pod. The container will join the pod shared namespaces, losing its configuration +that conflicts with the shared namespaces. + #### **--run** When set to true, this flag runs the newly created container after the diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 1986228a6..f45bdeba5 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -1496,6 +1496,35 @@ func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts enti return nil, err } + if ctrCloneOpts.CreateOpts.Pod != "" { + pod, err := ic.Libpod.LookupPod(ctrCloneOpts.CreateOpts.Pod) + if err != nil { + return nil, err + } + + allNamespaces := []struct { + isShared bool + value *specgen.Namespace + }{ + {pod.SharesPID(), &spec.PidNS}, + {pod.SharesNet(), &spec.NetNS}, + {pod.SharesCgroup(), &spec.CgroupNS}, + {pod.SharesIPC(), &spec.IpcNS}, + {pod.SharesUTS(), &spec.UtsNS}, + } + + printWarning := false + for _, n := range allNamespaces { + if n.isShared && !n.value.IsDefault() { + *n.value = specgen.Namespace{NSMode: specgen.Default} + printWarning = true + } + } + if printWarning { + logrus.Warning("At least one namespace was reset to the default configuration") + } + } + err = specgenutil.FillOutSpecGen(spec, &ctrCloneOpts.CreateOpts, []string{}) if err != nil { return nil, err diff --git a/test/e2e/container_clone_test.go b/test/e2e/container_clone_test.go index bebc6872b..a327bb8ed 100644 --- a/test/e2e/container_clone_test.go +++ b/test/e2e/container_clone_test.go @@ -184,4 +184,41 @@ var _ = Describe("Podman container clone", func() { Expect(ctrInspect.InspectContainerToJSON()[0].HostConfig.NetworkMode).Should(Equal(runInspect.InspectContainerToJSON()[0].HostConfig.NetworkMode)) }) + It("podman container clone to a pod", func() { + createPod := podmanTest.Podman([]string{"pod", "create", "--share", "uts", "--name", "foo-pod"}) + createPod.WaitWithDefaultTimeout() + Expect(createPod).To(Exit(0)) + + ctr := podmanTest.RunTopContainer("ctr") + ctr.WaitWithDefaultTimeout() + Expect(ctr).Should(Exit(0)) + + clone := podmanTest.Podman([]string{"container", "clone", "--name", "cloned", "--pod", "foo-pod", "ctr"}) + clone.WaitWithDefaultTimeout() + Expect(clone).To(Exit(0)) + + ctrInspect := podmanTest.Podman([]string{"inspect", "cloned"}) + ctrInspect.WaitWithDefaultTimeout() + Expect(ctrInspect).Should(Exit(0)) + + Expect(ctrInspect.InspectContainerToJSON()[0].Pod).Should(Equal(createPod.OutputToString())) + + Expect(ctrInspect.InspectContainerToJSON()[0].HostConfig.NetworkMode).Should(Not(ContainSubstring("container:"))) + + createPod = podmanTest.Podman([]string{"pod", "create", "--share", "uts,net", "--name", "bar-pod"}) + createPod.WaitWithDefaultTimeout() + Expect(createPod).To(Exit(0)) + + clone = podmanTest.Podman([]string{"container", "clone", "--name", "cloned2", "--pod", "bar-pod", "ctr"}) + clone.WaitWithDefaultTimeout() + Expect(clone).To(Exit(0)) + + ctrInspect = podmanTest.Podman([]string{"inspect", "cloned2"}) + ctrInspect.WaitWithDefaultTimeout() + Expect(ctrInspect).Should(Exit(0)) + + Expect(ctrInspect.InspectContainerToJSON()[0].Pod).Should(Equal(createPod.OutputToString())) + + Expect(ctrInspect.InspectContainerToJSON()[0].HostConfig.NetworkMode).Should(ContainSubstring("container:")) + }) }) -- cgit v1.2.3-54-g00ecf