Add API for sharing namespaces

Remove existing code for sharing namespaces and replace with use
of this API

Signed-off-by: Matthew Heon <matthew.heon@gmail.com>

Closes: #220
Approved by: rhatdan
This commit is contained in:
Matthew Heon
2018-01-11 17:41:59 -05:00
committed by Atomic Bot
parent 2ac4192bd3
commit d2ec1f7628
3 changed files with 193 additions and 71 deletions

View File

@ -2,7 +2,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"strings" "strings"
@ -53,21 +52,10 @@ func blockAccessToKernelFilesystems(config *createConfig, g *generate.Generator)
func addPidNS(config *createConfig, g *generate.Generator) error { func addPidNS(config *createConfig, g *generate.Generator) error {
pidMode := config.PidMode pidMode := config.PidMode
if pidMode.IsHost() { if pidMode.IsHost() {
return g.RemoveLinuxNamespace(libpod.PIDNamespace) return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
} }
if pidMode.IsContainer() { if pidMode.IsContainer() {
ctr, err := config.Runtime.LookupContainer(pidMode.Container()) logrus.Debug("using container pidmode")
if err != nil {
return errors.Wrapf(err, "container %q not found", pidMode.Container())
}
pid, err := ctr.PID()
if err != nil {
return errors.Wrapf(err, "Failed to get pid of container %q", pidMode.Container())
}
pidNsPath := fmt.Sprintf("/proc/%d/ns/pid", pid)
if err := g.AddOrReplaceLinuxNamespace(libpod.PIDNamespace, pidNsPath); err != nil {
return err
}
} }
return nil return nil
} }
@ -76,7 +64,7 @@ func addNetNS(config *createConfig, g *generate.Generator) error {
netMode := config.NetMode netMode := config.NetMode
if netMode.IsHost() { if netMode.IsHost() {
logrus.Debug("Using host netmode") logrus.Debug("Using host netmode")
return g.RemoveLinuxNamespace(libpod.NetNamespace) return g.RemoveLinuxNamespace(spec.NetworkNamespace)
} else if netMode.IsNone() { } else if netMode.IsNone() {
logrus.Debug("Using none netmode") logrus.Debug("Using none netmode")
return nil return nil
@ -85,18 +73,6 @@ func addNetNS(config *createConfig, g *generate.Generator) error {
return nil return nil
} else if netMode.IsContainer() { } else if netMode.IsContainer() {
logrus.Debug("Using container netmode") logrus.Debug("Using container netmode")
ctr, err := config.Runtime.LookupContainer(netMode.ConnectedContainer())
if err != nil {
return errors.Wrapf(err, "container %q not found", netMode.ConnectedContainer())
}
pid, err := ctr.PID()
if err != nil {
return errors.Wrapf(err, "Failed to get pid of container %q", netMode.ConnectedContainer())
}
nsPath := fmt.Sprintf("/proc/%d/ns/net", pid)
if err := g.AddOrReplaceLinuxNamespace(libpod.NetNamespace, nsPath); err != nil {
return err
}
} else { } else {
return errors.Errorf("unknown network mode") return errors.Errorf("unknown network mode")
} }
@ -106,7 +82,7 @@ func addNetNS(config *createConfig, g *generate.Generator) error {
func addUTSNS(config *createConfig, g *generate.Generator) error { func addUTSNS(config *createConfig, g *generate.Generator) error {
utsMode := config.UtsMode utsMode := config.UtsMode
if utsMode.IsHost() { if utsMode.IsHost() {
return g.RemoveLinuxNamespace(libpod.UTSNamespace) return g.RemoveLinuxNamespace(spec.UTSNamespace)
} }
return nil return nil
} }
@ -114,21 +90,10 @@ func addUTSNS(config *createConfig, g *generate.Generator) error {
func addIpcNS(config *createConfig, g *generate.Generator) error { func addIpcNS(config *createConfig, g *generate.Generator) error {
ipcMode := config.IpcMode ipcMode := config.IpcMode
if ipcMode.IsHost() { if ipcMode.IsHost() {
return g.RemoveLinuxNamespace(libpod.IPCNamespace) return g.RemoveLinuxNamespace(spec.IPCNamespace)
} }
if ipcMode.IsContainer() { if ipcMode.IsContainer() {
ctr, err := config.Runtime.LookupContainer(ipcMode.Container()) logrus.Debug("Using container ipcmode")
if err != nil {
return errors.Wrapf(err, "container %q not found", ipcMode.Container())
}
pid, err := ctr.PID()
if err != nil {
return errors.Wrapf(err, "Failed to get pid of container %q", ipcMode.Container())
}
nsPath := fmt.Sprintf("/proc/%d/ns/ipc", pid)
if err := g.AddOrReplaceLinuxNamespace(libpod.IPCNamespace, nsPath); err != nil {
return err
}
} }
return nil return nil
@ -580,9 +545,33 @@ func (c *createConfig) GetContainerCreateOptions() ([]libpod.CtrCreateOption, er
options = append(options, libpod.WithName(c.Name)) options = append(options, libpod.WithName(c.Name))
} }
// TODO parse ports into libpod format and include // TODO parse ports into libpod format and include
if !c.NetMode.IsHost() { if !c.NetMode.IsHost() && !c.NetMode.IsContainer() {
options = append(options, libpod.WithNetNS([]ocicni.PortMapping{})) options = append(options, libpod.WithNetNS([]ocicni.PortMapping{}))
} else if c.NetMode.IsContainer() {
connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.ConnectedContainer())
if err != nil {
return nil, errors.Wrapf(err, "container %q not found", c.NetMode.ConnectedContainer())
} }
options = append(options, libpod.WithNetNSFrom(connectedCtr))
}
if c.PidMode.IsContainer() {
connectedCtr, err := c.Runtime.LookupContainer(c.PidMode.Container())
if err != nil {
return nil, errors.Wrapf(err, "container %q not found", c.PidMode.Container())
}
options = append(options, libpod.WithPIDNSFrom(connectedCtr))
}
if c.IpcMode.IsContainer() {
connectedCtr, err := c.Runtime.LookupContainer(c.IpcMode.Container())
if err != nil {
return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container())
}
options = append(options, libpod.WithIPCNSFrom(connectedCtr))
}
options = append(options, libpod.WithStopSignal(c.StopSignal)) options = append(options, libpod.WithStopSignal(c.StopSignal))
options = append(options, libpod.WithStopTimeout(c.StopTimeout)) options = append(options, libpod.WithStopTimeout(c.StopTimeout))
return options, nil return options, nil

View File

@ -133,7 +133,6 @@ type Container struct {
// TODO enable pod support // TODO enable pod support
// TODO Add readonly support // TODO Add readonly support
// TODO add SHM size support // TODO add SHM size support
// TODO add shared namespace support
// containerRuntimeInfo contains the current state of the container // containerRuntimeInfo contains the current state of the container
// It is stored on disk in a tmpfs and recreated on reboot // It is stored on disk in a tmpfs and recreated on reboot

View File

@ -1,7 +1,6 @@
package libpod package libpod
import ( import (
"fmt"
"path/filepath" "path/filepath"
"regexp" "regexp"
"syscall" "syscall"
@ -13,27 +12,9 @@ import (
) )
var ( var (
ctrNotImplemented = func(c *Container) error {
return fmt.Errorf("NOT IMPLEMENTED")
}
nameRegex = regexp.MustCompile("[a-zA-Z0-9_-]+") nameRegex = regexp.MustCompile("[a-zA-Z0-9_-]+")
) )
const (
// IPCNamespace represents the IPC namespace
IPCNamespace = "ipc"
// MountNamespace represents the mount namespace
MountNamespace = "mount"
// NetNamespace represents the network namespace
NetNamespace = "network"
// PIDNamespace represents the PID namespace
PIDNamespace = "pid"
// UserNamespace represents the user namespace
UserNamespace = "user"
// UTSNamespace represents the UTS namespace
UTSNamespace = "uts"
)
// Runtime Creation Options // Runtime Creation Options
// WithStorageConfig uses the given configuration to set up container storage // WithStorageConfig uses the given configuration to set up container storage
@ -341,15 +322,6 @@ func WithStdin() CtrCreateOption {
} }
} }
// WithSharedNamespaces sets a container to share namespaces with another
// container. If the from container belongs to a pod, the new container will
// be added to the pod.
// By default no namespaces are shared. To share a namespace, add the Namespace
// string constant to the map as a key
func WithSharedNamespaces(from *Container, namespaces map[string]string) CtrCreateOption {
return ctrNotImplemented
}
// WithPod adds the container to a pod // WithPod adds the container to a pod
func (r *Runtime) WithPod(pod *Pod) CtrCreateOption { func (r *Runtime) WithPod(pod *Pod) CtrCreateOption {
return func(ctr *Container) error { return func(ctr *Container) error {
@ -434,6 +406,164 @@ func WithStopTimeout(timeout uint) CtrCreateOption {
} }
} }
// WithIPCNSFrom indicates the the container should join the IPC namespace of
// the given container
func WithIPCNSFrom(nsCtr *Container) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
if !nsCtr.valid {
return ErrCtrRemoved
}
if nsCtr.ID() == ctr.ID() {
return errors.Wrapf(ErrInvalidArg, "must specify another container")
}
ctr.config.IPCNsCtr = nsCtr.ID()
return nil
}
}
// WithMountNSFrom indicates the the container should join the mount namespace
// of the given container
func WithMountNSFrom(nsCtr *Container) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
if !nsCtr.valid {
return ErrCtrRemoved
}
if nsCtr.ID() == ctr.ID() {
return errors.Wrapf(ErrInvalidArg, "must specify another container")
}
ctr.config.MountNsCtr = nsCtr.ID()
return nil
}
}
// WithNetNSFrom indicates the the container should join the network namespace
// of the given container
func WithNetNSFrom(nsCtr *Container) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
if !nsCtr.valid {
return ErrCtrRemoved
}
if nsCtr.ID() == ctr.ID() {
return errors.Wrapf(ErrInvalidArg, "must specify another container")
}
if ctr.config.CreateNetNS {
return errors.Wrapf(ErrInvalidArg, "cannot join another container's net ns as we are making a new net ns")
}
ctr.config.NetNsCtr = nsCtr.ID()
return nil
}
}
// WithPIDNSFrom indicates the the container should join the PID namespace of
// the given container
func WithPIDNSFrom(nsCtr *Container) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
if !nsCtr.valid {
return ErrCtrRemoved
}
if nsCtr.ID() == ctr.ID() {
return errors.Wrapf(ErrInvalidArg, "must specify another container")
}
ctr.config.PIDNsCtr = nsCtr.ID()
return nil
}
}
// WithUserNSFrom indicates the the container should join the user namespace of
// the given container
func WithUserNSFrom(nsCtr *Container) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
if !nsCtr.valid {
return ErrCtrRemoved
}
if nsCtr.ID() == ctr.ID() {
return errors.Wrapf(ErrInvalidArg, "must specify another container")
}
ctr.config.UserNsCtr = nsCtr.ID()
return nil
}
}
// WithUTSNSFrom indicates the the container should join the UTS namespace of
// the given container
func WithUTSNSFrom(nsCtr *Container) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
if !nsCtr.valid {
return ErrCtrRemoved
}
if nsCtr.ID() == ctr.ID() {
return errors.Wrapf(ErrInvalidArg, "must specify another container")
}
ctr.config.UTSNsCtr = nsCtr.ID()
return nil
}
}
// WithCgroupNSFrom indicates the the container should join the CGroup namespace
// of the given container
func WithCgroupNSFrom(nsCtr *Container) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
if !nsCtr.valid {
return ErrCtrRemoved
}
if nsCtr.ID() == ctr.ID() {
return errors.Wrapf(ErrInvalidArg, "must specify another container")
}
ctr.config.CgroupNsCtr = nsCtr.ID()
return nil
}
}
// WithNetNS indicates that the container should be given a new network // WithNetNS indicates that the container should be given a new network
// namespace with a minimal configuration // namespace with a minimal configuration
// An optional array of port mappings can be provided // An optional array of port mappings can be provided
@ -443,6 +573,10 @@ func WithNetNS(portMappings []ocicni.PortMapping) CtrCreateOption {
return ErrCtrFinalized return ErrCtrFinalized
} }
if ctr.config.NetNsCtr != "" {
return errors.Wrapf(ErrInvalidArg, "container is already set to join another container's net ns, cannot create a new net ns")
}
ctr.config.CreateNetNS = true ctr.config.CreateNetNS = true
copy(ctr.config.PortMappings, portMappings) copy(ctr.config.PortMappings, portMappings)