瀏覽代碼

Make tty term exec driver specific

lxc is special in that we cannot create the master outside of the
container without opening the slave because we have nothing to provide to the
cmd.  We have to open both then do the crazy setup on command right now instead of
passing the console path to lxc and telling it to open up that console.  we save a couple of
openfiles in the native driver because we can do this.
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@docker.com> (github: crosbymichael)
Michael Crosby 11 年之前
父節點
當前提交
0d67b420b5
共有 3 個文件被更改,包括 153 次插入84 次删除
  1. 86 2
      daemon/execdriver/lxc/driver.go
  2. 67 2
      daemon/execdriver/native/driver.go
  3. 0 80
      daemon/execdriver/termconsole.go

+ 86 - 2
daemon/execdriver/lxc/driver.go

@@ -3,6 +3,7 @@ package lxc
 import (
 	"encoding/json"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"log"
 	"os"
@@ -19,7 +20,9 @@ import (
 	"github.com/docker/libcontainer/label"
 	"github.com/docker/libcontainer/mount/nodes"
 	"github.com/dotcloud/docker/daemon/execdriver"
+	"github.com/dotcloud/docker/pkg/term"
 	"github.com/dotcloud/docker/utils"
+	"github.com/kr/pty"
 )
 
 const DriverName = "lxc"
@@ -78,10 +81,20 @@ func (d *driver) Name() string {
 }
 
 func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
-	if err := execdriver.SetTerminal(c, pipes); err != nil {
-		return -1, err
+	var (
+		term execdriver.Terminal
+		err  error
+	)
+
+	if c.Tty {
+		term, err = NewTtyConsole(c, pipes)
+	} else {
+		term, err = execdriver.NewStdConsole(c, pipes)
 	}
+	c.Terminal = term
+
 	c.Mounts = append(c.Mounts, execdriver.Mount{d.initPath, c.InitPath, false, true})
+
 	if err := d.generateEnvConfig(c); err != nil {
 		return -1, err
 	}
@@ -462,3 +475,74 @@ func (d *driver) generateEnvConfig(c *execdriver.Command) error {
 
 	return ioutil.WriteFile(p, data, 0600)
 }
+
+type TtyConsole struct {
+	MasterPty *os.File
+	SlavePty  *os.File
+}
+
+func NewTtyConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*TtyConsole, error) {
+	// lxc is special in that we cannot create the master outside of the container without
+	// opening the slave because we have nothing to provide to the cmd.  We have to open both then do
+	// the crazy setup on command right now instead of passing the console path to lxc and telling it
+	// to open up that console.  we save a couple of openfiles in the native driver because we can do
+	// this.
+	ptyMaster, ptySlave, err := pty.Open()
+	if err != nil {
+		return nil, err
+	}
+
+	tty := &TtyConsole{
+		MasterPty: ptyMaster,
+		SlavePty:  ptySlave,
+	}
+
+	if err := tty.AttachPipes(&command.Cmd, pipes); err != nil {
+		tty.Close()
+		return nil, err
+	}
+
+	command.Console = tty.SlavePty.Name()
+
+	return tty, nil
+}
+
+func (t *TtyConsole) Master() *os.File {
+	return t.MasterPty
+}
+
+func (t *TtyConsole) Resize(h, w int) error {
+	return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
+}
+
+func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error {
+	command.Stdout = t.SlavePty
+	command.Stderr = t.SlavePty
+
+	go func() {
+		if wb, ok := pipes.Stdout.(interface {
+			CloseWriters() error
+		}); ok {
+			defer wb.CloseWriters()
+		}
+
+		io.Copy(pipes.Stdout, t.MasterPty)
+	}()
+
+	if pipes.Stdin != nil {
+		command.Stdin = t.SlavePty
+		command.SysProcAttr.Setctty = true
+
+		go func() {
+			io.Copy(t.MasterPty, pipes.Stdin)
+
+			pipes.Stdin.Close()
+		}()
+	}
+	return nil
+}
+
+func (t *TtyConsole) Close() error {
+	t.SlavePty.Close()
+	return t.MasterPty.Close()
+}

+ 67 - 2
daemon/execdriver/native/driver.go

@@ -5,6 +5,7 @@ package native
 import (
 	"encoding/json"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -21,6 +22,7 @@ import (
 	"github.com/docker/libcontainer/syncpipe"
 	"github.com/dotcloud/docker/daemon/execdriver"
 	"github.com/dotcloud/docker/pkg/system"
+	"github.com/dotcloud/docker/pkg/term"
 )
 
 const (
@@ -96,9 +98,14 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
 		return -1, err
 	}
 
-	if err := execdriver.SetTerminal(c, pipes); err != nil {
-		return -1, err
+	var term execdriver.Terminal
+
+	if c.Tty {
+		term, err = NewTtyConsole(c, pipes)
+	} else {
+		term, err = execdriver.NewStdConsole(c, pipes)
 	}
+	c.Terminal = term
 
 	d.Lock()
 	d.activeContainers[c.ID] = &activeContainer{
@@ -272,3 +279,61 @@ func getEnv(key string, env []string) string {
 	}
 	return ""
 }
+
+type TtyConsole struct {
+	MasterPty *os.File
+}
+
+func NewTtyConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*TtyConsole, error) {
+	ptyMaster, console, err := system.CreateMasterAndConsole()
+	if err != nil {
+		return nil, err
+	}
+
+	tty := &TtyConsole{
+		MasterPty: ptyMaster,
+	}
+
+	if err := tty.AttachPipes(&command.Cmd, pipes); err != nil {
+		tty.Close()
+		return nil, err
+	}
+
+	command.Console = console
+
+	return tty, nil
+}
+
+func (t *TtyConsole) Master() *os.File {
+	return t.MasterPty
+}
+
+func (t *TtyConsole) Resize(h, w int) error {
+	return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
+}
+
+func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error {
+	go func() {
+		if wb, ok := pipes.Stdout.(interface {
+			CloseWriters() error
+		}); ok {
+			defer wb.CloseWriters()
+		}
+
+		io.Copy(pipes.Stdout, t.MasterPty)
+	}()
+
+	if pipes.Stdin != nil {
+		go func() {
+			io.Copy(t.MasterPty, pipes.Stdin)
+
+			pipes.Stdin.Close()
+		}()
+	}
+
+	return nil
+}
+
+func (t *TtyConsole) Close() error {
+	return t.MasterPty.Close()
+}

+ 0 - 80
daemon/execdriver/termconsole.go

@@ -2,89 +2,9 @@ package execdriver
 
 import (
 	"io"
-	"os"
 	"os/exec"
-
-	"github.com/dotcloud/docker/pkg/system"
-	"github.com/dotcloud/docker/pkg/term"
 )
 
-func SetTerminal(command *Command, pipes *Pipes) error {
-	var (
-		term Terminal
-		err  error
-	)
-
-	if command.Tty {
-		term, err = NewTtyConsole(command, pipes)
-	} else {
-		term, err = NewStdConsole(command, pipes)
-	}
-
-	if err != nil {
-		return err
-	}
-
-	command.Terminal = term
-
-	return nil
-}
-
-type TtyConsole struct {
-	MasterPty *os.File
-}
-
-func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) {
-	ptyMaster, console, err := system.CreateMasterAndConsole()
-	if err != nil {
-		return nil, err
-	}
-
-	tty := &TtyConsole{
-		MasterPty: ptyMaster,
-	}
-
-	if err := tty.AttachPipes(&command.Cmd, pipes); err != nil {
-		tty.Close()
-		return nil, err
-	}
-	command.Console = console
-
-	return tty, nil
-}
-
-func (t *TtyConsole) Master() *os.File {
-	return t.MasterPty
-}
-
-func (t *TtyConsole) Resize(h, w int) error {
-	return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
-}
-
-func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error {
-	go func() {
-		if wb, ok := pipes.Stdout.(interface {
-			CloseWriters() error
-		}); ok {
-			defer wb.CloseWriters()
-		}
-		io.Copy(pipes.Stdout, t.MasterPty)
-	}()
-
-	if pipes.Stdin != nil {
-		go func() {
-			defer pipes.Stdin.Close()
-			io.Copy(t.MasterPty, pipes.Stdin)
-		}()
-	}
-
-	return nil
-}
-
-func (t *TtyConsole) Close() error {
-	return t.MasterPty.Close()
-}
-
 type StdConsole struct {
 }