diff options
author | Jim Minter <jminter@redhat.com> | 2017-01-30 13:49:22 +0100 |
---|---|---|
committer | Jim Minter <jminter@redhat.com> | 2017-02-01 09:01:36 +0000 |
commit | 84d6240cfe7cc66a7d3f6ac78ea6faad0e3108b9 (patch) | |
tree | 7b4ff738870a7269d05e5a584c957684197320c0 /daemon/attach.go | |
parent | 48dd90d3985889ca008faa3b041bf31d2ada95c5 (diff) | |
download | docker-84d6240cfe7cc66a7d3f6ac78ea6faad0e3108b9.tar.gz |
Resolve race conditions in attach API call
Signed-off-by: Jim Minter <jminter@redhat.com>
Diffstat (limited to 'daemon/attach.go')
-rw-r--r-- | daemon/attach.go | 100 |
1 files changed, 49 insertions, 51 deletions
diff --git a/daemon/attach.go b/daemon/attach.go index 5bdbb35b31..1cc8adb17b 100644 --- a/daemon/attach.go +++ b/daemon/attach.go @@ -15,14 +15,6 @@ import ( "github.com/docker/docker/pkg/term" ) -type containerAttachConfig struct { - detachKeys []byte - stdin io.ReadCloser - stdout, stderr io.Writer - showHistory bool - stream bool -} - // ContainerAttach attaches to logs according to the config passed in. See ContainerAttachConfig. func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerAttachConfig) error { keys := []byte{} @@ -43,6 +35,16 @@ func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerA return errors.NewRequestConflictError(err) } + cfg := stream.AttachConfig{ + UseStdin: c.UseStdin && container.Config.OpenStdin, + UseStdout: c.UseStdout, + UseStderr: c.UseStderr, + TTY: container.Config.Tty, + CloseStdin: container.Config.StdinOnce, + DetachKeys: keys, + } + container.StreamConfig.AttachStreams(&cfg) + inStream, outStream, errStream, err := c.GetStreams() if err != nil { return err @@ -54,48 +56,51 @@ func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerA outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) } - var cfg containerAttachConfig - - if c.UseStdin { - cfg.stdin = inStream + if cfg.UseStdin { + cfg.Stdin = inStream } - if c.UseStdout { - cfg.stdout = outStream + if cfg.UseStdout { + cfg.Stdout = outStream } - if c.UseStderr { - cfg.stderr = errStream + if cfg.UseStderr { + cfg.Stderr = errStream } - cfg.showHistory = c.Logs - cfg.stream = c.Stream - cfg.detachKeys = keys - - if err := daemon.containerAttach(container, &cfg); err != nil { + if err := daemon.containerAttach(container, &cfg, c.Logs, c.Stream); err != nil { fmt.Fprintf(outStream, "Error attaching: %s\n", err) } return nil } // ContainerAttachRaw attaches the provided streams to the container's stdio -func (daemon *Daemon) ContainerAttachRaw(prefixOrName string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool) error { +func (daemon *Daemon) ContainerAttachRaw(prefixOrName string, stdin io.ReadCloser, stdout, stderr io.Writer, doStream bool) error { container, err := daemon.GetContainer(prefixOrName) if err != nil { return err } - cfg := &containerAttachConfig{ - stdin: stdin, - stdout: stdout, - stderr: stderr, - stream: stream, + cfg := stream.AttachConfig{ + UseStdin: stdin != nil && container.Config.OpenStdin, + UseStdout: stdout != nil, + UseStderr: stderr != nil, + TTY: container.Config.Tty, + CloseStdin: container.Config.StdinOnce, + } + container.StreamConfig.AttachStreams(&cfg) + if cfg.UseStdin { + cfg.Stdin = stdin } - return daemon.containerAttach(container, cfg) + if cfg.UseStdout { + cfg.Stdout = stdout + } + if cfg.UseStderr { + cfg.Stderr = stderr + } + + return daemon.containerAttach(container, &cfg, false, doStream) } -func (daemon *Daemon) containerAttach(c *container.Container, cfg *containerAttachConfig) error { - stdin := cfg.stdin - stdout := cfg.stdout - stderr := cfg.stderr - if cfg.showHistory { +func (daemon *Daemon) containerAttach(c *container.Container, cfg *stream.AttachConfig, logs, doStream bool) error { + if logs { logDriver, err := daemon.getLogger(c) if err != nil { return err @@ -113,11 +118,11 @@ func (daemon *Daemon) containerAttach(c *container.Container, cfg *containerAtta if !ok { break LogLoop } - if msg.Source == "stdout" && stdout != nil { - stdout.Write(msg.Line) + if msg.Source == "stdout" && cfg.Stdout != nil { + cfg.Stdout.Write(msg.Line) } - if msg.Source == "stderr" && stderr != nil { - stderr.Write(msg.Line) + if msg.Source == "stderr" && cfg.Stderr != nil { + cfg.Stderr.Write(msg.Line) } case err := <-logs.Err: logrus.Errorf("Error streaming logs: %v", err) @@ -128,19 +133,18 @@ func (daemon *Daemon) containerAttach(c *container.Container, cfg *containerAtta daemon.LogContainerEvent(c, "attach") - if !cfg.stream { + if !doStream { return nil } - var stdinPipe io.ReadCloser - if stdin != nil { + if cfg.Stdin != nil { r, w := io.Pipe() - go func() { + go func(stdin io.ReadCloser) { defer w.Close() defer logrus.Debug("Closing buffered stdin pipe") io.Copy(w, stdin) - }() - stdinPipe = r + }(cfg.Stdin) + cfg.Stdin = r } waitChan := make(chan struct{}) @@ -154,14 +158,8 @@ func (daemon *Daemon) containerAttach(c *container.Container, cfg *containerAtta }() } - aCfg := &stream.AttachConfig{ - Stdin: stdinPipe, - Stdout: stdout, - Stderr: stderr, - DetachKeys: cfg.detachKeys, - } - - err := <-c.Attach(aCfg) + ctx := c.InitAttachContext() + err := <-c.StreamConfig.CopyStreams(ctx, cfg) if err != nil { if _, ok := err.(stream.DetachError); ok { daemon.LogContainerEvent(c, "detach") |