ContainerAttach attaches to logs according to the config passed in. See ContainerAttachConfig.
(prefixOrName string, req *backend.ContainerAttachConfig)
| 21 | |
| 22 | // ContainerAttach attaches to logs according to the config passed in. See ContainerAttachConfig. |
| 23 | func (daemon *Daemon) ContainerAttach(prefixOrName string, req *backend.ContainerAttachConfig) error { |
| 24 | keys := []byte{} |
| 25 | var err error |
| 26 | if req.DetachKeys != "" { |
| 27 | keys, err = term.ToBytes(req.DetachKeys) |
| 28 | if err != nil { |
| 29 | return errdefs.InvalidParameter(errors.Errorf("Invalid detach keys (%s) provided", req.DetachKeys)) |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | ctr, err := daemon.GetContainer(prefixOrName) |
| 34 | if err != nil { |
| 35 | return err |
| 36 | } |
| 37 | if ctr.State.IsPaused() { |
| 38 | return errdefs.Conflict(fmt.Errorf("container %s is paused, unpause the container before attach", prefixOrName)) |
| 39 | } |
| 40 | if ctr.State.IsRestarting() { |
| 41 | return errdefs.Conflict(fmt.Errorf("container %s is restarting, wait until the container is running", prefixOrName)) |
| 42 | } |
| 43 | |
| 44 | cfg := stream.AttachConfig{ |
| 45 | UseStdin: req.UseStdin, |
| 46 | UseStdout: req.UseStdout, |
| 47 | UseStderr: req.UseStderr, |
| 48 | TTY: ctr.Config.Tty, |
| 49 | CloseStdin: ctr.Config.StdinOnce, |
| 50 | DetachKeys: keys, |
| 51 | } |
| 52 | ctr.StreamConfig.AttachStreams(&cfg) |
| 53 | |
| 54 | clientCtx, closeNotify := context.WithCancel(context.Background()) |
| 55 | defer closeNotify() |
| 56 | go func() { |
| 57 | <-clientCtx.Done() |
| 58 | // The client has disconnected |
| 59 | // In this case we need to close the container's output streams so that the goroutines used to copy |
| 60 | // to the client streams are unblocked and can exit. |
| 61 | if cfg.CStdout != nil { |
| 62 | cfg.CStdout.Close() |
| 63 | } |
| 64 | if cfg.CStderr != nil { |
| 65 | cfg.CStderr.Close() |
| 66 | } |
| 67 | }() |
| 68 | |
| 69 | multiplexed := !ctr.Config.Tty && req.MuxStreams |
| 70 | inStream, outStream, errStream, err := req.GetStreams(multiplexed, closeNotify) |
| 71 | if err != nil { |
| 72 | return err |
| 73 | } |
| 74 | |
| 75 | defer inStream.Close() |
| 76 | |
| 77 | if multiplexed { |
| 78 | errStream = stdcopymux.NewStdWriter(errStream, stdcopy.Stderr) |
| 79 | outStream = stdcopymux.NewStdWriter(outStream, stdcopy.Stdout) |
| 80 | } |
nothing calls this directly
no test coverage detected