summaryrefslogtreecommitdiff
path: root/daemon/attach.go
diff options
context:
space:
mode:
authorJim Minter <jminter@redhat.com>2017-01-30 13:49:22 +0100
committerJim Minter <jminter@redhat.com>2017-02-01 09:01:36 +0000
commit84d6240cfe7cc66a7d3f6ac78ea6faad0e3108b9 (patch)
tree7b4ff738870a7269d05e5a584c957684197320c0 /daemon/attach.go
parent48dd90d3985889ca008faa3b041bf31d2ada95c5 (diff)
downloaddocker-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.go100
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")