Merge pull request #3741 from haircommander/uts-fix
Properly share UTS namespaces in a pod
This commit is contained in:
		
						commit
						35ecf498dc
					
				|  | @ -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:<path>)
 | ||||
| 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:<path> 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:<path>)
 | ||||
| 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:<path> 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
 | ||||
|  |  | |||
|  | @ -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() | ||||
|  | @ -541,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") | ||||
|  | @ -579,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") | ||||
|  | @ -606,6 +616,9 @@ func addUTSNS(config *CreateConfig, g *generate.Generator) error { | |||
| 	if utsMode.IsHost() { | ||||
| 		return g.RemoveLinuxNamespace(string(spec.UTSNamespace)) | ||||
| 	} | ||||
| 	if utsCtr := utsMode.Container(); utsCtr != "" { | ||||
| 		logrus.Debugf("using container %s utsmode", utsCtr) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  | @ -617,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 | ||||
|  | @ -635,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 | ||||
| } | ||||
|  |  | |||
|  | @ -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)) | ||||
| 	}) | ||||
| }) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue