From a87fb78dd1d7a99b84786364f83f423fdffe892e Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 6 Aug 2019 08:35:59 -0400 Subject: Properly share UTS namespaces in a pod Sharing a UTS namespace means sharing the hostname. Fix situations where a container in a pod didn't properly share the hostname of the pod. Signed-off-by: Peter Hunt --- pkg/spec/spec.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index c94746767..c16696ffe 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -174,10 +174,20 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM } hostname := config.Hostname - if hostname == "" && (config.NetMode.IsHost() || config.UtsMode.IsHost()) { - hostname, err = os.Hostname() - if err != nil { - return nil, errors.Wrap(err, "unable to retrieve hostname") + if hostname == "" { + if utsCtrID := config.UtsMode.Container(); utsCtrID != "" { + utsCtr, err := runtime.GetContainer(utsCtrID) + if err != nil { + return nil, errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID) + } + hostname = utsCtr.Hostname() + } else if config.NetMode.IsHost() || config.UtsMode.IsHost() { + hostname, err = os.Hostname() + if err != nil { + return nil, errors.Wrap(err, "unable to retrieve hostname of the host") + } + } else { + logrus.Debug("No hostname set; container's hostname will default to runtime default") } } g.RemoveHostname() @@ -606,6 +616,9 @@ func addUTSNS(config *CreateConfig, g *generate.Generator) error { if utsMode.IsHost() { return g.RemoveLinuxNamespace(string(spec.UTSNamespace)) } + if utsMode.IsContainer() { + logrus.Debug("using container utsmode") + } return nil } -- cgit v1.2.3-54-g00ecf From 7c9225610337c76203540377955ef7ae33302ba0 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 6 Aug 2019 13:15:54 -0400 Subject: add test to verify hostname is shared in a pod Signed-off-by: Peter Hunt --- test/e2e/pod_infra_container_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go index c8763de9f..3897aa851 100644 --- a/test/e2e/pod_infra_container_test.go +++ b/test/e2e/pod_infra_container_test.go @@ -383,4 +383,24 @@ var _ = Describe("Podman pod create", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) + + It("podman run hostname is shared", func() { + session := podmanTest.Podman([]string{"pod", "create"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podID := session.OutputToString() + + // verify we can add a host to the infra's /etc/hosts + session = podmanTest.Podman([]string{"run", "--pod", podID, ALPINE, "hostname"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + hostname := session.OutputToString() + + infraName := podID[:12] + "-infra" + // verify we can see the other hosts of infra's /etc/hosts + session = podmanTest.Podman([]string{"inspect", infraName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(hostname)) + }) }) -- cgit v1.2.3-54-g00ecf From a602e44e74865333d416fb75a29ba55554c3b02f Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 6 Aug 2019 15:24:12 -0400 Subject: refer to container whose namespace we share Signed-off-by: Peter Hunt --- pkg/spec/spec.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index c16696ffe..156d6849d 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -551,8 +551,8 @@ func addPidNS(config *CreateConfig, g *generate.Generator) error { if pidMode.IsHost() { return g.RemoveLinuxNamespace(string(spec.PIDNamespace)) } - if pidMode.IsContainer() { - logrus.Debug("using container pidmode") + if pidCtr := pidMode.Container(); pidCtr != "" { + logrus.Debugf("using container %s pidmode", pidCtr) } if IsPod(string(pidMode)) { logrus.Debug("using pod pidmode") @@ -589,8 +589,8 @@ func addNetNS(config *CreateConfig, g *generate.Generator) error { } else if netMode.IsBridge() { logrus.Debug("Using bridge netmode") return nil - } else if netMode.IsContainer() { - logrus.Debug("Using container netmode") + } else if netCtr := netMode.Container(); netCtr != "" { + logrus.Debugf("using container %s netmode", netCtr) return nil } else if IsNS(string(netMode)) { logrus.Debug("Using ns netmode") @@ -616,8 +616,8 @@ func addUTSNS(config *CreateConfig, g *generate.Generator) error { if utsMode.IsHost() { return g.RemoveLinuxNamespace(string(spec.UTSNamespace)) } - if utsMode.IsContainer() { - logrus.Debug("using container utsmode") + if utsCtr := utsMode.Container(); utsCtr != "" { + logrus.Debugf("using container %s utsmode", utsCtr) } return nil } @@ -630,8 +630,8 @@ func addIpcNS(config *CreateConfig, g *generate.Generator) error { if ipcMode.IsHost() { return g.RemoveLinuxNamespace(string(spec.IPCNamespace)) } - if ipcMode.IsContainer() { - logrus.Debug("Using container ipcmode") + if ipcCtr := ipcMode.Container(); ipcCtr != "" { + logrus.Debugf("Using container %s ipcmode", ipcCtr) } return nil @@ -648,8 +648,8 @@ func addCgroupNS(config *CreateConfig, g *generate.Generator) error { if cgroupMode.IsPrivate() { return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "") } - if cgroupMode.IsContainer() { - logrus.Debug("Using container cgroup mode") + if cgCtr := cgroupMode.Container(); cgCtr != "" { + logrus.Debugf("Using container %s cgroup mode", cgCtr) } return nil } -- cgit v1.2.3-54-g00ecf From dc750df8024ad3782a09ccc8d60ac82d5bb9eaca Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Wed, 7 Aug 2019 13:11:04 -0400 Subject: namespaces: fix Container() call If we call Container(), we expect the namespace to be prefixed with "container:". Add this check, and refactor to use named const strings instead of string literals Signed-off-by: Peter Hunt --- pkg/namespaces/namespaces.go | 87 +++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go index 35298796f..9d1033b93 100644 --- a/pkg/namespaces/namespaces.go +++ b/pkg/namespaces/namespaces.go @@ -4,17 +4,30 @@ import ( "strings" ) +const ( + bridgeType = "bridge" + containerType = "container" + defaultType = "default" + hostType = "host" + noneType = "none" + nsType = "ns" + podType = "pod" + privateType = "private" + shareableType = "shareable" + slirpType = "slirp4netns" +) + // CgroupMode represents cgroup mode in the container. type CgroupMode string // IsHost indicates whether the container uses the host's cgroup. func (n CgroupMode) IsHost() bool { - return n == "host" + return n == hostType } // IsNS indicates a cgroup namespace passed in by path (ns:) func (n CgroupMode) IsNS() bool { - return strings.HasPrefix(string(n), "ns:") + return strings.HasPrefix(string(n), nsType) } // NS gets the path associated with a ns: cgroup ns @@ -29,13 +42,13 @@ func (n CgroupMode) NS() string { // IsContainer indicates whether the container uses a new cgroup namespace. func (n CgroupMode) IsContainer() bool { parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" + return len(parts) > 1 && parts[0] == containerType } // Container returns the name of the container whose cgroup namespace is going to be used. func (n CgroupMode) Container() string { parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { + if len(parts) > 1 && parts[0] == containerType { return parts[1] } return "" @@ -43,15 +56,15 @@ func (n CgroupMode) Container() string { // IsPrivate indicates whether the container uses the a private cgroup. func (n CgroupMode) IsPrivate() bool { - return n == "private" + return n == privateType } // Valid indicates whether the Cgroup namespace is valid. func (n CgroupMode) Valid() bool { parts := strings.Split(string(n), ":") switch mode := parts[0]; mode { - case "", "host", "private", "ns": - case "container": + case "", hostType, privateType, nsType: + case containerType: if len(parts) != 2 || parts[1] == "" { return false } @@ -66,7 +79,7 @@ type UsernsMode string // IsHost indicates whether the container uses the host's userns. func (n UsernsMode) IsHost() bool { - return n == "host" + return n == hostType } // IsKeepID indicates whether container uses a mapping where the (uid, gid) on the host is lept inside of the namespace. @@ -83,8 +96,8 @@ func (n UsernsMode) IsPrivate() bool { func (n UsernsMode) Valid() bool { parts := strings.Split(string(n), ":") switch mode := parts[0]; mode { - case "", "host", "keep-id", "ns": - case "container": + case "", hostType, "keep-id", nsType: + case containerType: if len(parts) != 2 || parts[1] == "" { return false } @@ -111,13 +124,13 @@ func (n UsernsMode) NS() string { // IsContainer indicates whether container uses a container userns. func (n UsernsMode) IsContainer() bool { parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" + return len(parts) > 1 && parts[0] == containerType } // Container is the id of the container which network this container is connected to. func (n UsernsMode) Container() string { parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { + if len(parts) > 1 && parts[0] == containerType { return parts[1] } return "" @@ -133,19 +146,19 @@ func (n UTSMode) IsPrivate() bool { // IsHost indicates whether the container uses the host's UTS namespace. func (n UTSMode) IsHost() bool { - return n == "host" + return n == hostType } // IsContainer indicates whether the container uses a container's UTS namespace. func (n UTSMode) IsContainer() bool { parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" + return len(parts) > 1 && parts[0] == containerType } // Container returns the name of the container whose uts namespace is going to be used. func (n UTSMode) Container() string { parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { + if len(parts) > 1 && parts[0] == containerType { return parts[1] } return "" @@ -155,8 +168,8 @@ func (n UTSMode) Container() string { func (n UTSMode) Valid() bool { parts := strings.Split(string(n), ":") switch mode := parts[0]; mode { - case "", "host": - case "container": + case "", hostType: + case containerType: if len(parts) != 2 || parts[1] == "" { return false } @@ -171,28 +184,28 @@ type IpcMode string // IsPrivate indicates whether the container uses its own private ipc namespace which cannot be shared. func (n IpcMode) IsPrivate() bool { - return n == "private" + return n == privateType } // IsHost indicates whether the container shares the host's ipc namespace. func (n IpcMode) IsHost() bool { - return n == "host" + return n == hostType } // IsShareable indicates whether the container's ipc namespace can be shared with another container. func (n IpcMode) IsShareable() bool { - return n == "shareable" + return n == shareableType } // IsContainer indicates whether the container uses another container's ipc namespace. func (n IpcMode) IsContainer() bool { parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" + return len(parts) > 1 && parts[0] == containerType } // IsNone indicates whether container IpcMode is set to "none". func (n IpcMode) IsNone() bool { - return n == "none" + return n == noneType } // IsEmpty indicates whether container IpcMode is empty @@ -208,7 +221,7 @@ func (n IpcMode) Valid() bool { // Container returns the name of the container ipc stack is going to be used. func (n IpcMode) Container() string { parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 && parts[0] == "container" { + if len(parts) > 1 && parts[0] == containerType { return parts[1] } return "" @@ -224,21 +237,21 @@ func (n PidMode) IsPrivate() bool { // IsHost indicates whether the container uses the host's pid namespace. func (n PidMode) IsHost() bool { - return n == "host" + return n == hostType } // IsContainer indicates whether the container uses a container's pid namespace. func (n PidMode) IsContainer() bool { parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" + return len(parts) > 1 && parts[0] == containerType } // Valid indicates whether the pid namespace is valid. func (n PidMode) Valid() bool { parts := strings.Split(string(n), ":") switch mode := parts[0]; mode { - case "", "host": - case "container": + case "", hostType: + case containerType: if len(parts) != 2 || parts[1] == "" { return false } @@ -251,7 +264,7 @@ func (n PidMode) Valid() bool { // Container returns the name of the container whose pid namespace is going to be used. func (n PidMode) Container() string { parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { + if len(parts) > 1 && parts[0] == containerType { return parts[1] } return "" @@ -262,17 +275,17 @@ type NetworkMode string // IsNone indicates whether container isn't using a network stack. func (n NetworkMode) IsNone() bool { - return n == "none" + return n == noneType } // IsHost indicates whether the container uses the host's network stack. func (n NetworkMode) IsHost() bool { - return n == "host" + return n == hostType } // IsDefault indicates whether container uses the default network stack. func (n NetworkMode) IsDefault() bool { - return n == "default" + return n == defaultType } // IsPrivate indicates whether container uses its private network stack. @@ -283,13 +296,13 @@ func (n NetworkMode) IsPrivate() bool { // IsContainer indicates whether container uses a container network stack. func (n NetworkMode) IsContainer() bool { parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" + return len(parts) > 1 && parts[0] == containerType } // Container is the id of the container which network this container is connected to. func (n NetworkMode) Container() string { parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { + if len(parts) > 1 && parts[0] == containerType { return parts[1] } return "" @@ -305,17 +318,17 @@ func (n NetworkMode) UserDefined() string { // IsBridge indicates whether container uses the bridge network stack func (n NetworkMode) IsBridge() bool { - return n == "bridge" + return n == bridgeType } // IsSlirp4netns indicates if we are running a rootless network stack func (n NetworkMode) IsSlirp4netns() bool { - return n == "slirp4netns" + return n == slirpType } // IsNS indicates a network namespace passed in by path (ns:) func (n NetworkMode) IsNS() bool { - return strings.HasPrefix(string(n), "ns:") + return strings.HasPrefix(string(n), nsType) } // NS gets the path associated with a ns: network ns @@ -329,7 +342,7 @@ func (n NetworkMode) NS() string { // IsPod returns whether the network refers to pod networking func (n NetworkMode) IsPod() bool { - return n == "pod" + return n == podType } // IsUserDefined indicates user-created network -- cgit v1.2.3-54-g00ecf