github.com/akerouanton/docker@v1.11.0-rc3/daemon/attach.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "io" 6 "time" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/docker/api/types/backend" 10 "github.com/docker/docker/container" 11 "github.com/docker/docker/daemon/logger" 12 "github.com/docker/docker/errors" 13 "github.com/docker/docker/pkg/stdcopy" 14 ) 15 16 // ContainerAttach attaches to logs according to the config passed in. See ContainerAttachConfig. 17 func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerAttachConfig) error { 18 container, err := daemon.GetContainer(prefixOrName) 19 if err != nil { 20 return err 21 } 22 if container.IsPaused() { 23 err := fmt.Errorf("Container %s is paused. Unpause the container before attach", prefixOrName) 24 return errors.NewRequestConflictError(err) 25 } 26 27 inStream, outStream, errStream, err := c.GetStreams() 28 if err != nil { 29 return err 30 } 31 defer inStream.Close() 32 33 if !container.Config.Tty && c.MuxStreams { 34 errStream = stdcopy.NewStdWriter(errStream, stdcopy.Stderr) 35 outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) 36 } 37 38 var stdin io.ReadCloser 39 var stdout, stderr io.Writer 40 41 if c.UseStdin { 42 stdin = inStream 43 } 44 if c.UseStdout { 45 stdout = outStream 46 } 47 if c.UseStderr { 48 stderr = errStream 49 } 50 51 if err := daemon.containerAttach(container, stdin, stdout, stderr, c.Logs, c.Stream, c.DetachKeys); err != nil { 52 fmt.Fprintf(outStream, "Error attaching: %s\n", err) 53 } 54 return nil 55 } 56 57 // ContainerAttachRaw attaches the provided streams to the container's stdio 58 func (daemon *Daemon) ContainerAttachRaw(prefixOrName string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool) error { 59 container, err := daemon.GetContainer(prefixOrName) 60 if err != nil { 61 return err 62 } 63 return daemon.containerAttach(container, stdin, stdout, stderr, false, stream, nil) 64 } 65 66 func (daemon *Daemon) containerAttach(container *container.Container, stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool, keys []byte) error { 67 if logs { 68 logDriver, err := daemon.getLogger(container) 69 if err != nil { 70 return err 71 } 72 cLog, ok := logDriver.(logger.LogReader) 73 if !ok { 74 return logger.ErrReadLogsNotSupported 75 } 76 logs := cLog.ReadLogs(logger.ReadConfig{Tail: -1}) 77 78 LogLoop: 79 for { 80 select { 81 case msg, ok := <-logs.Msg: 82 if !ok { 83 break LogLoop 84 } 85 if msg.Source == "stdout" && stdout != nil { 86 stdout.Write(msg.Line) 87 } 88 if msg.Source == "stderr" && stderr != nil { 89 stderr.Write(msg.Line) 90 } 91 case err := <-logs.Err: 92 logrus.Errorf("Error streaming logs: %v", err) 93 break LogLoop 94 } 95 } 96 } 97 98 daemon.LogContainerEvent(container, "attach") 99 100 //stream 101 if stream { 102 var stdinPipe io.ReadCloser 103 if stdin != nil { 104 r, w := io.Pipe() 105 go func() { 106 defer w.Close() 107 defer logrus.Debugf("Closing buffered stdin pipe") 108 io.Copy(w, stdin) 109 }() 110 stdinPipe = r 111 } 112 <-container.Attach(stdinPipe, stdout, stderr, keys) 113 // If we are in stdinonce mode, wait for the process to end 114 // otherwise, simply return 115 if container.Config.StdinOnce && !container.Config.Tty { 116 container.WaitStop(-1 * time.Second) 117 } 118 } 119 return nil 120 }