Browse Source

Change Console to Terminal

Move creation and attach to driver
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
Michael Crosby 11 years ago
parent
commit
1e74287698
7 changed files with 159 additions and 161 deletions
  1. 10 17
      container.go
  2. 1 1
      execdriver/chroot/driver.go
  3. 0 137
      execdriver/console.go
  4. 3 3
      execdriver/driver.go
  5. 6 1
      execdriver/lxc/driver.go
  6. 137 0
      execdriver/term.go
  7. 2 2
      runtime.go

+ 10 - 17
container.go

@@ -55,7 +55,6 @@ type Container struct {
 	Driver         string
 
 	command   *execdriver.Command
-	console   execdriver.Console
 	stdout    *utils.WriteBroadcaster
 	stderr    *utils.WriteBroadcaster
 	stdin     io.ReadCloser
@@ -531,6 +530,9 @@ func (container *Container) Start() (err error) {
 	}
 
 	populateCommand(container)
+	if err := execdriver.NewTerminal(container.command); err != nil {
+		return err
+	}
 
 	// Setup logging of stdout and stderr to disk
 	if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
@@ -541,16 +543,6 @@ func (container *Container) Start() (err error) {
 	}
 	container.waitLock = make(chan struct{})
 
-	container.console, err = execdriver.NewConsole(
-		container.stdin, container.stdout, container.stderr,
-		container.Config.OpenStdin, container.Config.Tty)
-	if err != nil {
-		return err
-	}
-	if err := container.console.AttachTo(container.command); err != nil {
-		return err
-	}
-
 	callbackLock := make(chan struct{})
 	callback := func(command *execdriver.Command) {
 		container.State.SetRunning(command.Pid())
@@ -790,7 +782,8 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
 		populateCommand(container)
 		err = container.runtime.RestoreCommand(container)
 	} else {
-		exitCode, err = container.runtime.Run(container, callback)
+		pipes := execdriver.NewPipes(container.stdin, container.stdout, container.stderr, container.Config.OpenStdin)
+		exitCode, err = container.runtime.Run(container, pipes, callback)
 	}
 
 	if err != nil {
@@ -845,9 +838,9 @@ func (container *Container) cleanup() {
 	if err := container.stderr.Close(); err != nil {
 		utils.Errorf("%s: Error close stderr: %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)
+	if container.command.Terminal != nil {
+		if err := container.command.Terminal.Close(); err != nil {
+			utils.Errorf("%s: Error closing terminal: %s", container.ID, err)
 		}
 	}
 
@@ -939,7 +932,7 @@ func (container *Container) Wait() int {
 }
 
 func (container *Container) Resize(h, w int) error {
-	return container.console.Resize(h, w)
+	return container.command.Terminal.Resize(h, w)
 }
 
 func (container *Container) ExportRw() (archive.Archive, error) {
@@ -1143,7 +1136,7 @@ func (container *Container) Exposes(p nat.Port) bool {
 }
 
 func (container *Container) GetPtyMaster() (*os.File, error) {
-	ttyConsole, ok := container.console.(*execdriver.TtyConsole)
+	ttyConsole, ok := container.command.Terminal.(*execdriver.TtyConsole)
 	if !ok {
 		return nil, ErrNoTTY
 	}

+ 1 - 1
execdriver/chroot/driver.go

@@ -37,7 +37,7 @@ func NewDriver() (*driver, error) {
 	return &driver{}, nil
 }
 
-func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) {
+func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
 	params := []string{
 		"chroot",
 		c.Rootfs,

+ 0 - 137
execdriver/console.go

@@ -1,137 +0,0 @@
-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
-}

+ 3 - 3
execdriver/driver.go

@@ -58,7 +58,7 @@ type Info interface {
 }
 
 type Driver interface {
-	Run(c *Command, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
+	Run(c *Command, pipes *Pipes, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
 	Kill(c *Command, sig int) error
 	Restore(c *Command) error                     // Wait and try to re-attach on an out of process command
 	Name() string                                 // Driver name
@@ -82,7 +82,6 @@ type Resources struct {
 }
 
 // Process wrapps an os/exec.Cmd to add more metadata
-// TODO: Rename to Command
 type Command struct {
 	exec.Cmd `json:"-"`
 
@@ -100,7 +99,8 @@ type Command struct {
 	Config     []string   `json:"config"`  //  generic values that specific drivers can consume
 	Resources  *Resources `json:"resources"`
 
-	Console string `json:"-"`
+	Terminal Term   `json:"-"`
+	Console  string `json:"-"`
 }
 
 // Return the pid of the process

+ 6 - 1
execdriver/lxc/driver.go

@@ -76,7 +76,12 @@ func (d *driver) Name() string {
 	return fmt.Sprintf("%s-%s", DriverName, version)
 }
 
-func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) {
+func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
+	if c.Terminal != nil {
+		if err := c.Terminal.Attach(pipes); err != nil {
+			return -1, err
+		}
+	}
 	configPath, err := d.generateLXCConfig(c)
 	if err != nil {
 		return -1, err

+ 137 - 0
execdriver/term.go

@@ -0,0 +1,137 @@
+package execdriver
+
+import (
+	"github.com/dotcloud/docker/pkg/term"
+	"github.com/kr/pty"
+	"io"
+	"os"
+)
+
+type Term interface {
+	io.Closer
+	Resize(height, width int) error
+	Attach(pipes *Pipes) error
+}
+
+type Pipes struct {
+	Stdin          io.ReadCloser
+	Stdout, Stderr io.WriteCloser
+}
+
+func NewPipes(stdin io.ReadCloser, stdout, stderr io.WriteCloser, useStdin bool) *Pipes {
+	p := &Pipes{
+		Stdout: stdout,
+		Stderr: stderr,
+	}
+	if useStdin {
+		p.Stdin = stdin
+	}
+	return p
+}
+
+func NewTerminal(command *Command) error {
+	var (
+		term Term
+		err  error
+	)
+	if command.Tty {
+		term, err = NewTtyConsole(command)
+	} else {
+		term, err = NewStdConsole(command)
+	}
+	if err != nil {
+		return err
+	}
+	command.Terminal = term
+	return nil
+}
+
+type TtyConsole struct {
+	command *Command
+	Master  *os.File
+	Slave   *os.File
+}
+
+func NewTtyConsole(command *Command) (*TtyConsole, error) {
+	ptyMaster, ptySlave, err := pty.Open()
+	if err != nil {
+		return nil, err
+	}
+	tty := &TtyConsole{
+		Master:  ptyMaster,
+		Slave:   ptySlave,
+		command: command,
+	}
+	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) Attach(pipes *Pipes) error {
+	t.command.Stdout = t.Slave
+	t.command.Stderr = t.Slave
+
+	t.command.Console = t.Slave.Name()
+
+	go func() {
+		defer pipes.Stdout.Close()
+		io.Copy(pipes.Stdout, t.Master)
+	}()
+
+	if pipes.Stdin != nil {
+		t.command.Stdin = t.Slave
+		t.command.SysProcAttr.Setctty = true
+
+		go func() {
+			defer pipes.Stdin.Close()
+			io.Copy(t.Master, 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 {
+	command *Command
+}
+
+func NewStdConsole(command *Command) (*StdConsole, error) {
+	return &StdConsole{command}, nil
+}
+
+func (s *StdConsole) Attach(pipes *Pipes) error {
+	s.command.Stdout = pipes.Stdout
+	s.command.Stderr = pipes.Stderr
+
+	if pipes.Stdin != nil {
+		stdin, err := s.command.StdinPipe()
+		if err != nil {
+			return err
+		}
+
+		go func() {
+			defer stdin.Close()
+			io.Copy(stdin, 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
+}

+ 2 - 2
runtime.go

@@ -812,8 +812,8 @@ func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) {
 	}), nil
 }
 
-func (runtime *Runtime) Run(c *Container, startCallback execdriver.StartCallback) (int, error) {
-	return runtime.execDriver.Run(c.command, startCallback)
+func (runtime *Runtime) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
+	return runtime.execDriver.Run(c.command, pipes, startCallback)
 }
 
 func (runtime *Runtime) Kill(c *Container, sig int) error {