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

Commit

Permalink
Initial commit of libcontainer
Browse files Browse the repository at this point in the history
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
  • Loading branch information
crosbymichael committed Feb 21, 2014
0 parents commit 6415e8b
Show file tree
Hide file tree
Showing 20 changed files with 1,531 additions and 0 deletions.
2 changes: 2 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
Guillaume Charmes <guillaume@dotcloud.com> (@creack)
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
## libcontainer - reference implementation for containers

#### playground


Use the cli package to test out functionality

First setup a container configuration. You will need a root fs, better go the path to a
stopped docker container and use that.


```json
{
"id": "koye",
"namespace_pid": 12265,
"command": {
"args": [
"/bin/bash"
],
"environment": [
"HOME=/",
"PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin",
"container=docker",
"TERM=xterm"
]
},
"rootfs": "/root/development/gocode/src/github.com/docker/libcontainer/namespaces/ubuntu",
"network": null,
"user": "",
"working_dir": "",
"namespaces": [
"NEWNET",
"NEWIPC",
"NEWNS",
"NEWPID",
"NEWUTS"
],
"capabilities": [
"SETPCAP",
"SYS_MODULE",
"SYS_RAWIO",
"SYS_PACCT",
"SYS_ADMIN",
"SYS_NICE",
"SYS_RESOURCE",
"SYS_TIME",
"SYS_TTY_CONFIG",
"MKNOD",
"AUDIT_WRITE",
"AUDIT_CONTROL",
"MAC_OVERRIDE",
"MAC_ADMIN"
]
}
```

After you have a json file and a rootfs path to use just run:
`./cli exec container.json`


If you want to attach to an existing namespace just use the same json
file with the container still running and do:
`./cli execin container.json`
49 changes: 49 additions & 0 deletions capabilities/capabilities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package capabilities

import (
"github.com/dotcloud/docker/pkg/libcontainer"
"github.com/syndtr/gocapability/capability"
"os"
)

var capMap = map[libcontainer.Capability]capability.Cap{
libcontainer.CAP_SETPCAP: capability.CAP_SETPCAP,
libcontainer.CAP_SYS_MODULE: capability.CAP_SYS_MODULE,
libcontainer.CAP_SYS_RAWIO: capability.CAP_SYS_RAWIO,
libcontainer.CAP_SYS_PACCT: capability.CAP_SYS_PACCT,
libcontainer.CAP_SYS_ADMIN: capability.CAP_SYS_ADMIN,
libcontainer.CAP_SYS_NICE: capability.CAP_SYS_NICE,
libcontainer.CAP_SYS_RESOURCE: capability.CAP_SYS_RESOURCE,
libcontainer.CAP_SYS_TIME: capability.CAP_SYS_TIME,
libcontainer.CAP_SYS_TTY_CONFIG: capability.CAP_SYS_TTY_CONFIG,
libcontainer.CAP_MKNOD: capability.CAP_MKNOD,
libcontainer.CAP_AUDIT_WRITE: capability.CAP_AUDIT_WRITE,
libcontainer.CAP_AUDIT_CONTROL: capability.CAP_AUDIT_CONTROL,
libcontainer.CAP_MAC_OVERRIDE: capability.CAP_MAC_OVERRIDE,
libcontainer.CAP_MAC_ADMIN: capability.CAP_MAC_ADMIN,
}

// DropCapabilities drops capabilities for the current process based
// on the container's configuration.
func DropCapabilities(container *libcontainer.Container) error {
if drop := getCapabilities(container); len(drop) > 0 {
c, err := capability.NewPid(os.Getpid())
if err != nil {
return err
}
c.Unset(capability.CAPS|capability.BOUNDS, drop...)

if err := c.Apply(capability.CAPS | capability.BOUNDS); err != nil {
return err
}
}
return nil
}

func getCapabilities(container *libcontainer.Container) []capability.Cap {
drop := []capability.Cap{}
for _, c := range container.Capabilities {
drop = append(drop, capMap[c])
}
return drop
}
171 changes: 171 additions & 0 deletions cli/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"github.com/dotcloud/docker/pkg/libcontainer"
"github.com/dotcloud/docker/pkg/libcontainer/namespaces"
"github.com/dotcloud/docker/pkg/libcontainer/network"
"github.com/dotcloud/docker/pkg/libcontainer/utils"
"os"
)

var (
displayPid bool
newCommand string
usrNet bool
)

func init() {
flag.BoolVar(&displayPid, "pid", false, "display the pid before waiting")
flag.StringVar(&newCommand, "cmd", "/bin/bash", "command to run in the existing namespace")
flag.BoolVar(&usrNet, "net", false, "user a net namespace")
flag.Parse()
}

