From fe0e1cd11bd1d98c7687a58011746f6b189c8d67 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Thu, 11 Jan 2018 15:14:44 -0500 Subject: Add support for joining shared namespaces in libpod Signed-off-by: Matthew Heon Closes: #220 Approved by: rhatdan --- libpod/container.go | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/libpod/container.go b/libpod/container.go index 226985d9f..89b042d12 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -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) -- cgit v1.2.3-54-g00ecf