podman: handle namespaces specified on the CLI

and handle differently the user namespace as it supports additional
options.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano
2020-04-22 12:38:19 +02:00
parent 2fd6a84c09
commit 48530acbd9
6 changed files with 88 additions and 57 deletions

View File

@ -49,8 +49,9 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"cap-drop", []string{},
"Drop capabilities from the container",
)
cgroupNS := ""
createFlags.StringVar(
&cf.CGroupsNS,
&cgroupNS,
"cgroupns", containerConfig.CgroupNS(),
"cgroup namespace to use",
)
@ -247,8 +248,9 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"interactive", "i", false,
"Keep STDIN open even if not attached",
)
ipcNS := ""
createFlags.StringVar(
&cf.IPC,
&ipcNS,
"ipc", containerConfig.IPCNS(),
"IPC namespace to use",
)
@ -329,8 +331,9 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"use `OS` instead of the running OS for choosing images",
)
// markFlagHidden(createFlags, "override-os")
pid := ""
createFlags.StringVar(
&cf.PID,
&pid,
"pid", containerConfig.PidNS(),
"PID namespace to use",
)
@ -461,13 +464,15 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"user", "u", "",
"Username or UID (format: <name|uid>[:<group|gid>])",
)
userNS := ""
createFlags.StringVar(
&cf.UserNS,
&userNS,
"userns", containerConfig.Containers.UserNS,
"User namespace to use",
)
utsNS := ""
createFlags.StringVar(
&cf.UTS,
&utsNS,
"uts", containerConfig.Containers.UTSNS,
"UTS namespace to use",
)

View File

@ -222,55 +222,28 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.PortMappings = ep
s.Pod = c.Pod
//s.CgroupNS = specgen.Namespace{
// NSMode: ,
// Value: "",
//}
//s.UserNS = specgen.Namespace{}
// Kernel Namespaces
// TODO Fix handling of namespace from pod
// Instead of integrating here, should be done in libpod
// However, that also involves setting up security opts
// when the pod's namespace is integrated
//namespaces = map[string]string{
// "cgroup": c.CGroupsNS,
// "pid": c.PID,
// //"net": c.Net.Network.Value, // TODO need help here
// "ipc": c.IPC,
// "user": c.User,
// "uts": c.UTS,
//}
//
//if len(c.PID) > 0 {
// split := strings.SplitN(c.PID, ":", 2)
// // need a way to do thsi
// specgen.Namespace{
// NSMode: split[0],
// }
// //Value: split1 if len allows
//}
// TODO this is going to have be done after things like pod creation are done because
// pod creation changes these values.
//pidMode := ns.PidMode(namespaces["pid"])
//usernsMode := ns.UsernsMode(namespaces["user"])
//utsMode := ns.UTSMode(namespaces["uts"])
//cgroupMode := ns.CgroupMode(namespaces["cgroup"])
//ipcMode := ns.IpcMode(namespaces["ipc"])
//// Make sure if network is set to container namespace, port binding is not also being asked for
//netMode := ns.NetworkMode(namespaces["net"])
//if netMode.IsContainer() {
// if len(portBindings) > 0 {
// return nil, errors.Errorf("cannot set port bindings on an existing container network namespace")
// }
//}
// TODO Remove when done with namespaces for realz
// Setting a default for IPC to get this working
s.IpcNS = specgen.Namespace{
NSMode: specgen.Private,
Value: "",
for k, v := range map[string]*specgen.Namespace{
c.IPC: &s.IpcNS,
c.PID: &s.PidNS,
c.UTS: &s.UtsNS,
c.CGroupsNS: &s.CgroupNS,
} {
if k != "" {
*v, err = specgen.ParseNamespace(k)
if err != nil {
return err
}
}
}
// userns must be treated differently
if c.UserNS != "" {
s.UserNS, err = specgen.ParseUserNamespace(c.UserNS)
if err != nil {
return err
}
}
if c.Net != nil {
s.NetNS = c.Net.Network
}
// TODO this is going to have to be done the libpod/server end of things

View File

@ -149,6 +149,21 @@ func createInit(c *cobra.Command) error {
if c.Flag("no-hosts").Changed && c.Flag("add-host").Changed {
return errors.Errorf("--no-hosts and --add-host cannot be set together")
}
if c.Flag("userns").Changed {
cliVals.UserNS = c.Flag("userns").Value.String()
}
if c.Flag("ipc").Changed {
cliVals.IPC = c.Flag("ipc").Value.String()
}
if c.Flag("uts").Changed {
cliVals.UTS = c.Flag("uts").Value.String()
}
if c.Flag("pid").Changed {
cliVals.PID = c.Flag("pid").Value.String()
}
if c.Flag("cgroupns").Changed {
cliVals.CGroupsNS = c.Flag("cgroupns").Value.String()
}
// Docker-compatibility: the "-h" flag for run/create is reserved for
// the hostname (see https://github.com/containers/libpod/issues/1367).

View File

@ -129,7 +129,7 @@ func (s *SpecGenerator) Validate() error {
if err := s.CgroupNS.validate(); err != nil {
return err
}
if err := s.UserNS.validate(); err != nil {
if err := validateUserNS(&s.UserNS); err != nil {
return err
}

View File

@ -58,8 +58,7 @@ func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod)
case "uts":
return specgen.ParseNamespace(cfg.Containers.UTSNS)
case "user":
// TODO: This may not work for --userns=auto
return specgen.ParseNamespace(cfg.Containers.UserNS)
return specgen.ParseUserNamespace(cfg.Containers.UserNS)
case "net":
ns, _, err := specgen.ParseNetworkNamespace(cfg.Containers.NetNS)
return ns, err

View File

@ -33,6 +33,11 @@ const (
// Slirp indicates that a slirp4netns network stack should
// be used
Slirp NamespaceMode = "slirp4netns"
// KeepId indicates a user namespace to keep the owner uid inside
// of the namespace itself
KeepID NamespaceMode = "keep-id"
// KeepId indicates to automatically create a user namespace
Auto NamespaceMode = "auto"
)
// Namespace describes the namespace
@ -71,6 +76,16 @@ func (n *Namespace) IsPod() bool {
func (n *Namespace) IsPrivate() bool {
return n.NSMode == Private
}
func validateUserNS(n *Namespace) error {
if n == nil {
return nil
}
switch n.NSMode {
case Auto, KeepID:
return nil
}
return n.validate()
}
func validateNetNS(n *Namespace) error {
if n == nil {
@ -158,6 +173,30 @@ func ParseNamespace(ns string) (Namespace, error) {
return toReturn, nil
}
// ParseUserNamespace parses a user namespace specification in string
// form.
func ParseUserNamespace(ns string) (Namespace, error) {
toReturn := Namespace{}
switch {
case ns == "auto":
toReturn.NSMode = Auto
return toReturn, nil
case strings.HasPrefix(ns, "auto:"):
split := strings.SplitN(ns, ":", 2)
if len(split) != 2 {
return toReturn, errors.Errorf("invalid setting for auto: mode")
}
toReturn.NSMode = KeepID
toReturn.Value = split[1]
return toReturn, nil
case ns == "keep-id":
toReturn.NSMode = KeepID
toReturn.NSMode = FromContainer
return toReturn, nil
}
return ParseNamespace(ns)
}
// ParseNetworkNamespace parses a network namespace specification in string
// form.
// Returns a namespace and (optionally) a list of CNI networks to join.