Update libcontainer to 5210a236b92a8022a673108f347
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@docker.com> (github: crosbymichael)
This commit is contained in:
parent
e23e3a1600
commit
423a8f91d7
|
@ -61,4 +61,4 @@ mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
|
|||
|
||||
clone git github.com/godbus/dbus v1
|
||||
clone git github.com/coreos/go-systemd v2
|
||||
clone git github.com/docker/libcontainer v1.0.1
|
||||
clone git github.com/docker/libcontainer 5210a236b92a8022a673108f3471fed0a046bd05
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
## libcontainer - reference implementation for containers
|
||||
|
||||
### Note on API changes:
|
||||
|
||||
Please bear with us while we work on making the libcontainer API stable and something that we can support long term. We are currently discussing the API with the community, therefore, if you currently depend on libcontainer please pin your dependency at a specific tag or commit id. Please join the discussion and help shape the API.
|
||||
|
||||
#### Background
|
||||
|
||||
libcontainer specifies configuration options for what a container is. It provides a native Go implementation
|
||||
|
@ -13,7 +17,7 @@ a `container.json` file is placed with the runtime configuration for how the pro
|
|||
should be contained and run. Environment, networking, and different capabilities for the
|
||||
process are specified in this file. The configuration is used for each process executed inside the container.
|
||||
|
||||
See the `container.json` file for what the configuration should look like.
|
||||
See the `sample_configs` folder for examples of what the container configuration should look like.
|
||||
|
||||
Using this configuration and the current directory holding the rootfs for a process, one can use libcontainer to exec the container. Running the life of the namespace, a `pid` file
|
||||
is written to the current directory with the pid of the namespaced process to the external world. A client can use this pid to wait, kill, or perform other operation with the container. If a user tries to run a new process inside an existing container with a live namespace, the namespace will be joined by the new process.
|
||||
|
|
|
@ -57,12 +57,13 @@ func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) {
|
|||
|
||||
d, err := getCgroupData(c, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("getting CgroupData %s", err)
|
||||
}
|
||||
|
||||
for _, sys := range subsystems {
|
||||
if err := sys.GetStats(d, stats); err != nil {
|
||||
return nil, err
|
||||
for sysName, sys := range subsystems {
|
||||
// Don't fail if a cgroup hierarchy was not found.
|
||||
if err := sys.GetStats(d, stats); err != nil && err != cgroups.ErrNotFound {
|
||||
return nil, fmt.Errorf("getting stats for system %q %s", sysName, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,25 +2,22 @@ package libcontainer
|
|||
|
||||
import (
|
||||
"github.com/docker/libcontainer/cgroups"
|
||||
"github.com/docker/libcontainer/devices"
|
||||
"github.com/docker/libcontainer/mount"
|
||||
"github.com/docker/libcontainer/network"
|
||||
)
|
||||
|
||||
// Context is a generic key value pair that allows arbatrary data to be sent
|
||||
type Context map[string]string
|
||||
type MountConfig mount.MountConfig
|
||||
|
||||
type Network network.Network
|
||||
|
||||
// Config defines configuration options for executing a process inside a contained environment.
|
||||
type Config struct {
|
||||
// Mount specific options.
|
||||
MountConfig *MountConfig `json:"mount_config,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"`
|
||||
|
||||
// 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"`
|
||||
|
||||
// User will set the uid and gid of the executing process running inside the container
|
||||
User string `json:"user,omitempty"`
|
||||
|
||||
|
@ -58,37 +55,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
|
||||
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"`
|
||||
// TODO(vishh): Avoid overloading this field with params for different subsystems. Strongtype this.
|
||||
Context map[string]string `json:"context,omitempty"`
|
||||
}
|
||||
|
||||
// Routes can be specified to create entries in the route table as the container is started
|
||||
|
|
|
@ -4,6 +4,8 @@ import (
|
|||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libcontainer/devices"
|
||||
)
|
||||
|
||||
// Checks whether the expected capability is specified in the capabilities.
|
||||
|
@ -16,14 +18,28 @@ func contains(expected string, values []string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func TestContainerJsonFormat(t *testing.T) {
|
||||
f, err := os.Open("container.json")
|
||||
func containsDevice(expected *devices.Device, values []*devices.Device) bool {
|
||||
for _, d := range values {
|
||||
if d.Path == expected.Path &&
|
||||
d.CgroupPermissions == expected.CgroupPermissions &&
|
||||
d.FileMode == expected.FileMode &&
|
||||
d.MajorNumber == expected.MajorNumber &&
|
||||
d.MinorNumber == expected.MinorNumber &&
|
||||
d.Type == expected.Type {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestConfigJsonFormat(t *testing.T) {
|
||||
f, err := os.Open("sample_configs/attach_to_bridge.json")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to open container.json")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var container *Container
|
||||
var container *Config
|
||||
if err := json.NewDecoder(f).Decode(&container); err != nil {
|
||||
t.Fatalf("failed to decode container config: %s", err)
|
||||
}
|
||||
|
@ -61,4 +77,42 @@ func TestContainerJsonFormat(t *testing.T) {
|
|||
t.Log("capabilities mask should contain SYS_CHROOT")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
for _, n := range container.Networks {
|
||||
if n.Type == "veth" {
|
||||
if n.Bridge != "docker0" {
|
||||
t.Logf("veth bridge should be docker0 but received %q", n.Bridge)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if n.Address != "172.17.0.101/16" {
|
||||
t.Logf("veth address should be 172.17.0.101/61 but received %q", n.Address)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if n.VethPrefix != "veth" {
|
||||
t.Logf("veth prefix should be veth but received %q", n.VethPrefix)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if n.Gateway != "172.17.42.1" {
|
||||
t.Logf("veth gateway should be 172.17.42.1 but received %q", n.Gateway)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if n.Mtu != 1500 {
|
||||
t.Logf("veth mtu should be 1500 but received %d", n.Mtu)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, d := range devices.DefaultSimpleDevices {
|
||||
if !containsDevice(d, container.MountConfig.DeviceNodes) {
|
||||
t.Logf("expected defice configuration for %s", d.Path)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
@ -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, mountConfig *MountConfig) error {
|
||||
var (
|
||||
err error
|
||||
flag = syscall.MS_PRIVATE
|
||||
)
|
||||
if container.NoPivotRoot {
|
||||
if mountConfig.NoPivotRoot {
|
||||
flag = syscall.MS_SLAVE
|
||||
}
|
||||
if err := system.Mount("", "/", "", uintptr(flag|syscall.MS_REC), ""); err != nil {
|
||||
|
@ -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, mountConfig); err != nil {
|
||||
return fmt.Errorf("mount system %s", err)
|
||||
}
|
||||
if err := setupBindmounts(rootfs, container.Mounts); err != nil {
|
||||
if err := setupBindmounts(rootfs, mountConfig.Mounts); err != nil {
|
||||
return fmt.Errorf("bind mounts %s", err)
|
||||
}
|
||||
if err := nodes.CreateDeviceNodes(rootfs, container.DeviceNodes); err != nil {
|
||||
if err := nodes.CreateDeviceNodes(rootfs, mountConfig.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, mountConfig.MountLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setupDevSymlinks(rootfs); err != nil {
|
||||
|
@ -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 mountConfig.NoPivotRoot {
|
||||
err = MsMoveRoot(rootfs)
|
||||
} else {
|
||||
err = PivotRoot(rootfs)
|
||||
|
@ -70,7 +69,7 @@ func InitializeMountNamespace(rootfs, console string, container *libcontainer.Co
|
|||
return err
|
||||
}
|
||||
|
||||
if container.ReadonlyFs {
|
||||
if mountConfig.ReadonlyFs {
|
||||
if err := SetReadonly(); err != nil {
|
||||
return fmt.Errorf("set readonly %s", err)
|
||||
}
|
||||
|
@ -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, mountConfig *MountConfig) error {
|
||||
for _, m := range newSystemMounts(rootfs, mountConfig.MountLabel, mountConfig.Mounts) {
|
||||
if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
|
||||
return fmt.Errorf("mkdirall %s %s", m.path, err)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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},
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/docker/libcontainer"
|
||||
"errors"
|
||||
|
||||
"github.com/docker/libcontainer/devices"
|
||||
)
|
||||
|
||||
func CreateDeviceNodes(rootfs string, nodesToCreate []*devices.Device) error {
|
||||
return libcontainer.ErrUnsupported
|
||||
return errors.New("Unsupported method")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package mount
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/docker/libcontainer/devices"
|
||||
)
|
||||
|
||||
type MountConfig 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 `json:"mount_label,omitempty"`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
|
@ -7,4 +7,4 @@ import (
|
|||
"github.com/docker/libcontainer"
|
||||
)
|
||||
|
||||
type CreateCommand func(container *libcontainer.Container, console, rootfs, dataPath, init string, childPipe *os.File, args []string) *exec.Cmd
|
||||
type CreateCommand func(container *libcontainer.Config, console, rootfs, dataPath, init string, childPipe *os.File, args []string) *exec.Cmd
|
||||
|
|
|
@ -15,9 +15,11 @@ 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) {
|
||||
func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
|
||||
var (
|
||||
master *os.File
|
||||
console string
|
||||
|
@ -103,7 +105,7 @@ func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath str
|
|||
// root: the path to the container json file and information
|
||||
// pipe: sync pipe to syncronize the parent and child processes
|
||||
// args: the arguemnts to pass to the container to run as the user's program
|
||||
func DefaultCreateCommand(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
|
||||
func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
|
||||
// get our binary name from arg0 so we can always reexec ourself
|
||||
env := []string{
|
||||
"console=" + console,
|
||||
|
@ -135,7 +137,7 @@ func DefaultCreateCommand(container *libcontainer.Container, console, rootfs, da
|
|||
|
||||
// SetupCgroups applies the cgroup restrictions to the process running in the contaienr based
|
||||
// on the container's configuration
|
||||
func SetupCgroups(container *libcontainer.Container, nspid int) (cgroups.ActiveCgroup, error) {
|
||||
func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgroup, error) {
|
||||
if container.Cgroups != nil {
|
||||
c := container.Cgroups
|
||||
if systemd.UseSystemd() {
|
||||
|
@ -148,14 +150,14 @@ 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{}
|
||||
func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *SyncPipe) error {
|
||||
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((*network.Network)(config), nspid, context); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
// ExecIn uses an existing pid and joins the pid's namespaces with the new command.
|
||||
func ExecIn(container *libcontainer.Container, nspid int, args []string) error {
|
||||
func ExecIn(container *libcontainer.Config, nspid int, args []string) error {
|
||||
// TODO(vmarmol): If this gets too long, send it over a pipe to the child.
|
||||
// Marshall the container into JSON since it won't be available in the namespace.
|
||||
containerJson, err := json.Marshal(container)
|
||||
|
@ -31,7 +31,7 @@ func ExecIn(container *libcontainer.Container, nspid int, args []string) error {
|
|||
}
|
||||
|
||||
// NsEnter is run after entering the namespace.
|
||||
func NsEnter(container *libcontainer.Container, nspid int, args []string) error {
|
||||
func NsEnter(container *libcontainer.Config, nspid int, args []string) error {
|
||||
// clear the current processes env and replace it with the environment
|
||||
// defined on the container
|
||||
if err := LoadContainerEnvironment(container); err != nil {
|
||||
|
|
|
@ -23,9 +23,11 @@ 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 {
|
||||
func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error {
|
||||
rootfs, err := utils.ResolveRootfs(uncleanRootfs)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -67,7 +69,9 @@ 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,
|
||||
(*mount.MountConfig)(container.MountConfig)); err != nil {
|
||||
return fmt.Errorf("setup mount namespace %s", err)
|
||||
}
|
||||
if container.Hostname != "" {
|
||||
|
@ -157,14 +161,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.Config, 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((*network.Network)(config), context)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
|
@ -172,7 +176,7 @@ func setupNetwork(container *libcontainer.Container, context libcontainer.Contex
|
|||
return nil
|
||||
}
|
||||
|
||||
func setupRoute(container *libcontainer.Container) error {
|
||||
func setupRoute(container *libcontainer.Config) error {
|
||||
for _, config := range container.Routes {
|
||||
if err := netlink.AddRoute(config.Destination, config.Source, config.Gateway, config.InterfaceName); err != nil {
|
||||
return err
|
||||
|
@ -184,7 +188,7 @@ func setupRoute(container *libcontainer.Container) error {
|
|||
// FinalizeNamespace drops the caps, sets the correct user
|
||||
// and working dir, and closes any leaky file descriptors
|
||||
// before execing the command inside the namespace
|
||||
func FinalizeNamespace(container *libcontainer.Container) error {
|
||||
func FinalizeNamespace(container *libcontainer.Config) error {
|
||||
// Ensure that all non-standard fds we may have accidentally
|
||||
// inherited are marked close-on-exec so they stay out of the
|
||||
// container
|
||||
|
@ -193,7 +197,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)
|
||||
}
|
||||
|
||||
|
@ -211,7 +215,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)
|
||||
}
|
||||
|
||||
|
@ -224,7 +228,7 @@ func FinalizeNamespace(container *libcontainer.Container) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func LoadContainerEnvironment(container *libcontainer.Container) error {
|
||||
func LoadContainerEnvironment(container *libcontainer.Config) error {
|
||||
os.Clearenv()
|
||||
for _, pair := range container.Env {
|
||||
p := strings.SplitN(pair, "=", 2)
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
)
|
||||
|
||||
// SyncPipe allows communication to and from the child processes
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package namespaces
|
||||
|
||||
import "errors"
|
||||
|
||||
type (
|
||||
Namespace struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Value int `json:"value,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
}
|
||||
Namespaces []*Namespace
|
||||
)
|
||||
|
||||
// namespaceList is used to convert the libcontainer types
|
||||
// into the names of the files located in /proc/<pid>/ns/* for
|
||||
// each namespace
|
||||
var (
|
||||
namespaceList = Namespaces{}
|
||||
ErrUnkownNamespace = errors.New("Unknown namespace")
|
||||
ErrUnsupported = errors.New("Unsupported method")
|
||||
)
|
||||
|
||||
func (ns *Namespace) String() string {
|
||||
return ns.Key
|
||||
}
|
||||
|
||||
func GetNamespace(key string) *Namespace {
|
||||
for _, ns := range namespaceList {
|
||||
if ns.Key == key {
|
||||
cpy := *ns
|
||||
return &cpy
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Contains returns true if the specified Namespace is
|
||||
// in the slice
|
||||
func (n Namespaces) Contains(ns string) bool {
|
||||
return n.Get(ns) != nil
|
||||
}
|
||||
|
||||
func (n Namespaces) Get(ns string) *Namespace {
|
||||
for _, nsp := range n {
|
||||
if nsp != nil && nsp.Key == ns {
|
||||
return nsp
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package libcontainer
|
||||
package namespaces
|
||||
|
||||
import (
|
||||
"syscall"
|
|
@ -1,4 +1,4 @@
|
|||
package libcontainer
|
||||
package namespaces
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@ -28,17 +28,3 @@ func TestNamespacesContains(t *testing.T) {
|
|||
t.Fatal("namespaces should contain NEWPID but does not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCapabilitiesContains(t *testing.T) {
|
||||
caps := Capabilities{
|
||||
GetCapability("MKNOD"),
|
||||
GetCapability("SETPCAP"),
|
||||
}
|
||||
|
||||
if caps.Contains("SYS_ADMIN") {
|
||||
t.Fatal("capabilities should not contain SYS_ADMIN")
|
||||
}
|
||||
if !caps.Contains("MKNOD") {
|
||||
t.Fatal("capabilities should contain MKNOD but does not")
|
||||
}
|
||||
}
|
|
@ -7,20 +7,20 @@ import (
|
|||
"github.com/docker/libcontainer/cgroups"
|
||||
)
|
||||
|
||||
func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
|
||||
return -1, libcontainer.ErrUnsupported
|
||||
func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
|
||||
return -1, ErrUnsupported
|
||||
}
|
||||
|
||||
func Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error {
|
||||
return libcontainer.ErrUnsupported
|
||||
func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error {
|
||||
return ErrUnsupported
|
||||
}
|
||||
|
||||
func InitializeNetworking(container *libcontainer.Container, nspid int, pipe *SyncPipe) error {
|
||||
return libcontainer.ErrUnsupported
|
||||
func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *SyncPipe) error {
|
||||
return ErrUnsupported
|
||||
}
|
||||
|
||||
func SetupCgroups(container *libcontainer.Container, nspid int) (cgroups.ActiveCgroup, error) {
|
||||
return nil, libcontainer.ErrUnsupported
|
||||
func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgroup, error) {
|
||||
return nil, ErrUnsupported
|
||||
}
|
||||
|
||||
func GetNamespaceFlags(namespaces map[string]bool) (flag int) {
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
// +build linux
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/docker/libcontainer"
|
||||
)
|
||||
|
||||
// Loopback is a network strategy that provides a basic loopback device
|
||||
type Loopback struct {
|
||||
}
|
||||
|
||||
func (l *Loopback) Create(n *libcontainer.Network, nspid int, context libcontainer.Context) error {
|
||||
func (l *Loopback) Create(n *Network, nspid int, context map[string]string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Loopback) Initialize(config *libcontainer.Network, context libcontainer.Context) error {
|
||||
func (l *Loopback) Initialize(config *Network, context map[string]string) error {
|
||||
if err := SetMtu("lo", config.Mtu); err != nil {
|
||||
return fmt.Errorf("set lo mtu to %d %s", config.Mtu, err)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build linux
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
|
@ -5,7 +7,6 @@ import (
|
|||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/dotcloud/docker/pkg/system"
|
||||
)
|
||||
|
||||
|
@ -13,12 +14,12 @@ import (
|
|||
type NetNS struct {
|
||||
}
|
||||
|
||||
func (v *NetNS) Create(n *libcontainer.Network, nspid int, context libcontainer.Context) error {
|
||||
context["nspath"] = n.Context["nspath"]
|
||||
func (v *NetNS) Create(n *Network, nspid int, context map[string]string) error {
|
||||
context["nspath"] = n.NsPath
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *NetNS) Initialize(config *libcontainer.Network, context libcontainer.Context) error {
|
||||
func (v *NetNS) Initialize(config *Network, context map[string]string) error {
|
||||
nspath, exists := context["nspath"]
|
||||
if !exists {
|
||||
return fmt.Errorf("nspath does not exist in network context")
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
// +build linux
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
)
|
||||
|
||||
func InterfaceUp(name string) error {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// +build linux
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -19,8 +19,8 @@ var strategies = map[string]NetworkStrategy{
|
|||
// NetworkStrategy represents a specific network configuration for
|
||||
// a container's networking stack
|
||||
type NetworkStrategy interface {
|
||||
Create(*libcontainer.Network, int, libcontainer.Context) error
|
||||
Initialize(*libcontainer.Network, libcontainer.Context) error
|
||||
Create(*Network, int, map[string]string) error
|
||||
Initialize(*Network, map[string]string) error
|
||||
}
|
||||
|
||||
// GetStrategy returns the specific network strategy for the
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package network
|
||||
|
||||
// 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"`
|
||||
|
||||
// Path to network namespace
|
||||
NsPath string `json:"ns_path,omitempty"`
|
||||
|
||||
// The bridge to use.
|
||||
Bridge string `json:"bridge,omitempty"`
|
||||
|
||||
// Prefix for the veth interfaces.
|
||||
VethPrefix string `json:"veth_prefix,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"`
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
// +build linux
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/docker/libcontainer"
|
||||
|
||||
"github.com/docker/libcontainer/utils"
|
||||
)
|
||||
|
||||
|
@ -14,17 +16,16 @@ type Veth struct {
|
|||
|
||||
const defaultDevice = "eth0"
|
||||
|
||||
func (v *Veth) Create(n *libcontainer.Network, nspid int, context libcontainer.Context) error {
|
||||
func (v *Veth) Create(n *Network, nspid int, context map[string]string) error {
|
||||
var (
|
||||
bridge string
|
||||
prefix string
|
||||
exists bool
|
||||
bridge = n.Bridge
|
||||
prefix = n.VethPrefix
|
||||
)
|
||||
if bridge, exists = n.Context["bridge"]; !exists {
|
||||
return fmt.Errorf("bridge does not exist in network context")
|
||||
if bridge == "" {
|
||||
return fmt.Errorf("bridge is not specified")
|
||||
}
|
||||
if prefix, exists = n.Context["prefix"]; !exists {
|
||||
return fmt.Errorf("veth prefix does not exist in network context")
|
||||
if prefix == "" {
|
||||
return fmt.Errorf("veth prefix is not specified")
|
||||
}
|
||||
name1, name2, err := createVethPair(prefix)
|
||||
if err != nil {
|
||||
|
@ -47,7 +48,7 @@ func (v *Veth) Create(n *libcontainer.Network, nspid int, context libcontainer.C
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *Veth) Initialize(config *libcontainer.Network, context libcontainer.Context) error {
|
||||
func (v *Veth) Initialize(config *Network, context map[string]string) error {
|
||||
var (
|
||||
vethChild string
|
||||
exists bool
|
||||
|
|
|
@ -48,7 +48,7 @@ func execAction(context *cli.Context) {
|
|||
// error.
|
||||
//
|
||||
// Signals sent to the current process will be forwarded to container.
|
||||
func startContainer(container *libcontainer.Container, term namespaces.Terminal, dataPath string, args []string) (int, error) {
|
||||
func startContainer(container *libcontainer.Config, term namespaces.Terminal, dataPath string, args []string) (int, error) {
|
||||
var (
|
||||
cmd *exec.Cmd
|
||||
sigc = make(chan os.Signal, 10)
|
||||
|
@ -56,7 +56,7 @@ func startContainer(container *libcontainer.Container, term namespaces.Terminal,
|
|||
|
||||
signal.Notify(sigc)
|
||||
|
||||
createCommand := func(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
|
||||
createCommand := func(container *libcontainer.Config, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
|
||||
cmd = namespaces.DefaultCreateCommand(container, console, rootfs, dataPath, init, pipe, args)
|
||||
if logPath != "" {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("log=%s", logPath))
|
||||
|
|
|
@ -30,7 +30,7 @@ func specAction(context *cli.Context) {
|
|||
}
|
||||
|
||||
// returns the container spec in json format.
|
||||
func getContainerSpec(container *libcontainer.Container) (string, error) {
|
||||
func getContainerSpec(container *libcontainer.Config) (string, error) {
|
||||
spec, err := json.MarshalIndent(container, "", "\t")
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -31,7 +31,7 @@ func statsAction(context *cli.Context) {
|
|||
}
|
||||
|
||||
// returns the container stats in json format.
|
||||
func getContainerStats(container *libcontainer.Container) (string, error) {
|
||||
func getContainerStats(container *libcontainer.Config) (string, error) {
|
||||
stats, err := fs.GetStats(container.Cgroups)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -11,14 +11,14 @@ import (
|
|||
"github.com/docker/libcontainer"
|
||||
)
|
||||
|
||||
func loadContainer() (*libcontainer.Container, error) {
|
||||
func loadContainer() (*libcontainer.Config, error) {
|
||||
f, err := os.Open(filepath.Join(dataPath, "container.json"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var container *libcontainer.Container
|
||||
var container *libcontainer.Config
|
||||
if err := json.NewDecoder(f).Decode(&container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ func openLog(name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func loadContainerFromJson(rawData string) (*libcontainer.Container, error) {
|
||||
var container *libcontainer.Container
|
||||
func loadContainerFromJson(rawData string) (*libcontainer.Config, error) {
|
||||
var container *libcontainer.Config
|
||||
|
||||
if err := json.Unmarshal([]byte(rawData), &container); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
These configuration files can be used with `nsinit` to quickly develop, test,
|
||||
and experiment with features of libcontainer.
|
||||
|
||||
When consuming these configuration files, copy them into your rootfs and rename
|
||||
the file to `container.json` for use with `nsinit`.
|
|
@ -121,14 +121,8 @@
|
|||
"process_label": "",
|
||||
"restrictions": "true"
|
||||
},
|
||||
"mount_config": {
|
||||
"device_nodes": [
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"major_number": 10,
|
||||
"minor_number": 229,
|
||||
"path": "/dev/fuse",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
|
@ -176,11 +170,12 @@
|
|||
"path": "/dev/random",
|
||||
"type": 99
|
||||
}
|
||||
],
|
||||
]
|
||||
},
|
||||
"environment": [
|
||||
"HOME=/",
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"HOSTNAME=2d388ea3bd92",
|
||||
"HOSTNAME=koye",
|
||||
"TERM=xterm"
|
||||
],
|
||||
"hostname": "koye",
|
||||
|
@ -200,10 +195,8 @@
|
|||
},
|
||||
{
|
||||
"address": "172.17.0.101/16",
|
||||
"context": {
|
||||
"bridge": "docker0",
|
||||
"prefix": "veth"
|
||||
},
|
||||
"veth_prefix": "veth",
|
||||
"gateway": "172.17.42.1",
|
||||
"mtu": 1500,
|
||||
"type": "veth"
|
|
@ -0,0 +1,199 @@
|
|||
{
|
||||
"capabilities": [
|
||||
"CHOWN",
|
||||
"DAC_OVERRIDE",
|
||||
"FOWNER",
|
||||
"MKNOD",
|
||||
"NET_RAW",
|
||||
"SETGID",
|
||||
"SETUID",
|
||||
"SETFCAP",
|
||||
"SETPCAP",
|
||||
"NET_BIND_SERVICE",
|
||||
"SYS_CHROOT",
|
||||
"KILL"
|
||||
],
|
||||
"cgroups": {
|
||||
"allowed_devices": [
|
||||
{
|
||||
"cgroup_permissions": "m",
|
||||
"major_number": -1,
|
||||
"minor_number": -1,
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "m",
|
||||
"major_number": -1,
|
||||
"minor_number": -1,
|
||||
"type": 98
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"major_number": 5,
|
||||
"minor_number": 1,
|
||||
"path": "/dev/console",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"major_number": 4,
|
||||
"path": "/dev/tty0",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"major_number": 4,
|
||||
"minor_number": 1,
|
||||
"path": "/dev/tty1",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"major_number": 136,
|
||||
"minor_number": -1,
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"major_number": 5,
|
||||
"minor_number": 2,
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"major_number": 10,
|
||||
"minor_number": 200,
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 3,
|
||||
"path": "/dev/null",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 5,
|
||||
"path": "/dev/zero",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 7,
|
||||
"path": "/dev/full",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 5,
|
||||
"path": "/dev/tty",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 9,
|
||||
"path": "/dev/urandom",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 8,
|
||||
"path": "/dev/random",
|
||||
"type": 99
|
||||
}
|
||||
],
|
||||
"name": "docker-koye",
|
||||
"parent": "docker"
|
||||
},
|
||||
"context": {
|
||||
"mount_label": "",
|
||||
"process_label": "",
|
||||
"restrictions": "true"
|
||||
},
|
||||
"mount_config": {
|
||||
"device_nodes": [
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 3,
|
||||
"path": "/dev/null",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 5,
|
||||
"path": "/dev/zero",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 7,
|
||||
"path": "/dev/full",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 5,
|
||||
"path": "/dev/tty",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 9,
|
||||
"path": "/dev/urandom",
|
||||
"type": 99
|
||||
},
|
||||
{
|
||||
"cgroup_permissions": "rwm",
|
||||
"file_mode": 438,
|
||||
"major_number": 1,
|
||||
"minor_number": 8,
|
||||
"path": "/dev/random",
|
||||
"type": 99
|
||||
}
|
||||
]
|
||||
},
|
||||
"environment": [
|
||||
"HOME=/",
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"HOSTNAME=koye",
|
||||
"TERM=xterm"
|
||||
],
|
||||
"hostname": "koye",
|
||||
"namespaces": {
|
||||
"NEWIPC": true,
|
||||
"NEWNET": true,
|
||||
"NEWNS": true,
|
||||
"NEWPID": true,
|
||||
"NEWUTS": true
|
||||
},
|
||||
"networks": [
|
||||
{
|
||||
"address": "127.0.0.1/0",
|
||||
"gateway": "localhost",
|
||||
"mtu": 1500,
|
||||
"type": "loopback"
|
||||
}
|
||||
],
|
||||
"tty": true,
|
||||
"user": "daemon"
|
||||
}
|
|
@ -3,7 +3,6 @@ package capabilities
|
|||
import (
|
||||
"os"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
)
|
||||
|
||||
|
@ -11,13 +10,13 @@ const allCapabilityTypes = capability.CAPS | capability.BOUNDS
|
|||
|
||||
// DropBoundingSet drops the capability bounding set to those specified in the
|
||||
// container configuration.
|
||||
func DropBoundingSet(container *libcontainer.Container) error {
|
||||
func DropBoundingSet(capabilities []string) error {
|
||||
c, err := capability.NewPid(os.Getpid())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keep := getEnabledCapabilities(container)
|
||||
keep := getEnabledCapabilities(capabilities)
|
||||
c.Clear(capability.BOUNDS)
|
||||
c.Set(capability.BOUNDS, keep...)
|
||||
|
||||
|
@ -29,13 +28,13 @@ func DropBoundingSet(container *libcontainer.Container) error {
|
|||
}
|
||||
|
||||
// DropCapabilities drops all capabilities for the current process expect those specified in the container configuration.
|
||||
func DropCapabilities(container *libcontainer.Container) error {
|
||||
func DropCapabilities(capList []string) error {
|
||||
c, err := capability.NewPid(os.Getpid())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keep := getEnabledCapabilities(container)
|
||||
keep := getEnabledCapabilities(capList)
|
||||
c.Clear(allCapabilityTypes)
|
||||
c.Set(allCapabilityTypes, keep...)
|
||||
|
||||
|
@ -46,10 +45,10 @@ func DropCapabilities(container *libcontainer.Container) error {
|
|||
}
|
||||
|
||||
// getEnabledCapabilities returns the capabilities that should not be dropped by the container.
|
||||
func getEnabledCapabilities(container *libcontainer.Container) []capability.Cap {
|
||||
func getEnabledCapabilities(capList []string) []capability.Cap {
|
||||
keep := []capability.Cap{}
|
||||
for _, capability := range container.Capabilities {
|
||||
if c := libcontainer.GetCapability(capability); c != nil {
|
||||
for _, capability := range capList {
|
||||
if c := GetCapability(capability); c != nil {
|
||||
keep = append(keep, c.Value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package capabilities
|
||||
|
||||
import "github.com/syndtr/gocapability/capability"
|
||||
|
||||
type (
|
||||
CapabilityMapping struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Value capability.Cap `json:"value,omitempty"`
|
||||
}
|
||||
Capabilities []*CapabilityMapping
|
||||
)
|
||||
|
||||
func (c *CapabilityMapping) String() string {
|
||||
return c.Key
|
||||
}
|
||||
|
||||
func GetCapability(key string) *CapabilityMapping {
|
||||
for _, capp := range capabilityList {
|
||||
if capp.Key == key {
|
||||
cpy := *capp
|
||||
return &cpy
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAllCapabilities() []string {
|
||||
output := make([]string, len(capabilityList))
|
||||
for i, capability := range capabilityList {
|
||||
output[i] = capability.String()
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// Contains returns true if the specified Capability is
|
||||
// in the slice
|
||||
func (c Capabilities) contains(capp string) bool {
|
||||
return c.get(capp) != nil
|
||||
}
|
||||
|
||||
func (c Capabilities) get(capp string) *CapabilityMapping {
|
||||
for _, cap := range c {
|
||||
if cap.Key == capp {
|
||||
return cap
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var capabilityList = Capabilities{
|
||||
{Key: "SETPCAP", Value: capability.CAP_SETPCAP},
|
||||
{Key: "SYS_MODULE", Value: capability.CAP_SYS_MODULE},
|
||||
{Key: "SYS_RAWIO", Value: capability.CAP_SYS_RAWIO},
|
||||
{Key: "SYS_PACCT", Value: capability.CAP_SYS_PACCT},
|
||||
{Key: "SYS_ADMIN", Value: capability.CAP_SYS_ADMIN},
|
||||
{Key: "SYS_NICE", Value: capability.CAP_SYS_NICE},
|
||||
{Key: "SYS_RESOURCE", Value: capability.CAP_SYS_RESOURCE},
|
||||
{Key: "SYS_TIME", Value: capability.CAP_SYS_TIME},
|
||||
{Key: "SYS_TTY_CONFIG", Value: capability.CAP_SYS_TTY_CONFIG},
|
||||
{Key: "MKNOD", Value: capability.CAP_MKNOD},
|
||||
{Key: "AUDIT_WRITE", Value: capability.CAP_AUDIT_WRITE},
|
||||
{Key: "AUDIT_CONTROL", Value: capability.CAP_AUDIT_CONTROL},
|
||||
{Key: "MAC_OVERRIDE", Value: capability.CAP_MAC_OVERRIDE},
|
||||
{Key: "MAC_ADMIN", Value: capability.CAP_MAC_ADMIN},
|
||||
{Key: "NET_ADMIN", Value: capability.CAP_NET_ADMIN},
|
||||
{Key: "SYSLOG", Value: capability.CAP_SYSLOG},
|
||||
{Key: "SETUID", Value: capability.CAP_SETUID},
|
||||
{Key: "SETGID", Value: capability.CAP_SETGID},
|
||||
{Key: "CHOWN", Value: capability.CAP_CHOWN},
|
||||
{Key: "NET_RAW", Value: capability.CAP_NET_RAW},
|
||||
{Key: "DAC_OVERRIDE", Value: capability.CAP_DAC_OVERRIDE},
|
||||
{Key: "FOWNER", Value: capability.CAP_FOWNER},
|
||||
{Key: "DAC_READ_SEARCH", Value: capability.CAP_DAC_READ_SEARCH},
|
||||
{Key: "FSETID", Value: capability.CAP_FSETID},
|
||||
{Key: "KILL", Value: capability.CAP_KILL},
|
||||
{Key: "SETGID", Value: capability.CAP_SETGID},
|
||||
{Key: "SETUID", Value: capability.CAP_SETUID},
|
||||
{Key: "LINUX_IMMUTABLE", Value: capability.CAP_LINUX_IMMUTABLE},
|
||||
{Key: "NET_BIND_SERVICE", Value: capability.CAP_NET_BIND_SERVICE},
|
||||
{Key: "NET_BROADCAST", Value: capability.CAP_NET_BROADCAST},
|
||||
{Key: "IPC_LOCK", Value: capability.CAP_IPC_LOCK},
|
||||
{Key: "IPC_OWNER", Value: capability.CAP_IPC_OWNER},
|
||||
{Key: "SYS_CHROOT", Value: capability.CAP_SYS_CHROOT},
|
||||
{Key: "SYS_PTRACE", Value: capability.CAP_SYS_PTRACE},
|
||||
{Key: "SYS_BOOT", Value: capability.CAP_SYS_BOOT},
|
||||
{Key: "LEASE", Value: capability.CAP_LEASE},
|
||||
{Key: "SETFCAP", Value: capability.CAP_SETFCAP},
|
||||
{Key: "WAKE_ALARM", Value: capability.CAP_WAKE_ALARM},
|
||||
{Key: "BLOCK_SUSPEND", Value: capability.CAP_BLOCK_SUSPEND},
|
||||
}
|
19
vendor/src/github.com/docker/libcontainer/security/capabilities/types_test.go
vendored
Normal file
19
vendor/src/github.com/docker/libcontainer/security/capabilities/types_test.go
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
package capabilities
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCapabilitiesContains(t *testing.T) {
|
||||
caps := Capabilities{
|
||||
GetCapability("MKNOD"),
|
||||
GetCapability("SETPCAP"),
|
||||
}
|
||||
|
||||
if caps.contains("SYS_ADMIN") {
|
||||
t.Fatal("capabilities should not contain SYS_ADMIN")
|
||||
}
|
||||
if !caps.contains("MKNOD") {
|
||||
t.Fatal("capabilities should contain MKNOD but does not")
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
package libcontainer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnkownNamespace = errors.New("Unknown namespace")
|
||||
ErrUnkownCapability = errors.New("Unknown capability")
|
||||
ErrUnsupported = errors.New("Unsupported method")
|
||||
)
|
||||
|
||||
type Mounts []Mount
|
||||
|
||||
func (s Mounts) OfType(t string) Mounts {
|
||||
out := Mounts{}
|
||||
for _, m := range s {
|
||||
if m.Type == t {
|
||||
out = append(out, m)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
// namespaceList is used to convert the libcontainer types
|
||||
// into the names of the files located in /proc/<pid>/ns/* for
|
||||
// each namespace
|
||||
var (
|
||||
namespaceList = Namespaces{}
|
||||
|
||||
capabilityList = Capabilities{
|
||||
{Key: "SETPCAP", Value: capability.CAP_SETPCAP},
|
||||
{Key: "SYS_MODULE", Value: capability.CAP_SYS_MODULE},
|
||||
{Key: "SYS_RAWIO", Value: capability.CAP_SYS_RAWIO},
|
||||
{Key: "SYS_PACCT", Value: capability.CAP_SYS_PACCT},
|
||||
{Key: "SYS_ADMIN", Value: capability.CAP_SYS_ADMIN},
|
||||
{Key: "SYS_NICE", Value: capability.CAP_SYS_NICE},
|
||||
{Key: "SYS_RESOURCE", Value: capability.CAP_SYS_RESOURCE},
|
||||
{Key: "SYS_TIME", Value: capability.CAP_SYS_TIME},
|
||||
{Key: "SYS_TTY_CONFIG", Value: capability.CAP_SYS_TTY_CONFIG},
|
||||
{Key: "MKNOD", Value: capability.CAP_MKNOD},
|
||||
{Key: "AUDIT_WRITE", Value: capability.CAP_AUDIT_WRITE},
|
||||
{Key: "AUDIT_CONTROL", Value: capability.CAP_AUDIT_CONTROL},
|
||||
{Key: "MAC_OVERRIDE", Value: capability.CAP_MAC_OVERRIDE},
|
||||
{Key: "MAC_ADMIN", Value: capability.CAP_MAC_ADMIN},
|
||||
{Key: "NET_ADMIN", Value: capability.CAP_NET_ADMIN},
|
||||
{Key: "SYSLOG", Value: capability.CAP_SYSLOG},
|
||||
{Key: "SETUID", Value: capability.CAP_SETUID},
|
||||
{Key: "SETGID", Value: capability.CAP_SETGID},
|
||||
{Key: "CHOWN", Value: capability.CAP_CHOWN},
|
||||
{Key: "NET_RAW", Value: capability.CAP_NET_RAW},
|
||||
{Key: "DAC_OVERRIDE", Value: capability.CAP_DAC_OVERRIDE},
|
||||
{Key: "FOWNER", Value: capability.CAP_FOWNER},
|
||||
{Key: "DAC_READ_SEARCH", Value: capability.CAP_DAC_READ_SEARCH},
|
||||
{Key: "FSETID", Value: capability.CAP_FSETID},
|
||||
{Key: "KILL", Value: capability.CAP_KILL},
|
||||
{Key: "SETGID", Value: capability.CAP_SETGID},
|
||||
{Key: "SETUID", Value: capability.CAP_SETUID},
|
||||
{Key: "LINUX_IMMUTABLE", Value: capability.CAP_LINUX_IMMUTABLE},
|
||||
{Key: "NET_BIND_SERVICE", Value: capability.CAP_NET_BIND_SERVICE},
|
||||
{Key: "NET_BROADCAST", Value: capability.CAP_NET_BROADCAST},
|
||||
{Key: "IPC_LOCK", Value: capability.CAP_IPC_LOCK},
|
||||
{Key: "IPC_OWNER", Value: capability.CAP_IPC_OWNER},
|
||||
{Key: "SYS_CHROOT", Value: capability.CAP_SYS_CHROOT},
|
||||
{Key: "SYS_PTRACE", Value: capability.CAP_SYS_PTRACE},
|
||||
{Key: "SYS_BOOT", Value: capability.CAP_SYS_BOOT},
|
||||
{Key: "LEASE", Value: capability.CAP_LEASE},
|
||||
{Key: "SETFCAP", Value: capability.CAP_SETFCAP},
|
||||
{Key: "WAKE_ALARM", Value: capability.CAP_WAKE_ALARM},
|
||||
{Key: "BLOCK_SUSPEND", Value: capability.CAP_BLOCK_SUSPEND},
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
Namespace struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Value int `json:"value,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
}
|
||||
Namespaces []*Namespace
|
||||
)
|
||||
|
||||
func (ns *Namespace) String() string {
|
||||
return ns.Key
|
||||
}
|
||||
|
||||
func GetNamespace(key string) *Namespace {
|
||||
for _, ns := range namespaceList {
|
||||
if ns.Key == key {
|
||||
cpy := *ns
|
||||
return &cpy
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Contains returns true if the specified Namespace is
|
||||
// in the slice
|
||||
func (n Namespaces) Contains(ns string) bool {
|
||||
return n.Get(ns) != nil
|
||||
}
|
||||
|
||||
func (n Namespaces) Get(ns string) *Namespace {
|
||||
for _, nsp := range n {
|
||||
if nsp != nil && nsp.Key == ns {
|
||||
return nsp
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type (
|
||||
Capability struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Value capability.Cap `json:"value,omitempty"`
|
||||
}
|
||||
Capabilities []*Capability
|
||||
)
|
||||
|
||||
func (c *Capability) String() string {
|
||||
return c.Key
|
||||
}
|
||||
|
||||
func GetCapability(key string) *Capability {
|
||||
for _, capp := range capabilityList {
|
||||
if capp.Key == key {
|
||||
cpy := *capp
|
||||
return &cpy
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAllCapabilities() []string {
|
||||
output := make([]string, len(capabilityList))
|
||||
for i, capability := range capabilityList {
|
||||
output[i] = capability.String()
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// Contains returns true if the specified Capability is
|
||||
// in the slice
|
||||
func (c Capabilities) Contains(capp string) bool {
|
||||
return c.Get(capp) != nil
|
||||
}
|
||||
|
||||
func (c Capabilities) Get(capp string) *Capability {
|
||||
for _, cap := range c {
|
||||
if cap.Key == capp {
|
||||
return cap
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue