diff options
-rw-r--r-- | cmd/podman/common/create.go | 15 | ||||
-rw-r--r-- | cmd/podman/containers/create.go | 1 | ||||
-rw-r--r-- | cmd/podman/pods/create.go | 1 | ||||
-rw-r--r-- | docs/source/markdown/podman-pod-clone.1.md | 9 | ||||
-rw-r--r-- | docs/source/markdown/podman-pod-create.1.md | 8 | ||||
-rw-r--r-- | libpod/container.go | 49 | ||||
-rw-r--r-- | libpod/container_inspect.go | 24 | ||||
-rw-r--r-- | libpod/define/pod_inspect.go | 2 | ||||
-rw-r--r-- | libpod/pod_api.go | 1 | ||||
-rw-r--r-- | pkg/specgen/container_validate.go | 1 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 6 | ||||
-rw-r--r-- | pkg/specgen/generate/namespaces.go | 9 | ||||
-rw-r--r-- | pkg/specgen/generate/pod_create.go | 1 | ||||
-rw-r--r-- | test/e2e/pod_clone_test.go | 42 | ||||
-rw-r--r-- | test/e2e/pod_create_test.go | 33 |
15 files changed, 165 insertions, 37 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index f05549a8d..c1a744011 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -544,13 +544,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, ) _ = cmd.RegisterFlagCompletionFunc(userFlagName, AutocompleteUserFlag) - utsFlagName := "uts" - createFlags.String( - utsFlagName, "", - "UTS namespace to use", - ) - _ = cmd.RegisterFlagCompletionFunc(utsFlagName, AutocompleteNamespace) - mountFlagName := "mount" createFlags.StringArrayVar( &cf.Mount, @@ -684,6 +677,14 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, ) _ = cmd.RegisterFlagCompletionFunc(usernsFlagName, AutocompleteUserNamespace) + utsFlagName := "uts" + createFlags.StringVar( + &cf.UTS, + utsFlagName, "", + "UTS namespace to use", + ) + _ = cmd.RegisterFlagCompletionFunc(utsFlagName, AutocompleteNamespace) + cgroupParentFlagName := "cgroup-parent" createFlags.StringVar( &cf.CgroupParent, diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index 05a59ce7b..7d0f4d9ae 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -224,7 +224,6 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra return vals, errors.New("--cpu-quota and --cpus cannot be set together") } vals.IPC = c.Flag("ipc").Value.String() - vals.UTS = c.Flag("uts").Value.String() vals.PID = c.Flag("pid").Value.String() vals.CgroupNS = c.Flag("cgroupns").Value.String() diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go index 45ad2dfd0..aea8a7229 100644 --- a/cmd/podman/pods/create.go +++ b/cmd/podman/pods/create.go @@ -277,6 +277,7 @@ func create(cmd *cobra.Command, args []string) error { if err != nil { return err } + podSpec.Volumes = podSpec.InfraContainerSpec.Volumes podSpec.ImageVolumes = podSpec.InfraContainerSpec.ImageVolumes podSpec.OverlayVolumes = podSpec.InfraContainerSpec.OverlayVolumes diff --git a/docs/source/markdown/podman-pod-clone.1.md b/docs/source/markdown/podman-pod-clone.1.md index a18f7dbfe..d90d1efb9 100644 --- a/docs/source/markdown/podman-pod-clone.1.md +++ b/docs/source/markdown/podman-pod-clone.1.md @@ -211,6 +211,15 @@ Valid _mode_ values are: - *nomap*: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is ignored for containers created by the root user. +#### **--uts**=*mode* + +Set the UTS namespace mode for the pod. The following values are supported: + +- **host**: use the host's UTS namespace inside the pod. +- **private**: create a new namespace for the pod (default). +- **ns:[path]**: run the pod in the given existing UTS namespace. + + #### **--volume**, **-v**[=*[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]*] Create a bind mount. If ` -v /HOST-DIR:/CONTAINER-DIR` is specified, Podman diff --git a/docs/source/markdown/podman-pod-create.1.md b/docs/source/markdown/podman-pod-create.1.md index 75d2bb611..53d1e3327 100644 --- a/docs/source/markdown/podman-pod-create.1.md +++ b/docs/source/markdown/podman-pod-create.1.md @@ -381,6 +381,14 @@ Valid _mode_ values are: - *nomap*: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user. +#### **--uts**=*mode* + +Set the UTS namespace mode for the pod. The following values are supported: + +- **host**: use the host's UTS namespace inside the pod. +- **private**: create a new namespace for the pod (default). +- **ns:[path]**: run the pod in the given existing UTS namespace. + #### **--volume**, **-v**[=*[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]*] Create a bind mount. If you specify, ` -v /HOST-DIR:/CONTAINER-DIR`, Podman diff --git a/libpod/container.go b/libpod/container.go index 786d9c3d4..4e2d93860 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -1335,3 +1335,52 @@ func (c *Container) getNetworkStatus() map[string]types.StatusBlock { } return nil } + +func (c *Container) NamespaceMode(ns spec.LinuxNamespaceType, ctrSpec *spec.Spec) string { + switch ns { + case spec.UTSNamespace: + if c.config.UTSNsCtr != "" { + return fmt.Sprintf("container:%s", c.config.UTSNsCtr) + } + case spec.CgroupNamespace: + if c.config.CgroupNsCtr != "" { + return fmt.Sprintf("container:%s", c.config.CgroupNsCtr) + } + case spec.IPCNamespace: + if c.config.IPCNsCtr != "" { + return fmt.Sprintf("container:%s", c.config.IPCNsCtr) + } + case spec.PIDNamespace: + if c.config.PIDNsCtr != "" { + return fmt.Sprintf("container:%s", c.config.PIDNsCtr) + } + case spec.UserNamespace: + if c.config.UserNsCtr != "" { + return fmt.Sprintf("container:%s", c.config.UserNsCtr) + } + case spec.NetworkNamespace: + if c.config.NetNsCtr != "" { + return fmt.Sprintf("container:%s", c.config.NetNsCtr) + } + case spec.MountNamespace: + if c.config.MountNsCtr != "" { + return fmt.Sprintf("container:%s", c.config.MountNsCtr) + } + } + + if ctrSpec.Linux != nil { + // Locate the spec's given namespace. + // If there is none, it's namespace=host. + // If there is one and it has a path, it's "ns:". + // If there is no path, it's default - the empty string. + for _, availableNS := range ctrSpec.Linux.Namespaces { + if availableNS.Type == ns { + if availableNS.Path != "" { + return fmt.Sprintf("ns:%s", availableNS.Path) + } + return "private" + } + } + } + return "host" +} diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 04233455d..fa2130a28 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -794,28 +794,8 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named hostConfig.PidMode = pidMode // UTS namespace mode - utsMode := "" - if c.config.UTSNsCtr != "" { - utsMode = fmt.Sprintf("container:%s", c.config.UTSNsCtr) - } else if ctrSpec.Linux != nil { - // Locate the spec's UTS namespace. - // If there is none, it's uts=host. - // If there is one and it has a path, it's "ns:". - // If there is no path, it's default - the empty string. - for _, ns := range ctrSpec.Linux.Namespaces { - if ns.Type == spec.UTSNamespace { - if ns.Path != "" { - utsMode = fmt.Sprintf("ns:%s", ns.Path) - } else { - utsMode = "private" - } - break - } - } - if utsMode == "" { - utsMode = "host" - } - } + utsMode := c.NamespaceMode(spec.UTSNamespace, ctrSpec) + hostConfig.UTSMode = utsMode // User namespace mode diff --git a/libpod/define/pod_inspect.go b/libpod/define/pod_inspect.go index 935e0f5f9..2afef48c4 100644 --- a/libpod/define/pod_inspect.go +++ b/libpod/define/pod_inspect.go @@ -122,6 +122,8 @@ type InspectPodInfraConfig struct { PidNS string `json:"pid_ns,omitempty"` // UserNS is the usernamespace that all the containers in the pod will join. UserNS string `json:"userns,omitempty"` + // UtsNS is the uts namespace that all containers in the pod will join + UtsNS string `json:"uts_ns,omitempty"` } // InspectPodContainerInfo contains information on a container in a pod. diff --git a/libpod/pod_api.go b/libpod/pod_api.go index e04bb6b05..c1d54d55e 100644 --- a/libpod/pod_api.go +++ b/libpod/pod_api.go @@ -676,6 +676,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) { infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus infraConfig.PidNS = p.NamespaceMode(specs.PIDNamespace) infraConfig.UserNS = p.NamespaceMode(specs.UserNamespace) + infraConfig.UtsNS = p.NamespaceMode(specs.UTSNamespace) namedVolumes, mounts := infra.SortUserVolumes(infra.config.Spec) inspectMounts, err = infra.GetMounts(namedVolumes, infra.config.ImageVolumes, mounts) infraSecurity = infra.GetSecurityOptions() diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go index 5616a4511..e09757d1d 100644 --- a/pkg/specgen/container_validate.go +++ b/pkg/specgen/container_validate.go @@ -59,6 +59,7 @@ func (s *SpecGenerator) Validate() error { if s.ContainerBasicConfig.UtsNS.IsPod() { return errors.Wrap(ErrInvalidSpecConfig, "cannot set hostname when joining the pod UTS namespace") } + return errors.Wrap(ErrInvalidSpecConfig, "cannot set hostname when running in the host UTS namespace") } // systemd values must be true, false, or always diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 6b2e90b22..f31e46090 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -133,6 +133,12 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener options = append(options, libpod.WithRootFSFromImage(newImage.ID(), resolvedImageName, s.RawImageName)) } + + _, err = rt.LookupPod(s.Hostname) + if len(s.Hostname) > 0 && !s.UtsNS.IsPrivate() && err == nil { + // ok, we are incorrectly setting the pod as the hostname, lets undo that before validation + s.Hostname = "" + } if err := s.Validate(); err != nil { return nil, nil, nil, errors.Wrap(err, "invalid config provided") } diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go index 4224d16ce..a3719d58e 100644 --- a/pkg/specgen/generate/namespaces.go +++ b/pkg/specgen/generate/namespaces.go @@ -176,7 +176,14 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod. if pod == nil || infraCtr == nil { return nil, errNoInfra } - toReturn = append(toReturn, libpod.WithUTSNSFrom(infraCtr)) + if pod.NamespaceMode(spec.UTSNamespace) == host { + // adding infra as a nsCtr is not what we want to do when uts == host + // this leads the new ctr to try to add an ns path which is should not in this mode + logrus.Debug("pod has host uts, not adding infra as a nsCtr") + s.UtsNS = specgen.Namespace{NSMode: specgen.Host} + } else { + toReturn = append(toReturn, libpod.WithUTSNSFrom(infraCtr)) + } case specgen.FromContainer: utsCtr, err := rt.LookupContainer(s.UtsNS.Value) if err != nil { diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go index 4ac8a0aa2..59936c7a8 100644 --- a/pkg/specgen/generate/pod_create.go +++ b/pkg/specgen/generate/pod_create.go @@ -60,6 +60,7 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) { if err != nil { return nil, err } + spec.Pod = pod.ID() opts = append(opts, rt.WithPod(pod)) spec.CgroupParent = pod.CgroupParent() diff --git a/test/e2e/pod_clone_test.go b/test/e2e/pod_clone_test.go index b90bf10da..0a1d2358c 100644 --- a/test/e2e/pod_clone_test.go +++ b/test/e2e/pod_clone_test.go @@ -11,9 +11,10 @@ import ( var _ = Describe("Podman pod clone", func() { var ( - tempdir string - err error - podmanTest *PodmanTestIntegration + tempdir string + err error + podmanTest *PodmanTestIntegration + hostname, _ = os.Hostname() ) BeforeEach(func() { @@ -155,4 +156,39 @@ var _ = Describe("Podman pod clone", func() { Expect(strings[0]).Should(ContainSubstring("size=10240k")) }) + It("podman pod create --uts test", func() { + SkipIfRemote("hostname for the custom NS test is not as expected on the remote client") + + session := podmanTest.Podman([]string{"pod", "create"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"pod", "clone", "--uts", "host", session.OutputToString()}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"run", "-it", "--pod", session.OutputToString(), ALPINE, "printenv", "HOSTNAME"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring(hostname)) + + podName := "utsPod" + ns := "ns:/proc/self/ns/" + + session = podmanTest.Podman([]string{"pod", "create"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + // just share uts with a custom path + podCreate := podmanTest.Podman([]string{"pod", "clone", "--uts", ns, "--name", podName, session.OutputToString()}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate).Should(Exit(0)) + + podInspect := podmanTest.Podman([]string{"pod", "inspect", podName}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect).Should(Exit(0)) + podJSON := podInspect.InspectPodToJSON() + Expect(podJSON.InfraConfig).To(HaveField("UtsNS", ns)) + }) + }) diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 0e363c1fb..10a8d52b5 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -23,9 +23,10 @@ import ( var _ = Describe("Podman pod create", func() { var ( - tempdir string - err error - podmanTest *PodmanTestIntegration + tempdir string + err error + podmanTest *PodmanTestIntegration + hostname, _ = os.Hostname() ) BeforeEach(func() { @@ -1136,4 +1137,30 @@ ENTRYPOINT ["sleep","99999"] Expect(run).ShouldNot(Exit(0)) }) + It("podman pod create --uts test", func() { + session := podmanTest.Podman([]string{"pod", "create", "--uts", "host"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"run", "-it", "--pod", session.OutputToString(), ALPINE, "printenv", "HOSTNAME"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + if !IsRemote() { // remote hostname will not match os.Hostname() + Expect(session.OutputToString()).To(ContainSubstring(hostname)) + } + + podName := "utsPod" + ns := "ns:/proc/self/ns/" + + // just share uts with a custom path + podCreate := podmanTest.Podman([]string{"pod", "create", "--uts", ns, "--name", podName, "--share", "uts"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate).Should(Exit(0)) + + podInspect := podmanTest.Podman([]string{"pod", "inspect", podName}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect).Should(Exit(0)) + podJSON := podInspect.InspectPodToJSON() + Expect(podJSON.InfraConfig).To(HaveField("UtsNS", ns)) + }) }) |