aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcdoern <cdoern@redhat.com>2022-06-06 13:03:37 -0400
committerCharlie Doern <cdoern@redhat.com>2022-07-05 09:28:07 -0400
commit8f2d9e7a7c30f5e74f6aa0375b21a4522ec81756 (patch)
tree03526a91d8d8c428547b63b22f145e59a373bd63
parent13479d457d34496b43027bc1d71cdb0891a8b738 (diff)
downloadpodman-8f2d9e7a7c30f5e74f6aa0375b21a4522ec81756.tar.gz
podman-8f2d9e7a7c30f5e74f6aa0375b21a4522ec81756.tar.bz2
podman-8f2d9e7a7c30f5e74f6aa0375b21a4522ec81756.zip
podman pod create --uts support
add support for the --uts flag in pod create, allowing users to avoid issues with default values in containers.conf. uts follows the same format as other namespace flags: --uts=private (default), --uts=host, --uts=ns:PATH resolves #13714 Signed-off-by: Charlie Doern <cdoern@redhat.com>
-rw-r--r--cmd/podman/common/create.go15
-rw-r--r--cmd/podman/containers/create.go1
-rw-r--r--cmd/podman/pods/create.go1
-rw-r--r--docs/source/markdown/podman-pod-clone.1.md9
-rw-r--r--docs/source/markdown/podman-pod-create.1.md8
-rw-r--r--libpod/container.go49
-rw-r--r--libpod/container_inspect.go24
-rw-r--r--libpod/define/pod_inspect.go2
-rw-r--r--libpod/pod_api.go1
-rw-r--r--pkg/specgen/container_validate.go1
-rw-r--r--pkg/specgen/generate/container_create.go6
-rw-r--r--pkg/specgen/generate/namespaces.go9
-rw-r--r--pkg/specgen/generate/pod_create.go1
-rw-r--r--test/e2e/pod_clone_test.go42
-rw-r--r--test/e2e/pod_create_test.go33
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 0619471b4..1e2dad3f3 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -1336,3 +1336,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 93240812d..7ccd9fdbf 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 f06e62007..29dc22890 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 e463862f5..4effc98ca 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))
+ })
})