Skip to content
This repository has been archived by the owner on Dec 13, 2018. It is now read-only.

Commit

Permalink
Updated libcontainer subpackage dependencies. Most subpackages now do…
Browse files Browse the repository at this point in the history
… not depend on their parent ('libcontainer') package. 'namespaces' and 'nsinit' still do.

'namespaces' need to refactored a bit more to move the API part of it to 'libcontainer' package and keep the namespace specific code inside that package.
This change is not expected to break docker.

Docker-DCO-1.1-Signed-off-by: Vishnu Kannan <vishnuk@google.com> (github: vishh)
  • Loading branch information
vishh committed Jun 20, 2014
1 parent 902319a commit b502663
Show file tree
Hide file tree
Showing 21 changed files with 375 additions and 278 deletions.
77 changes: 42 additions & 35 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,54 @@ import (
// Context is a generic key value pair that allows arbatrary data to be sent
type Context map[string]string

type Mount struct {
Type string `json:"type,omitempty"`
Source string `json:"source,omitempty"` // Source path, in the host namespace
Destination string `json:"destination,omitempty"` // Destination path, in the container
Writable bool `json:"writable,omitempty"`
Private bool `json:"private,omitempty"`
}

type Mounts []Mount

type Network struct {
// Type sets the networks type, commonly veth and loopback
Type string `json:"type,omitempty"`

// Context is a generic key value format for setting additional options that are specific to
// the network type
Context Context `json:"context,omitempty"`

// Address contains the IP and mask to set on the network interface
Address string `json:"address,omitempty"`

// Gateway sets the gateway address that is used as the default for the interface
Gateway string `json:"gateway,omitempty"`

// Mtu sets the mtu value for the interface and will be mirrored on both the host and
// container's interfaces if a pair is created, specifically in the case of type veth
Mtu int `json:"mtu,omitempty"`
}

// Container defines configuration options for executing a process inside a contained environment
type Container struct {
// Hostname optionally sets the container's hostname if provided
Hostname string `json:"hostname,omitempty"`
// NoPivotRoot will use MS_MOVE and a chroot to jail the process into the container's rootfs
// This is a common option when the container is running in ramdisk
NoPivotRoot bool `json:"no_pivot_root,omitempty"`

// ReadonlyFs will remount the container's rootfs as readonly where only externally mounted
// bind mounts are writtable
ReadonlyFs bool `json:"readonly_fs,omitempty"`

// NoPivotRoot will use MS_MOVE and a chroot to jail the process into the container's rootfs
// This is a common option when the container is running in ramdisk
NoPivotRoot bool `json:"no_pivot_root,omitempty"`
// Mounts specify additional source and destination paths that will be mounted inside the container's
// rootfs and mount namespace if specified
Mounts Mounts `json:"mounts,omitempty"`

// The device nodes that should be automatically created within the container upon container start. Note, make sure that the node is marked as allowed in the cgroup as well!
DeviceNodes []*devices.Device `json:"device_nodes,omitempty"`

// Hostname optionally sets the container's hostname if provided
Hostname string `json:"hostname,omitempty"`

// User will set the uid and gid of the executing process running inside the container
User string `json:"user,omitempty"`
Expand Down Expand Up @@ -58,37 +94,8 @@ type Container struct {
// on the container's creation
// This is commonly used to specify apparmor profiles, selinux labels, and different restrictions
// placed on the container's processes
// TODO(vishh): Strongtype this.
Context Context `json:"context,omitempty"`

// Mounts specify additional source and destination paths that will be mounted inside the container's
// rootfs and mount namespace if specified
Mounts Mounts `json:"mounts,omitempty"`

// The device nodes that should be automatically created within the container upon container start. Note, make sure that the node is marked as allowed in the cgroup as well!
DeviceNodes []*devices.Device `json:"device_nodes,omitempty"`
}

// Network defines configuration for a container's networking stack
//
// The network configuration can be omited from a container causing the
// container to be setup with the host's networking stack
type Network struct {
// Type sets the networks type, commonly veth and loopback
Type string `json:"type,omitempty"`

// Context is a generic key value format for setting additional options that are specific to
// the network type
Context Context `json:"context,omitempty"`

// Address contains the IP and mask to set on the network interface
Address string `json:"address,omitempty"`

// Gateway sets the gateway address that is used as the default for the interface
Gateway string `json:"gateway,omitempty"`

// Mtu sets the mtu value for the interface and will be mirrored on both the host and
// container's interfaces if a pair is created, specifically in the case of type veth
Mtu int `json:"mtu,omitempty"`
}

// Routes can be specified to create entries in the route table as the container is started
Expand Down
25 changes: 12 additions & 13 deletions mount/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"path/filepath"
"syscall"

"github.com/docker/libcontainer"
"github.com/docker/libcontainer/label"
"github.com/docker/libcontainer/mount/nodes"
"github.com/dotcloud/docker/pkg/symlink"
Expand All @@ -28,12 +27,12 @@ type mount struct {

// InitializeMountNamespace setups up the devices, mount points, and filesystems for use inside a
// new mount namepsace
func InitializeMountNamespace(rootfs, console string, container *libcontainer.Container) error {
func InitializeMountNamespace(rootfs, console string, MountSpec *MountSpec) error {
var (
err error
flag = syscall.MS_PRIVATE
)
if container.NoPivotRoot {
if MountSpec.NoPivotRoot {
flag = syscall.MS_SLAVE
}
if err := system.Mount("", "/", "", uintptr(flag|syscall.MS_REC), ""); err != nil {
Expand All @@ -42,16 +41,16 @@ func InitializeMountNamespace(rootfs, console string, container *libcontainer.Co
if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
return fmt.Errorf("mouting %s as bind %s", rootfs, err)
}
if err := mountSystem(rootfs, container); err != nil {
if err := mountSystem(rootfs, MountSpec); err != nil {
return fmt.Errorf("mount system %s", err)
}
if err := setupBindmounts(rootfs, container.Mounts); err != nil {
if err := setupBindmounts(rootfs, MountSpec.Mounts); err != nil {
return fmt.Errorf("bind mounts %s", err)
}
if err := nodes.CreateDeviceNodes(rootfs, container.DeviceNodes); err != nil {
if err := nodes.CreateDeviceNodes(rootfs, MountSpec.DeviceNodes); err != nil {
return fmt.Errorf("create device nodes %s", err)
}
if err := SetupPtmx(rootfs, console, container.Context["mount_label"]); err != nil {
if err := SetupPtmx(rootfs, console, MountSpec.MountLabel); err != nil {
return err
}
if err := setupDevSymlinks(rootfs); err != nil {
Expand All @@ -61,7 +60,7 @@ func InitializeMountNamespace(rootfs, console string, container *libcontainer.Co
return fmt.Errorf("chdir into %s %s", rootfs, err)
}

if container.NoPivotRoot {
if MountSpec.NoPivotRoot {
err = MsMoveRoot(rootfs)
} else {
err = PivotRoot(rootfs)
Expand All @@ -70,7 +69,7 @@ func InitializeMountNamespace(rootfs, console string, container *libcontainer.Co
return err
}

if container.ReadonlyFs {
if MountSpec.ReadonlyFs {
if err := SetReadonly(); err != nil {
return fmt.Errorf("set readonly %s", err)
}
Expand All @@ -83,8 +82,8 @@ func InitializeMountNamespace(rootfs, console string, container *libcontainer.Co

// mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
// inside the mount namespace
func mountSystem(rootfs string, container *libcontainer.Container) error {
for _, m := range newSystemMounts(rootfs, container.Context["mount_label"], container.Mounts) {
func mountSystem(rootfs string, MountSpec *MountSpec) error {
for _, m := range newSystemMounts(rootfs, MountSpec.MountLabel, MountSpec.Mounts) {
if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
return fmt.Errorf("mkdirall %s %s", m.path, err)
}
Expand Down Expand Up @@ -145,7 +144,7 @@ func setupDevSymlinks(rootfs string) error {
return nil
}

func setupBindmounts(rootfs string, bindMounts libcontainer.Mounts) error {
func setupBindmounts(rootfs string, bindMounts Mounts) error {
for _, m := range bindMounts.OfType("bind") {
var (
flags = syscall.MS_BIND | syscall.MS_REC
Expand Down Expand Up @@ -188,7 +187,7 @@ func setupBindmounts(rootfs string, bindMounts libcontainer.Mounts) error {

// TODO: this is crappy right now and should be cleaned up with a better way of handling system and
// standard bind mounts allowing them to be more dynamic
func newSystemMounts(rootfs, mountLabel string, mounts libcontainer.Mounts) []mount {
func newSystemMounts(rootfs, mountLabel string, mounts Mounts) []mount {
systemMounts := []mount{
{source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaultMountFlags},
{source: "sysfs", path: filepath.Join(rootfs, "sys"), device: "sysfs", flags: defaultMountFlags},
Expand Down
3 changes: 1 addition & 2 deletions mount/nodes/nodes_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
package nodes

import (
"github.com/docker/libcontainer"
"github.com/docker/libcontainer/devices"
)

func CreateDeviceNodes(rootfs string, nodesToCreate []*devices.Device) error {
return libcontainer.ErrUnsupported
return ErrUnsupported
}
47 changes: 47 additions & 0 deletions mount/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package mount

import (
"errors"
"github.com/docker/libcontainer/devices"
)

type MountSpec struct {
// NoPivotRoot will use MS_MOVE and a chroot to jail the process into the container's rootfs
// This is a common option when the container is running in ramdisk
NoPivotRoot bool `json:"no_pivot_root,omitempty"`

// ReadonlyFs will remount the container's rootfs as readonly where only externally mounted
// bind mounts are writtable
ReadonlyFs bool `json:"readonly_fs,omitempty"`

// Mounts specify additional source and destination paths that will be mounted inside the container's
// rootfs and mount namespace if specified
Mounts Mounts `json:"mounts,omitempty"`

// The device nodes that should be automatically created within the container upon container start. Note, make sure that the node is marked as allowed in the cgroup as well!
DeviceNodes []*devices.Device `json:"device_nodes,omitempty"`

MountLabel string
}

type Mount struct {
Type string `json:"type,omitempty"`
Source string `json:"source,omitempty"` // Source path, in the host namespace
Destination string `json:"destination,omitempty"` // Destination path, in the container
Writable bool `json:"writable,omitempty"`
Private bool `json:"private,omitempty"`
}

type Mounts []Mount

var ErrUnsupported = errors.New("Unsupported method")

func (s Mounts) OfType(t string) Mounts {
out := Mounts{}
for _, m := range s {
if m.Type == t {
out = append(out, m)
}
}
return out
}
8 changes: 5 additions & 3 deletions namespaces/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/dotcloud/docker/pkg/system"
)

// TODO(vishh): This is part of the libcontainer API and it does much more than just namespaces related work.
// Move this to libcontainer package.
// Exec performes setup outside of a namespace so that a container can be
// executed. Exec is a high level function for working with container namespaces.
func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
Expand Down Expand Up @@ -149,13 +151,13 @@ func SetupCgroups(container *libcontainer.Container, nspid int) (cgroups.ActiveC
// InitializeNetworking creates the container's network stack outside of the namespace and moves
// interfaces into the container's net namespaces if necessary
func InitializeNetworking(container *libcontainer.Container, nspid int, pipe *SyncPipe) error {
context := libcontainer.Context{}
context := map[string]string{}
for _, config := range container.Networks {
strategy, err := network.GetStrategy(config.Type)
if err != nil {
return err
}
if err := strategy.Create(config, nspid, context); err != nil {
if err := strategy.Create(libcontainer.GetInternalNetworkSpec(config), nspid, context); err != nil {
return err
}
}
Expand All @@ -167,7 +169,7 @@ func InitializeNetworking(container *libcontainer.Container, nspid int, pipe *Sy
func GetNamespaceFlags(namespaces map[string]bool) (flag int) {
for key, enabled := range namespaces {
if enabled {
if ns := libcontainer.GetNamespace(key); ns != nil {
if ns := GetNamespace(key); ns != nil {
flag |= ns.Value
}
}
Expand Down
12 changes: 7 additions & 5 deletions namespaces/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"github.com/dotcloud/docker/pkg/user"
)

// TODO(vishh): This is part of the libcontainer API and it does much more than just namespaces related work.
// Move this to libcontainer package.
// Init is the init process that first runs inside a new namespace to setup mounts, users, networking,
// and other options required for the new container.
func Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error {
Expand Down Expand Up @@ -67,7 +69,7 @@ func Init(container *libcontainer.Container, uncleanRootfs, consolePath string,

label.Init()

if err := mount.InitializeMountNamespace(rootfs, consolePath, container); err != nil {
if err := mount.InitializeMountNamespace(rootfs, consolePath, libcontainer.GetInternalMountSpec(container)); err != nil {
return fmt.Errorf("setup mount namespace %s", err)
}
if container.Hostname != "" {
Expand Down Expand Up @@ -157,14 +159,14 @@ func SetupUser(u string) error {
// setupVethNetwork uses the Network config if it is not nil to initialize
// the new veth interface inside the container for use by changing the name to eth0
// setting the MTU and IP address along with the default gateway
func setupNetwork(container *libcontainer.Container, context libcontainer.Context) error {
func setupNetwork(container *libcontainer.Container, context map[string]string) error {
for _, config := range container.Networks {
strategy, err := network.GetStrategy(config.Type)
if err != nil {
return err
}

err1 := strategy.Initialize(config, context)
err1 := strategy.Initialize(libcontainer.GetInternalNetworkSpec(config), context)
if err1 != nil {
return err1
}
Expand Down Expand Up @@ -193,7 +195,7 @@ func FinalizeNamespace(container *libcontainer.Container) error {
}

// drop capabilities in bounding set before changing user
if err := capabilities.DropBoundingSet(container); err != nil {
if err := capabilities.DropBoundingSet(&container.Capabilities); err != nil {
return fmt.Errorf("drop bounding set %s", err)
}

Expand All @@ -211,7 +213,7 @@ func FinalizeNamespace(container *libcontainer.Container) error {
}

// drop all other capabilities
if err := capabilities.DropCapabilities(container); err != nil {
if err := capabilities.DropCapabilities(&container.Capabilities); err != nil {
return fmt.Errorf("drop capabilities %s", err)
}

Expand Down
8 changes: 3 additions & 5 deletions namespaces/sync_pipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"fmt"
"io/ioutil"
"os"

"github.com/docker/libcontainer"
)

// SyncPipe allows communication to and from the child processes
Expand Down Expand Up @@ -45,7 +43,7 @@ func (s *SyncPipe) Parent() *os.File {
return s.parent
}

func (s *SyncPipe) SendToChild(context libcontainer.Context) error {
func (s *SyncPipe) SendToChild(context map[string]string) error {
data, err := json.Marshal(context)
if err != nil {
return err
Expand All @@ -54,12 +52,12 @@ func (s *SyncPipe) SendToChild(context libcontainer.Context) error {
return nil
}

func (s *SyncPipe) ReadFromParent() (libcontainer.Context, error) {
func (s *SyncPipe) ReadFromParent() (map[string]string, error) {
data, err := ioutil.ReadAll(s.child)
if err != nil {
return nil, fmt.Errorf("error reading from sync pipe %s", err)
}
var context libcontainer.Context
var context map[string]string
if len(data) > 0 {
if err := json.Unmarshal(data, &context); err != nil {
return nil, err
Expand Down
Loading

0 comments on commit b502663

Please sign in to comment.