Skip to content

Commit

Permalink
Merge pull request #2 from creack/extract-lxc
Browse files Browse the repository at this point in the history
Move docker init into drivers functions
  • Loading branch information
crosbymichael committed Jan 15, 2014
2 parents fd82972 + c9274fc commit 9954a39
Show file tree
Hide file tree
Showing 7 changed files with 273 additions and 226 deletions.
22 changes: 21 additions & 1 deletion execdriver/chroot/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,29 @@ package chroot

import (
"github.com/dotcloud/docker/execdriver"
"github.com/dotcloud/docker/mount"
"os"
"os/exec"
)

const DriverName = "chroot"

func init() {
execdriver.RegisterDockerInitFct(DriverName, func(args *execdriver.DockerInitArgs) error {
if err := mount.ForceMount("proc", "proc", "proc", ""); err != nil {
return err
}
defer mount.ForceUnmount("proc")
cmd := exec.Command(args.Args[0], args.Args[1:]...)

cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin

return cmd.Run()
})
}

type driver struct {
}

Expand All @@ -13,7 +33,7 @@ func NewDriver() (*driver, error) {
}

func (d *driver) Name() string {
return "chroot"
return DriverName
}

func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallback) (int, error) {
Expand Down
44 changes: 41 additions & 3 deletions execdriver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,49 @@ import (
)

var (
ErrNotRunning = errors.New("Process could not be started")
ErrWaitTimeoutReached = errors.New("Wait timeout reached")
ErrNotRunning = errors.New("Process could not be started")
ErrWaitTimeoutReached = errors.New("Wait timeout reached")
ErrDriverAlreadyRegistered = errors.New("A driver already registered this docker init function")
ErrDriverNotFound = errors.New("The requested docker init has not been found")
)

type StartCallback func(*Process)
var dockerInitFcts map[string]DockerInitFct

type (
StartCallback func(*Process)
DockerInitFct func(i *DockerInitArgs) error
)

func RegisterDockerInitFct(name string, fct DockerInitFct) error {
if dockerInitFcts == nil {
dockerInitFcts = make(map[string]DockerInitFct)
}
if _, ok := dockerInitFcts[name]; ok {
return ErrDriverAlreadyRegistered
}
dockerInitFcts[name] = fct
return nil
}

func GetDockerInitFct(name string) (DockerInitFct, error) {
fct, ok := dockerInitFcts[name]
if !ok {
return nil, ErrDriverNotFound
}
return fct, nil
}

type DockerInitArgs struct {
User string
Gateway string
Ip string
WorkDir string
Privileged bool
Env []string
Args []string
Mtu int
Driver string
}

type Driver interface {
Run(c *Process, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
Expand Down
38 changes: 37 additions & 1 deletion execdriver/lxc/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,50 @@ import (
"github.com/dotcloud/docker/execdriver"
"github.com/dotcloud/docker/utils"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"strconv"
"strings"
"syscall"
"time"
)

const DriverName = "lxc"

func init() {
execdriver.RegisterDockerInitFct(DriverName, func(args *execdriver.DockerInitArgs) error {
if err := setupHostname(args); err != nil {
return err
}

if err := setupNetworking(args); err != nil {
return err
}

if err := setupCapabilities(args); err != nil {
return err
}
if err := setupWorkingDirectory(args); err != nil {
return err
}

if err := changeUser(args); err != nil {
return err
}
path, err := exec.LookPath(args.Args[0])
if err != nil {
log.Printf("Unable to locate %v", args.Args[0])
os.Exit(127)
}
if err := syscall.Exec(path, args.Args, os.Environ()); err != nil {
panic(err)
}
panic("Unreachable")
})
}

type driver struct {
root string // root path for the driver to use
apparmor bool
Expand All @@ -32,7 +68,7 @@ func NewDriver(root string, apparmor bool) (*driver, error) {
}

func (d *driver) Name() string {
return "lxc"
return DriverName
}

func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallback) (int, error) {
Expand Down
153 changes: 153 additions & 0 deletions execdriver/lxc/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package lxc

import (
"fmt"
"github.com/dotcloud/docker/execdriver"
"github.com/dotcloud/docker/pkg/netlink"
"github.com/dotcloud/docker/utils"
"github.com/syndtr/gocapability/capability"
"net"
"os"
"strconv"
"strings"
"syscall"
)

func setupHostname(args *execdriver.DockerInitArgs) error {
hostname := getEnv(args, "HOSTNAME")
if hostname == "" {
return nil
}
return setHostname(hostname)
}

// Setup networking
func setupNetworking(args *execdriver.DockerInitArgs) error {
if args.Ip != "" {
// eth0
iface, err := net.InterfaceByName("eth0")
if err != nil {
return fmt.Errorf("Unable to set up networking: %v", err)
}
ip, ipNet, err := net.ParseCIDR(args.Ip)
if err != nil {
return fmt.Errorf("Unable to set up networking: %v", err)
}
if err := netlink.NetworkLinkAddIp(iface, ip, ipNet); err != nil {
return fmt.Errorf("Unable to set up networking: %v", err)
}
if err := netlink.NetworkSetMTU(iface, args.Mtu); err != nil {
return fmt.Errorf("Unable to set MTU: %v", err)
}
if err := netlink.NetworkLinkUp(iface); err != nil {
return fmt.Errorf("Unable to set up networking: %v", err)
}

// loopback
iface, err = net.InterfaceByName("lo")
if err != nil {
return fmt.Errorf("Unable to set up networking: %v", err)
}
if err := netlink.NetworkLinkUp(iface); err != nil {
return fmt.Errorf("Unable to set up networking: %v", err)
}
}
if args.Gateway != "" {
gw := net.ParseIP(args.Gateway)
if gw == nil {
return fmt.Errorf("Unable to set up networking, %s is not a valid gateway IP", args.Gateway)
}

if err := netlink.AddDefaultGw(gw); err != nil {
return fmt.Errorf("Unable to set up networking: %v", err)
}
}

return nil
}

// Setup working directory
func setupWorkingDirectory(args *execdriver.DockerInitArgs) error {
if args.WorkDir == "" {
return nil
}
if err := syscall.Chdir(args.WorkDir); err != nil {
return fmt.Errorf("Unable to change dir to %v: %v", args.WorkDir, err)
}
return nil
}

// Takes care of dropping privileges to the desired user
func changeUser(args *execdriver.DockerInitArgs) error {
if args.User == "" {
return nil
}
userent, err := utils.UserLookup(args.User)
if err != nil {
return fmt.Errorf("Unable to find user %v: %v", args.User, err)
}

uid, err := strconv.Atoi(userent.Uid)
if err != nil {
return fmt.Errorf("Invalid uid: %v", userent.Uid)
}
gid, err := strconv.Atoi(userent.Gid)
if err != nil {
return fmt.Errorf("Invalid gid: %v", userent.Gid)
}

if err := syscall.Setgid(gid); err != nil {
return fmt.Errorf("setgid failed: %v", err)
}
if err := syscall.Setuid(uid); err != nil {
return fmt.Errorf("setuid failed: %v", err)
}

return nil
}

func setupCapabilities(args *execdriver.DockerInitArgs) error {

if args.Privileged {
return nil
}

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

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 getEnv(args *execdriver.DockerInitArgs, key string) string {
for _, kv := range args.Env {
parts := strings.SplitN(kv, "=", 2)
if parts[0] == key && len(parts) == 2 {
return parts[1]
}
}
return ""
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sysinit
package lxc

func setHostname(hostname string) error {
panic("Not supported on darwin")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sysinit
package lxc

import (
"syscall"
Expand Down

0 comments on commit 9954a39

Please sign in to comment.