Add support for joining shared namespaces in libpod

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

Closes: #220
Approved by: rhatdan
This commit is contained in:
Matthew Heon 2018-01-11 15:14:44 -05:00 committed by Atomic Bot
parent 333f664da7
commit fe0e1cd11b
1 changed files with 155 additions and 0 deletions

View File

@ -63,6 +63,49 @@ const (
// CgroupParent is the default prefix to a cgroup path in libpod
var CgroupParent = "/libpod_parent"
// LinuxNS represents a Linux namespace
type LinuxNS int
const (
// InvalidNS is an invalid namespace
InvalidNS LinuxNS = iota
// IPCNS is the IPC namespace
IPCNS LinuxNS = iota
// MntNS is the mount namespace
MountNS LinuxNS = iota
// NetNS is the network namespace
NetNS LinuxNS = iota
// PIDNS is the PID namespace
PIDNS LinuxNS = iota
// UserNS is the user namespace
UserNS LinuxNS = iota
// UTSNS is the UTS namespace
UTSNS LinuxNS = iota
)
// String returns a string representation of a Linux namespace
// It is guaranteed to be the name of the namespace in /proc for valid ns types
func (ns LinuxNS) String() string {
switch ns {
case InvalidNS:
return "invalid"
case IPCNS:
return "ipc"
case MountNS:
return "mnt"
case NetNS:
return "net"
case PIDNS:
return "pid"
case UserNS:
return "user"
case UTSNS:
return "uts"
default:
return "unknown"
}
}
// Container is a single OCI container
type Container struct {
config *ContainerConfig
@ -484,6 +527,26 @@ func (c *Container) MountPoint() (string, error) {
return c.state.Mountpoint, nil
}
// NamespacePath returns the path of one of the container's namespaces
// If the container is not running, an error will be returned
func (c *Container) NamespacePath(ns LinuxNS) (string, error) {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return "", errors.Wrapf(err, "error updating container %s state", c.ID())
}
if c.state.State != ContainerStateRunning {
return "", errors.Wrapf(ErrCtrStopped, "cannot get namespace path unless container %s is running", c.ID())
}
if ns == InvalidNS {
return "", errors.Wrapf(ErrInvalidArg, "invalid namespace requested from container %s", c.ID())
}
return fmt.Sprintf("/proc/%d/ns/%s", c.state.PID, ns.String()), nil
}
// The path to the container's root filesystem - where the OCI spec will be
// placed, amongst other things
func (c *Container) bundlePath() string {
@ -766,6 +829,98 @@ func (c *Container) Init() (err error) {
g.SetProcessGID(gid)
}
// Add shared namespaces from other containers
if c.config.IPCNsCtr != "" {
ipcCtr, err := c.runtime.state.Container(c.config.IPCNsCtr)
if err != nil {
return err
}
nsPath, err := ipcCtr.NamespacePath(IPCNS)
if err != nil {
return err
}
if err := g.AddOrReplaceLinuxNamespace(spec.IPCNamespace, nsPath); err != nil {
return err
}
}
if c.config.MountNsCtr != "" {
mountCtr, err := c.runtime.state.Container(c.config.MountNsCtr)
if err != nil {
return err
}
nsPath, err := mountCtr.NamespacePath(MountNS)
if err != nil {
return err
}
if err := g.AddOrReplaceLinuxNamespace(spec.MountNamespace, nsPath); err != nil {
return err
}
}
if c.config.NetNsCtr != "" {
netCtr, err := c.runtime.state.Container(c.config.NetNsCtr)
if err != nil {
return err
}
nsPath, err := netCtr.NamespacePath(NetNS)
if err != nil {
return err
}
if err := g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, nsPath); err != nil {
return err
}
}
if c.config.PIDNsCtr != "" {
pidCtr, err := c.runtime.state.Container(c.config.PIDNsCtr)
if err != nil {
return err
}
nsPath, err := pidCtr.NamespacePath(PIDNS)
if err != nil {
return err
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), nsPath); err != nil {
return err
}
}
if c.config.UserNsCtr != "" {
userCtr, err := c.runtime.state.Container(c.config.UserNsCtr)
if err != nil {
return err
}
nsPath, err := userCtr.NamespacePath(UserNS)
if err != nil {
return err
}
if err := g.AddOrReplaceLinuxNamespace(spec.UserNamespace, nsPath); err != nil {
return err
}
}
if c.config.UTSNsCtr != "" {
utsCtr, err := c.runtime.state.Container(c.config.UTSNsCtr)
if err != nil {
return err
}
nsPath, err := utsCtr.NamespacePath(UTSNS)
if err != nil {
return err
}
if err := g.AddOrReplaceLinuxNamespace(spec.UTSNamespace, nsPath); err != nil {
return err
}
}
c.runningSpec = g.Spec()
c.runningSpec.Root.Path = c.state.Mountpoint
c.runningSpec.Annotations[crioAnnotations.Created] = c.config.CreatedTime.Format(time.RFC3339Nano)