func exec(container *libcontainer.Container) error {
var (
netFile *os.File
err error
)
container.NetNsFd = 0

if usrNet {
netFile, err = os.Open("/root/nsroot/test")
if err != nil {
return err
}
container.NetNsFd = netFile.Fd()
}

pid, err := namespaces.Exec(container)
if err != nil {
return fmt.Errorf("error exec container %s", err)
}

if displayPid {
fmt.Println(pid)
}

exitcode, err := utils.WaitOnPid(pid)
if err != nil {
return fmt.Errorf("error waiting on child %s", err)
}
fmt.Println(exitcode)
if usrNet {
netFile.Close()
if err := network.DeleteNetworkNamespace("/root/nsroot/test"); err != nil {
return err
}
}
os.Exit(exitcode)
return nil
}

func execIn(container *libcontainer.Container) error {
f, err := os.Open("/root/nsroot/test")
if err != nil {
return err
}
container.NetNsFd = f.Fd()
pid, err := namespaces.ExecIn(container, &libcontainer.Command{
Env: container.Command.Env,
Args: []string{
newCommand,
},
})
if err != nil {
return fmt.Errorf("error exexin container %s", err)
}
exitcode, err := utils.WaitOnPid(pid)
if err != nil {
return fmt.Errorf("error waiting on child %s", err)
}
os.Exit(exitcode)
return nil
}

func createNet(config *libcontainer.Network) error {
root := "/root/nsroot"
if err := network.SetupNamespaceMountDir(root); err != nil {
return err
}

nspath := root + "/test"
if err := network.CreateNetworkNamespace(nspath); err != nil {
return nil
}
if err := network.CreateVethPair("veth0", config.TempVethName); err != nil {
return err
}
if err := network.SetInterfaceMaster("veth0", config.Bridge); err != nil {
return err
}
if err := network.InterfaceUp("veth0"); err != nil {
return err
}

f, err := os.Open(nspath)
if err != nil {
return err
}
defer f.Close()

if err := network.SetInterfaceInNamespaceFd("veth1", int(f.Fd())); err != nil {
return err
}

/*
if err := network.SetupVethInsideNamespace(f.Fd(), config); err != nil {
return err
}
*/
return nil
}

func printErr(err error) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}

func main() {
var (
err error
cliCmd = flag.Arg(0)
config = flag.Arg(1)
)
f, err := os.Open(config)
if err != nil {
printErr(err)
}

dec := json.NewDecoder(f)
var container *libcontainer.Container

if err := dec.Decode(&container); err != nil {
printErr(err)
}
f.Close()

switch cliCmd {
case "exec":
err = exec(container)
case "execin":
err = execIn(container)
case "net":
err = createNet(&libcontainer.Network{
TempVethName: "veth1",
IP: "172.17.0.100/16",
Gateway: "172.17.42.1",
Mtu: 1500,
Bridge: "docker0",
})
default:
err = fmt.Errorf("command not supported: %s", cliCmd)
}

if err != nil {
printErr(err)
}
}
27 changes: 27 additions & 0 deletions container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package libcontainer

type Container struct {
ID string `json:"id,omitempty"`
NsPid int `json:"namespace_pid,omitempty"`
Command *Command `json:"command,omitempty"`
RootFs string `json:"rootfs,omitempty"`
ReadonlyFs bool `json:"readonly_fs,omitempty"`
NetNsFd uintptr `json:"network_namespace_fd,omitempty"`
User string `json:"user,omitempty"`
WorkingDir string `json:"working_dir,omitempty"`
Namespaces Namespaces `json:"namespaces,omitempty"`
Capabilities Capabilities `json:"capabilities,omitempty"`
}

type Command struct {
Args []string `json:"args,omitempty"`
Env []string `json:"environment,omitempty"`
}

type Network struct {
TempVethName string `json:"temp_veth,omitempty"`
IP string `json:"ip,omitempty"`
Gateway string `json:"gateway,omitempty"`
Bridge string `json:"bridge,omitempty"`
Mtu int `json:"mtu,omitempty"`
}
38 changes: 38 additions & 0 deletions container.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"id": "koye",
"namespace_pid": 3117,
"command": {
"args": [
"/bin/bash"
],
"environment": [
"HOME=/",
"PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin",
"container=docker",
"TERM=xterm"
]
},
"rootfs": "/root/main/mycontainer",
"namespaces": [
"NEWIPC",
"NEWNS",
"NEWPID",
"NEWUTS"
],
"capabilities": [
"SETPCAP",
"SYS_MODULE",
"SYS_RAWIO",
"SYS_PACCT",
"SYS_ADMIN",
"SYS_NICE",
"SYS_RESOURCE",
"SYS_TIME",
"SYS_TTY_CONFIG",
"MKNOD",
"AUDIT_WRITE",
"AUDIT_CONTROL",
"MAC_OVERRIDE",
"MAC_ADMIN"
]
}
9 changes: 9 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package libcontainer

import (
"errors"
)

var (
ErrInvalidPid = errors.New("no ns pid found")
)
Loading

0 comments on commit 6415e8b

Please sign in to comment.