1
0
mirror of https://github.com/docker/cli.git synced 2026-01-23 15:21:32 +03:00

Move attach code to stream package

This cleans up attach a little bit, and moves it out of the container
package.
Really `AttachStream` is a method on `*stream.Config`, so moved if from
a package level function to one bound to `Config`.
In addition, uses a config struct rather than passing around tons and
tons of arguments.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Upstream-commit: 2ddec97545f4c5834cfbc163c0168ce1d5826ba2
Component: engine
This commit is contained in:
Brian Goff
2017-01-19 11:02:51 -05:00
parent 58b37acff7
commit 8ae3be5ef9
5 changed files with 296 additions and 223 deletions

View File

@@ -9,11 +9,20 @@ import (
"github.com/docker/docker/api/errors"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/container"
"github.com/docker/docker/container/stream"
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/pkg/stdcopy"
"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{}
@@ -45,20 +54,23 @@ func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerA
outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
}
var stdin io.ReadCloser
var stdout, stderr io.Writer
var cfg containerAttachConfig
if c.UseStdin {
stdin = inStream
cfg.stdin = inStream
}
if c.UseStdout {
stdout = outStream
cfg.stdout = outStream
}
if c.UseStderr {
stderr = errStream
cfg.stderr = errStream
}
if err := daemon.containerAttach(container, stdin, stdout, stderr, c.Logs, c.Stream, keys); err != nil {
cfg.showHistory = c.Logs
cfg.stream = c.Stream
cfg.detachKeys = keys
if err := daemon.containerAttach(container, &cfg); err != nil {
fmt.Fprintf(outStream, "Error attaching: %s\n", err)
}
return nil
@@ -70,11 +82,20 @@ func (daemon *Daemon) ContainerAttachRaw(prefixOrName string, stdin io.ReadClose
if err != nil {
return err
}
return daemon.containerAttach(container, stdin, stdout, stderr, false, stream, nil)
cfg := &containerAttachConfig{
stdin: stdin,
stdout: stdout,
stderr: stderr,
stream: stream,
}
return daemon.containerAttach(container, cfg)
}
func (daemon *Daemon) containerAttach(c *container.Container, stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool, keys []byte) error {
if logs {
func (daemon *Daemon) containerAttach(c *container.Container, cfg *containerAttachConfig) error {
stdin := cfg.stdin
stdout := cfg.stdout
stderr := cfg.stderr
if cfg.showHistory {
logDriver, err := daemon.getLogger(c)
if err != nil {
return err
@@ -107,41 +128,47 @@ func (daemon *Daemon) containerAttach(c *container.Container, stdin io.ReadClose
daemon.LogContainerEvent(c, "attach")
//stream
if stream {
var stdinPipe io.ReadCloser
if stdin != nil {
r, w := io.Pipe()
go func() {
defer w.Close()
defer logrus.Debug("Closing buffered stdin pipe")
io.Copy(w, stdin)
}()
stdinPipe = r
}
if !cfg.stream {
return nil
}
waitChan := make(chan struct{})
if c.Config.StdinOnce && !c.Config.Tty {
go func() {
c.WaitStop(-1 * time.Second)
close(waitChan)
}()
}
var stdinPipe io.ReadCloser
if stdin != nil {
r, w := io.Pipe()
go func() {
defer w.Close()
defer logrus.Debug("Closing buffered stdin pipe")
io.Copy(w, stdin)
}()
stdinPipe = r
}
err := <-c.Attach(stdinPipe, stdout, stderr, keys)
if err != nil {
if _, ok := err.(container.DetachError); ok {
daemon.LogContainerEvent(c, "detach")
} else {
logrus.Errorf("attach failed with error: %v", err)
}
}
// If we are in stdinonce mode, wait for the process to end
// otherwise, simply return
if c.Config.StdinOnce && !c.Config.Tty {
waitChan := make(chan struct{})
if c.Config.StdinOnce && !c.Config.Tty {
defer func() {
<-waitChan
}()
go func() {
c.WaitStop(-1 * time.Second)
close(waitChan)
}()
}
aCfg := &stream.AttachConfig{
Stdin: stdinPipe,
Stdout: stdout,
Stderr: stderr,
DetachKeys: cfg.detachKeys,
}
err := <-c.Attach(aCfg)
if err != nil {
if _, ok := err.(stream.DetachError); ok {
daemon.LogContainerEvent(c, "detach")
} else {
logrus.Errorf("attach failed with error: %v", err)
}
}
return nil
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/container"
"github.com/docker/docker/container/stream"
"github.com/docker/docker/daemon/exec"
"github.com/docker/docker/libcontainerd"
"github.com/docker/docker/pkg/pools"
@@ -209,7 +210,15 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R
return err
}
attachErr := container.AttachStreams(ctx, ec.StreamConfig, ec.OpenStdin, true, ec.Tty, cStdin, cStdout, cStderr, ec.DetachKeys)
attachConfig := &stream.AttachConfig{
TTY: ec.Tty,
Stdin: cStdin,
Stdout: cStdout,
Stderr: cStderr,
DetachKeys: ec.DetachKeys,
CloseStdin: true,
}
attachErr := ec.StreamConfig.Attach(ctx, attachConfig)
systemPid, err := d.containerd.AddProcess(ctx, c.ID, name, p, ec.InitializeStdio)
if err != nil {
@@ -233,7 +242,7 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R
return fmt.Errorf("context cancelled")
case err := <-attachErr:
if err != nil {
if _, ok := err.(container.DetachError); !ok {
if _, ok := err.(stream.DetachError); !ok {
return fmt.Errorf("exec attach failed with error: %v", err)
}
d.LogContainerEvent(c, "exec_detach")