|
@@ -14,6 +14,7 @@ import (
|
|
|
"sync"
|
|
|
"syscall"
|
|
|
|
|
|
+ log "github.com/Sirupsen/logrus"
|
|
|
"github.com/docker/docker/daemon/execdriver"
|
|
|
"github.com/docker/docker/pkg/term"
|
|
|
"github.com/docker/libcontainer"
|
|
@@ -60,11 +61,20 @@ func NewDriver(root, initPath string) (*driver, error) {
|
|
|
}, nil
|
|
|
}
|
|
|
|
|
|
-func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
|
|
+func (d *driver) notifyOnOOM(config *libcontainer.Config) (<-chan struct{}, error) {
|
|
|
+ return fs.NotifyOnOOM(config.Cgroups)
|
|
|
+}
|
|
|
+
|
|
|
+type execOutput struct {
|
|
|
+ exitCode int
|
|
|
+ err error
|
|
|
+}
|
|
|
+
|
|
|
+func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (*execdriver.ExitStatus, error) {
|
|
|
// take the Command and populate the libcontainer.Config from it
|
|
|
container, err := d.createContainer(c)
|
|
|
if err != nil {
|
|
|
- return -1, err
|
|
|
+ return nil, err
|
|
|
}
|
|
|
|
|
|
var term execdriver.Terminal
|
|
@@ -75,7 +85,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
|
|
term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes)
|
|
|
}
|
|
|
if err != nil {
|
|
|
- return -1, err
|
|
|
+ return nil, err
|
|
|
}
|
|
|
c.ProcessConfig.Terminal = term
|
|
|
|
|
@@ -92,40 +102,70 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
|
|
)
|
|
|
|
|
|
if err := d.createContainerRoot(c.ID); err != nil {
|
|
|
- return -1, err
|
|
|
+ return nil, err
|
|
|
}
|
|
|
defer d.cleanContainer(c.ID)
|
|
|
|
|
|
if err := d.writeContainerFile(container, c.ID); err != nil {
|
|
|
- return -1, err
|
|
|
+ return nil, err
|
|
|
}
|
|
|
|
|
|
- return namespaces.Exec(container, c.ProcessConfig.Stdin, c.ProcessConfig.Stdout, c.ProcessConfig.Stderr, c.ProcessConfig.Console, dataPath, args, func(container *libcontainer.Config, console, dataPath, init string, child *os.File, args []string) *exec.Cmd {
|
|
|
- c.ProcessConfig.Path = d.initPath
|
|
|
- c.ProcessConfig.Args = append([]string{
|
|
|
- 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.ProcessConfig.SysProcAttr = &syscall.SysProcAttr{
|
|
|
- Cloneflags: uintptr(namespaces.GetNamespaceFlags(container.Namespaces)),
|
|
|
- }
|
|
|
- c.ProcessConfig.ExtraFiles = []*os.File{child}
|
|
|
+ execOutputChan := make(chan execOutput, 0)
|
|
|
+ waitForStart := make(chan struct{}, 0)
|
|
|
|
|
|
- c.ProcessConfig.Env = container.Env
|
|
|
- c.ProcessConfig.Dir = container.RootFs
|
|
|
+ go func() {
|
|
|
+ exitCode, err := namespaces.Exec(container, c.ProcessConfig.Stdin, c.ProcessConfig.Stdout, c.ProcessConfig.Stderr, c.ProcessConfig.Console, dataPath, args, func(container *libcontainer.Config, console, dataPath, init string, child *os.File, args []string) *exec.Cmd {
|
|
|
+ c.ProcessConfig.Path = d.initPath
|
|
|
+ c.ProcessConfig.Args = append([]string{
|
|
|
+ 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.ProcessConfig.SysProcAttr = &syscall.SysProcAttr{
|
|
|
+ Cloneflags: uintptr(namespaces.GetNamespaceFlags(container.Namespaces)),
|
|
|
+ }
|
|
|
+ c.ProcessConfig.ExtraFiles = []*os.File{child}
|
|
|
|
|
|
- return &c.ProcessConfig.Cmd
|
|
|
- }, func() {
|
|
|
- if startCallback != nil {
|
|
|
- c.ContainerPid = c.ProcessConfig.Process.Pid
|
|
|
- startCallback(&c.ProcessConfig, c.ContainerPid)
|
|
|
+ c.ProcessConfig.Env = container.Env
|
|
|
+ c.ProcessConfig.Dir = container.RootFs
|
|
|
+
|
|
|
+ return &c.ProcessConfig.Cmd
|
|
|
+ }, func() {
|
|
|
+ close(waitForStart)
|
|
|
+ if startCallback != nil {
|
|
|
+ c.ContainerPid = c.ProcessConfig.Process.Pid
|
|
|
+ startCallback(&c.ProcessConfig, c.ContainerPid)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ execOutputChan <- execOutput{exitCode, err}
|
|
|
+ }()
|
|
|
+
|
|
|
+ select {
|
|
|
+ case execOutput := <-execOutputChan:
|
|
|
+ return &execdriver.ExitStatus{execOutput.exitCode, false}, execOutput.err
|
|
|
+ case <-waitForStart:
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ oomKill := false
|
|
|
+ go func() {
|
|
|
+ oomKillNotification, err := d.notifyOnOOM(container)
|
|
|
+ if err == nil {
|
|
|
+ if _, ok := <-oomKillNotification; ok {
|
|
|
+ oomKill = true
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.Infof("WARNING: Your kernel does not support OOM notifications: %s", err)
|
|
|
}
|
|
|
- })
|
|
|
+ }()
|
|
|
+ // wait for the container to exit.
|
|
|
+ execOutput := <-execOutputChan
|
|
|
+
|
|
|
+ return &execdriver.ExitStatus{execOutput.exitCode, oomKill}, execOutput.err
|
|
|
}
|
|
|
|
|
|
func (d *driver) Kill(p *execdriver.Command, sig int) error {
|