From da0d6dbd7b5b429b79ae4ea22957e8a14b4ca1ec Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 30 Apr 2014 18:49:24 -0700 Subject: [PATCH] Make native driver use Exec func with different CreateCommand Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- daemon/execdriver/native/driver.go | 116 ++++++------------------- pkg/libcontainer/nsinit/create.go | 10 +++ pkg/libcontainer/nsinit/exec.go | 8 +- pkg/libcontainer/nsinit/nsinit/main.go | 2 +- pkg/libcontainer/nsinit/unsupported.go | 4 + 5 files changed, 46 insertions(+), 94 deletions(-) create mode 100644 pkg/libcontainer/nsinit/create.go diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index c73eb0aec5..a397387f11 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -90,9 +90,6 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba d.activeContainers[c.ID] = &c.Cmd var ( - master *os.File - console string - dataPath = filepath.Join(d.root, c.ID) args = append([]string{c.Entrypoint}, c.Arguments...) ) @@ -105,72 +102,36 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba return -1, err } - // create a pipe so that we can syncronize with the namespaced process and - // pass the veth name to the child - syncPipe, err := nsinit.NewSyncPipe() - if err != nil { - return -1, err - } term := getTerminal(c, pipes) - if container.Tty { - master, console, err = system.CreateMasterAndConsole() - if err != nil { - return -1, err + return nsinit.Exec(container, term, c.Rootfs, dataPath, args, func(container *libcontainer.Container, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd { + // we need to join the rootfs because nsinit will setup the rootfs and chroot + initPath := filepath.Join(c.Rootfs, c.InitPath) + + c.Path = d.initPath + c.Args = append([]string{ + initPath, + "-driver", DriverName, + "-console", console, + "-pipe", "3", + "-root", filepath.Join(d.root, c.ID), + "--", + }, args...) + + // set this to nil so that when we set the clone flags anything else is reset + c.SysProcAttr = nil + system.SetCloneFlags(&c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces))) + c.ExtraFiles = []*os.File{child} + + c.Env = container.Env + c.Dir = c.Rootfs + + return &c.Cmd + }, func() { + if startCallback != nil { + startCallback(c) } - term.SetMaster(master) - } - - setupCommand(d, c, container, console, syncPipe.Child(), args) - if err := term.Attach(&c.Cmd); err != nil { - return -1, err - } - defer term.Close() - - if err := c.Start(); err != nil { - return -1, err - } - - started, err := system.GetProcessStartTime(c.Process.Pid) - if err != nil { - return -1, err - } - if err := nsinit.WritePid(dataPath, c.Process.Pid, started); err != nil { - c.Process.Kill() - return -1, err - } - defer nsinit.DeletePid(dataPath) - - // Do this before syncing with child so that no children - // can escape the cgroup - cleaner, err := nsinit.SetupCgroups(container, c.Process.Pid) - if err != nil { - c.Process.Kill() - return -1, err - } - if cleaner != nil { - defer cleaner.Cleanup() - } - - if err := nsinit.InitializeNetworking(container, c.Process.Pid, syncPipe); err != nil { - c.Process.Kill() - return -1, err - } - - // Sync with child - syncPipe.Close() - - if startCallback != nil { - startCallback(c) - } - - if err := c.Wait(); err != nil { - if _, ok := err.(*exec.ExitError); !ok { - return -1, err - } - } - return c.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil - + }) } func (d *driver) Kill(p *execdriver.Command, sig int) error { @@ -297,26 +258,3 @@ func getTerminal(c *execdriver.Command, pipes *execdriver.Pipes) nsinit.Terminal c.Terminal = term return term } - -func setupCommand(d *driver, c *execdriver.Command, container *libcontainer.Container, console string, syncFile *os.File, args []string) { - // we need to join the rootfs because nsinit will setup the rootfs and chroot - initPath := filepath.Join(c.Rootfs, c.InitPath) - - c.Path = d.initPath - c.Args = append([]string{ - initPath, - "-driver", DriverName, - "-console", console, - "-pipe", "3", - "-root", filepath.Join(d.root, c.ID), - "--", - }, args...) - - // set this to nil so that when we set the clone flags anything else is reset - c.SysProcAttr = nil - system.SetCloneFlags(&c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces))) - c.ExtraFiles = []*os.File{syncFile} - - c.Env = container.Env - c.Dir = c.Rootfs -} diff --git a/pkg/libcontainer/nsinit/create.go b/pkg/libcontainer/nsinit/create.go new file mode 100644 index 0000000000..d5cba464d2 --- /dev/null +++ b/pkg/libcontainer/nsinit/create.go @@ -0,0 +1,10 @@ +package nsinit + +import ( + "os" + "os/exec" + + "github.com/dotcloud/docker/pkg/libcontainer" +) + +type CreateCommand func(container *libcontainer.Container, console, rootfs, dataPath, init string, childPipe *os.File, args []string) *exec.Cmd diff --git a/pkg/libcontainer/nsinit/exec.go b/pkg/libcontainer/nsinit/exec.go index 078f277e80..8886efeb32 100644 --- a/pkg/libcontainer/nsinit/exec.go +++ b/pkg/libcontainer/nsinit/exec.go @@ -17,7 +17,7 @@ import ( // 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, startCallback func()) (int, error) { +func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { var ( master *os.File console string @@ -39,7 +39,7 @@ func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath str term.SetMaster(master) } - command := CreateCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args) + command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args) if err := term.Attach(command); err != nil { return -1, err } @@ -90,7 +90,7 @@ func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath str return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil } -// CreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces +// DefaultCreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces // defined on the container's configuration and use the current binary as the init with the // args provided // @@ -99,7 +99,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 CreateCommand(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd { +func DefaultCreateCommand(container *libcontainer.Container, 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, diff --git a/pkg/libcontainer/nsinit/nsinit/main.go b/pkg/libcontainer/nsinit/nsinit/main.go index 6faa9c61cd..b5325d40b3 100644 --- a/pkg/libcontainer/nsinit/nsinit/main.go +++ b/pkg/libcontainer/nsinit/nsinit/main.go @@ -39,7 +39,7 @@ func main() { exitCode, err = nsinit.ExecIn(container, nspid, os.Args[2:]) } else { term := nsinit.NewTerminal(os.Stdin, os.Stdout, os.Stderr, container.Tty) - exitCode, err = nsinit.Exec(container, term, "", dataPath, os.Args[2:], nil) + exitCode, err = nsinit.Exec(container, term, "", dataPath, os.Args[2:], nsinit.DefaultCreateCommand, nil) } if err != nil { diff --git a/pkg/libcontainer/nsinit/unsupported.go b/pkg/libcontainer/nsinit/unsupported.go index c99d881a59..f213f2ec88 100644 --- a/pkg/libcontainer/nsinit/unsupported.go +++ b/pkg/libcontainer/nsinit/unsupported.go @@ -7,6 +7,10 @@ import ( "github.com/dotcloud/docker/pkg/libcontainer" ) +func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { + return -1, libcontainer.ErrUnsupported +} + func Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error { return libcontainer.ErrUnsupported }