Browse Source

Move console into execdriver
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby 11 years ago
parent
commit
8c783c1c13
4 changed files with 155 additions and 79 deletions
  1. 16 77
      container.go
  2. 137 0
      execdriver/console.go
  3. 1 1
      utils/utils.go
  4. 1 1
      utils/utils_test.go

+ 16 - 77
container.go

@@ -10,10 +10,8 @@ import (
 	"github.com/dotcloud/docker/graphdriver"
 	"github.com/dotcloud/docker/links"
 	"github.com/dotcloud/docker/nat"
-	"github.com/dotcloud/docker/pkg/term"
 	"github.com/dotcloud/docker/runconfig"
 	"github.com/dotcloud/docker/utils"
-	"github.com/kr/pty"
 	"io"
 	"io/ioutil"
 	"log"
@@ -57,11 +55,11 @@ type Container struct {
 	Driver         string
 
 	command   *execdriver.Command
+	console   execdriver.Console
 	stdout    *utils.WriteBroadcaster
 	stderr    *utils.WriteBroadcaster
 	stdin     io.ReadCloser
 	stdinPipe io.WriteCloser
-	ptyMaster io.Closer
 
 	runtime *Runtime
 
@@ -213,56 +211,6 @@ func (container *Container) generateEnvConfig(env []string) error {
 	return nil
 }
 
-func (container *Container) setupPty() error {
-	ptyMaster, ptySlave, err := pty.Open()
-	if err != nil {
-		return err
-	}
-	container.ptyMaster = ptyMaster
-	container.command.Stdout = ptySlave
-	container.command.Stderr = ptySlave
-	container.command.Console = ptySlave.Name()
-
-	// Copy the PTYs to our broadcasters
-	go func() {
-		defer container.stdout.CloseWriters()
-		utils.Debugf("startPty: begin of stdout pipe")
-		io.Copy(container.stdout, ptyMaster)
-		utils.Debugf("startPty: end of stdout pipe")
-	}()
-
-	// stdin
-	if container.Config.OpenStdin {
-		container.command.Stdin = ptySlave
-		container.command.SysProcAttr.Setctty = true
-		go func() {
-			defer container.stdin.Close()
-			utils.Debugf("startPty: begin of stdin pipe")
-			io.Copy(ptyMaster, container.stdin)
-			utils.Debugf("startPty: end of stdin pipe")
-		}()
-	}
-	return nil
-}
-
-func (container *Container) setupStd() error {
-	container.command.Stdout = container.stdout
-	container.command.Stderr = container.stderr
-	if container.Config.OpenStdin {
-		stdin, err := container.command.StdinPipe()
-		if err != nil {
-			return err
-		}
-		go func() {
-			defer stdin.Close()
-			utils.Debugf("start: begin of stdin pipe")
-			io.Copy(stdin, container.stdin)
-			utils.Debugf("start: end of stdin pipe")
-		}()
-	}
-	return nil
-}
-
 func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
 	var cStdout, cStderr io.ReadCloser
 
@@ -593,14 +541,13 @@ func (container *Container) Start() (err error) {
 	}
 	container.waitLock = make(chan struct{})
 
-	// Setuping pipes and/or Pty
-	var setup func() error
-	if container.Config.Tty {
-		setup = container.setupPty
-	} else {
-		setup = container.setupStd
+	container.console, err = execdriver.NewConsole(
+		container.stdin, container.stdout, container.stderr,
+		container.Config.OpenStdin, container.Config.Tty)
+	if err != nil {
+		return err
 	}
-	if err := setup(); err != nil {
+	if err := container.console.AttachTo(container.command); err != nil {
 		return err
 	}
 
@@ -887,22 +834,20 @@ func (container *Container) cleanup() {
 			link.Disable()
 		}
 	}
-
 	if container.Config.OpenStdin {
 		if err := container.stdin.Close(); err != nil {
 			utils.Errorf("%s: Error close stdin: %s", container.ID, err)
 		}
 	}
-	if err := container.stdout.CloseWriters(); err != nil {
+	if err := container.stdout.Close(); err != nil {
 		utils.Errorf("%s: Error close stdout: %s", container.ID, err)
 	}
-	if err := container.stderr.CloseWriters(); err != nil {
+	if err := container.stderr.Close(); err != nil {
 		utils.Errorf("%s: Error close stderr: %s", container.ID, err)
 	}
-
-	if container.ptyMaster != nil {
-		if err := container.ptyMaster.Close(); err != nil {
-			utils.Errorf("%s: Error closing Pty master: %s", container.ID, err)
+	if container.console != nil {
+		if err := container.console.Close(); err != nil {
+			utils.Errorf("%s: Error closing console: %s", container.ID, err)
 		}
 	}
 
@@ -994,11 +939,7 @@ func (container *Container) Wait() int {
 }
 
 func (container *Container) Resize(h, w int) error {
-	pty, ok := container.ptyMaster.(*os.File)
-	if !ok {
-		return fmt.Errorf("ptyMaster does not have Fd() method")
-	}
-	return term.SetWinsize(pty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
+	return container.console.Resize(h, w)
 }
 
 func (container *Container) ExportRw() (archive.Archive, error) {
@@ -1202,11 +1143,9 @@ func (container *Container) Exposes(p nat.Port) bool {
 }
 
 func (container *Container) GetPtyMaster() (*os.File, error) {
-	if container.ptyMaster == nil {
+	ttyConsole, ok := container.console.(*execdriver.TtyConsole)
+	if !ok {
 		return nil, ErrNoTTY
 	}
-	if pty, ok := container.ptyMaster.(*os.File); ok {
-		return pty, nil
-	}
-	return nil, ErrNotATTY
+	return ttyConsole.Master, nil
 }

+ 137 - 0
execdriver/console.go

@@ -0,0 +1,137 @@
+package execdriver
+
+import (
+	"github.com/dotcloud/docker/pkg/term"
+	"github.com/kr/pty"
+	"io"
+	"os"
+)
+
+type Console interface {
+	io.Closer
+	Resize(height, width int) error
+	AttachTo(command *Command) error
+}
+
+type pipes struct {
+	Stdin          io.ReadCloser
+	Stdout, Stderr io.WriteCloser
+}
+
+func (p *pipes) Close() error {
+	if p.Stderr != nil {
+		p.Stdin.Close()
+	}
+	if p.Stdout != nil {
+		p.Stdout.Close()
+	}
+	if p.Stderr != nil {
+		p.Stderr.Close()
+	}
+	return nil
+}
+
+func NewConsole(stdin io.ReadCloser, stdout, stderr io.WriteCloser, useStdin, tty bool) (Console, error) {
+	p := &pipes{
+		Stdout: stdout,
+		Stderr: stderr,
+	}
+	if useStdin {
+		p.Stdin = stdin
+	}
+	if tty {
+		return NewTtyConsole(p)
+	}
+	return NewStdConsole(p)
+}
+
+type TtyConsole struct {
+	Master *os.File
+	Slave  *os.File
+	pipes  *pipes
+}
+
+func NewTtyConsole(p *pipes) (*TtyConsole, error) {
+	ptyMaster, ptySlave, err := pty.Open()
+	if err != nil {
+		return nil, err
+	}
+	tty := &TtyConsole{
+		Master: ptyMaster,
+		Slave:  ptySlave,
+		pipes:  p,
+	}
+	return tty, nil
+}
+
+func (t *TtyConsole) Resize(h, w int) error {
+	return term.SetWinsize(t.Master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
+
+}
+
+func (t *TtyConsole) AttachTo(command *Command) error {
+	command.Stdout = t.Slave
+	command.Stderr = t.Slave
+
+	command.Console = t.Slave.Name()
+
+	go func() {
+		defer t.pipes.Stdout.Close()
+		io.Copy(t.pipes.Stdout, t.Master)
+	}()
+
+	if t.pipes.Stdin != nil {
+		command.Stdin = t.Slave
+		command.SysProcAttr.Setctty = true
+
+		go func() {
+			defer t.pipes.Stdin.Close()
+			io.Copy(t.Master, t.pipes.Stdin)
+		}()
+	}
+	return nil
+}
+
+func (t *TtyConsole) Close() error {
+	err := t.Slave.Close()
+	if merr := t.Master.Close(); err == nil {
+		err = merr
+	}
+	return err
+}
+
+type StdConsole struct {
+	pipes *pipes
+}
+
+func NewStdConsole(p *pipes) (*StdConsole, error) {
+	return &StdConsole{p}, nil
+}
+
+func (s *StdConsole) AttachTo(command *Command) error {
+	command.Stdout = s.pipes.Stdout
+	command.Stderr = s.pipes.Stderr
+
+	if s.pipes.Stdin != nil {
+		stdin, err := command.StdinPipe()
+		if err != nil {
+			return err
+		}
+
+		go func() {
+			defer stdin.Close()
+			io.Copy(stdin, s.pipes.Stdin)
+		}()
+	}
+	return nil
+}
+
+func (s *StdConsole) Resize(h, w int) error {
+	// we do not need to reside a non tty
+	return nil
+}
+
+func (s *StdConsole) Close() error {
+	// nothing to close here
+	return nil
+}

+ 1 - 1
utils/utils.go

@@ -388,7 +388,7 @@ func (w *WriteBroadcaster) Write(p []byte) (n int, err error) {
 	return len(p), nil
 }
 
-func (w *WriteBroadcaster) CloseWriters() error {
+func (w *WriteBroadcaster) Close() error {
 	w.Lock()
 	defer w.Unlock()
 	for sw := range w.writers {

+ 1 - 1
utils/utils_test.go

@@ -110,7 +110,7 @@ func TestWriteBroadcaster(t *testing.T) {
 		t.Errorf("Buffer contains %v", bufferC.String())
 	}
 
-	writer.CloseWriters()
+	writer.Close()
 }
 
 type devNullCloser int