|
@@ -152,7 +152,9 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
|
|
User: c.ProcessConfig.User,
|
|
User: c.ProcessConfig.User,
|
|
}
|
|
}
|
|
|
|
|
|
- if err := setupPipes(container, &c.ProcessConfig, p, pipes); err != nil {
|
|
|
|
|
|
+ wg := sync.WaitGroup{}
|
|
|
|
+ writers, err := setupPipes(container, &c.ProcessConfig, p, pipes, &wg)
|
|
|
|
+ if err != nil {
|
|
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
}
|
|
}
|
|
|
|
|
|
@@ -174,6 +176,10 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
|
|
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //close the write end of any opened pipes now that they are dup'ed into the container
|
|
|
|
+ for _, writer := range writers {
|
|
|
|
+ writer.Close()
|
|
|
|
+ }
|
|
// 'oom' is used to emit 'oom' events to the eventstream, 'oomKilled' is used
|
|
// 'oom' is used to emit 'oom' events to the eventstream, 'oomKilled' is used
|
|
// to set the 'OOMKilled' flag in state
|
|
// to set the 'OOMKilled' flag in state
|
|
oom := notifyOnOOM(cont)
|
|
oom := notifyOnOOM(cont)
|
|
@@ -202,6 +208,9 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
|
|
}
|
|
}
|
|
ps = execErr.ProcessState
|
|
ps = execErr.ProcessState
|
|
}
|
|
}
|
|
|
|
+ // wait for all IO goroutine copiers to finish
|
|
|
|
+ wg.Wait()
|
|
|
|
+
|
|
cont.Destroy()
|
|
cont.Destroy()
|
|
destroyed = true
|
|
destroyed = true
|
|
// oomKilled will have an oom event if any process within the container was
|
|
// oomKilled will have an oom event if any process within the container was
|
|
@@ -480,24 +489,26 @@ func (t *TtyConsole) Close() error {
|
|
return t.console.Close()
|
|
return t.console.Close()
|
|
}
|
|
}
|
|
|
|
|
|
-func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConfig, p *libcontainer.Process, pipes *execdriver.Pipes) error {
|
|
|
|
|
|
+func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConfig, p *libcontainer.Process, pipes *execdriver.Pipes, wg *sync.WaitGroup) ([]io.WriteCloser, error) {
|
|
|
|
+
|
|
|
|
+ writers := []io.WriteCloser{}
|
|
|
|
|
|
rootuid, err := container.HostUID()
|
|
rootuid, err := container.HostUID()
|
|
if err != nil {
|
|
if err != nil {
|
|
- return err
|
|
|
|
|
|
+ return writers, err
|
|
}
|
|
}
|
|
|
|
|
|
if processConfig.Tty {
|
|
if processConfig.Tty {
|
|
cons, err := p.NewConsole(rootuid)
|
|
cons, err := p.NewConsole(rootuid)
|
|
if err != nil {
|
|
if err != nil {
|
|
- return err
|
|
|
|
|
|
+ return writers, err
|
|
}
|
|
}
|
|
term, err := NewTtyConsole(cons, pipes)
|
|
term, err := NewTtyConsole(cons, pipes)
|
|
if err != nil {
|
|
if err != nil {
|
|
- return err
|
|
|
|
|
|
+ return writers, err
|
|
}
|
|
}
|
|
processConfig.Terminal = term
|
|
processConfig.Terminal = term
|
|
- return nil
|
|
|
|
|
|
+ return writers, nil
|
|
}
|
|
}
|
|
// not a tty--set up stdio pipes
|
|
// not a tty--set up stdio pipes
|
|
term := &execdriver.StdConsole{}
|
|
term := &execdriver.StdConsole{}
|
|
@@ -512,7 +523,7 @@ func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConf
|
|
|
|
|
|
r, w, err := os.Pipe()
|
|
r, w, err := os.Pipe()
|
|
if err != nil {
|
|
if err != nil {
|
|
- return err
|
|
|
|
|
|
+ return writers, err
|
|
}
|
|
}
|
|
if pipes.Stdin != nil {
|
|
if pipes.Stdin != nil {
|
|
go func() {
|
|
go func() {
|
|
@@ -521,23 +532,32 @@ func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConf
|
|
}()
|
|
}()
|
|
p.Stdin = r
|
|
p.Stdin = r
|
|
}
|
|
}
|
|
- return nil
|
|
|
|
|
|
+ return writers, nil
|
|
}
|
|
}
|
|
|
|
|
|
// if we have user namespaces enabled (rootuid != 0), we will set
|
|
// if we have user namespaces enabled (rootuid != 0), we will set
|
|
// up os pipes for stderr, stdout, stdin so we can chown them to
|
|
// up os pipes for stderr, stdout, stdin so we can chown them to
|
|
// the proper ownership to allow for proper access to the underlying
|
|
// the proper ownership to allow for proper access to the underlying
|
|
// fds
|
|
// fds
|
|
- var fds []int
|
|
|
|
|
|
+ var fds []uintptr
|
|
|
|
+
|
|
|
|
+ copyPipes := func(out io.Writer, in io.ReadCloser) {
|
|
|
|
+ defer wg.Done()
|
|
|
|
+ io.Copy(out, in)
|
|
|
|
+ in.Close()
|
|
|
|
+ }
|
|
|
|
|
|
//setup stdout
|
|
//setup stdout
|
|
r, w, err := os.Pipe()
|
|
r, w, err := os.Pipe()
|
|
if err != nil {
|
|
if err != nil {
|
|
- return err
|
|
|
|
|
|
+ w.Close()
|
|
|
|
+ return writers, err
|
|
}
|
|
}
|
|
- fds = append(fds, int(r.Fd()), int(w.Fd()))
|
|
|
|
|
|
+ writers = append(writers, w)
|
|
|
|
+ fds = append(fds, r.Fd(), w.Fd())
|
|
if pipes.Stdout != nil {
|
|
if pipes.Stdout != nil {
|
|
- go io.Copy(pipes.Stdout, r)
|
|
|
|
|
|
+ wg.Add(1)
|
|
|
|
+ go copyPipes(pipes.Stdout, r)
|
|
}
|
|
}
|
|
term.Closers = append(term.Closers, r)
|
|
term.Closers = append(term.Closers, r)
|
|
p.Stdout = w
|
|
p.Stdout = w
|
|
@@ -545,11 +565,14 @@ func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConf
|
|
//setup stderr
|
|
//setup stderr
|
|
r, w, err = os.Pipe()
|
|
r, w, err = os.Pipe()
|
|
if err != nil {
|
|
if err != nil {
|
|
- return err
|
|
|
|
|
|
+ w.Close()
|
|
|
|
+ return writers, err
|
|
}
|
|
}
|
|
- fds = append(fds, int(r.Fd()), int(w.Fd()))
|
|
|
|
|
|
+ writers = append(writers, w)
|
|
|
|
+ fds = append(fds, r.Fd(), w.Fd())
|
|
if pipes.Stderr != nil {
|
|
if pipes.Stderr != nil {
|
|
- go io.Copy(pipes.Stderr, r)
|
|
|
|
|
|
+ wg.Add(1)
|
|
|
|
+ go copyPipes(pipes.Stderr, r)
|
|
}
|
|
}
|
|
term.Closers = append(term.Closers, r)
|
|
term.Closers = append(term.Closers, r)
|
|
p.Stderr = w
|
|
p.Stderr = w
|
|
@@ -557,9 +580,10 @@ func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConf
|
|
//setup stdin
|
|
//setup stdin
|
|
r, w, err = os.Pipe()
|
|
r, w, err = os.Pipe()
|
|
if err != nil {
|
|
if err != nil {
|
|
- return err
|
|
|
|
|
|
+ r.Close()
|
|
|
|
+ return writers, err
|
|
}
|
|
}
|
|
- fds = append(fds, int(r.Fd()), int(w.Fd()))
|
|
|
|
|
|
+ fds = append(fds, r.Fd(), w.Fd())
|
|
if pipes.Stdin != nil {
|
|
if pipes.Stdin != nil {
|
|
go func() {
|
|
go func() {
|
|
io.Copy(w, pipes.Stdin)
|
|
io.Copy(w, pipes.Stdin)
|
|
@@ -568,11 +592,11 @@ func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConf
|
|
p.Stdin = r
|
|
p.Stdin = r
|
|
}
|
|
}
|
|
for _, fd := range fds {
|
|
for _, fd := range fds {
|
|
- if err := syscall.Fchown(fd, rootuid, rootuid); err != nil {
|
|
|
|
- return fmt.Errorf("Failed to chown pipes fd: %v", err)
|
|
|
|
|
|
+ if err := syscall.Fchown(int(fd), rootuid, rootuid); err != nil {
|
|
|
|
+ return writers, fmt.Errorf("Failed to chown pipes fd: %v", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- return nil
|
|
|
|
|
|
+ return writers, nil
|
|
}
|
|
}
|
|
|
|
|
|
// SupportsHooks implements the execdriver Driver interface.
|
|
// SupportsHooks implements the execdriver Driver interface.
|