فهرست منبع

reuse same code for setting pipes in run/exec

This also moves `exec -i` test to _unix_test.go because it seems to need a
pty to reliably reproduce the behavior.

Signed-off-by: Daniel, Dao Quang Minh <dqminh89@gmail.com>
Daniel, Dao Quang Minh 10 سال پیش
والد
کامیت
ade8146aa8

+ 38 - 30
daemon/execdriver/native/driver.go

@@ -87,8 +87,6 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
 		return execdriver.ExitStatus{ExitCode: -1}, err
 	}
 
-	var term execdriver.Terminal
-
 	p := &libcontainer.Process{
 		Args: append([]string{c.ProcessConfig.Entrypoint}, c.ProcessConfig.Arguments...),
 		Env:  c.ProcessConfig.Env,
@@ -96,36 +94,9 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
 		User: c.ProcessConfig.User,
 	}
 
-	if c.ProcessConfig.Tty {
-		rootuid, err := container.HostUID()
-		if err != nil {
-			return execdriver.ExitStatus{ExitCode: -1}, err
-		}
-		cons, err := p.NewConsole(rootuid)
-		if err != nil {
-			return execdriver.ExitStatus{ExitCode: -1}, err
-		}
-		term, err = NewTtyConsole(cons, pipes, rootuid)
-	} else {
-		p.Stdout = pipes.Stdout
-		p.Stderr = pipes.Stderr
-		r, w, err := os.Pipe()
-		if err != nil {
-			return execdriver.ExitStatus{ExitCode: -1}, err
-		}
-		if pipes.Stdin != nil {
-			go func() {
-				io.Copy(w, pipes.Stdin)
-				w.Close()
-			}()
-			p.Stdin = r
-		}
-		term = &execdriver.StdConsole{}
-	}
-	if err != nil {
+	if err := setupPipes(container, &c.ProcessConfig, p, pipes); err != nil {
 		return execdriver.ExitStatus{ExitCode: -1}, err
 	}
-	c.ProcessConfig.Terminal = term
 
 	cont, err := d.factory.Create(c.ID, container)
 	if err != nil {
@@ -398,3 +369,40 @@ func (t *TtyConsole) AttachPipes(pipes *execdriver.Pipes) error {
 func (t *TtyConsole) Close() error {
 	return t.console.Close()
 }
+
+func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConfig, p *libcontainer.Process, pipes *execdriver.Pipes) error {
+	var term execdriver.Terminal
+	var err error
+
+	if processConfig.Tty {
+		rootuid, err := container.HostUID()
+		if err != nil {
+			return err
+		}
+		cons, err := p.NewConsole(rootuid)
+		if err != nil {
+			return err
+		}
+		term, err = NewTtyConsole(cons, pipes, rootuid)
+	} else {
+		p.Stdout = pipes.Stdout
+		p.Stderr = pipes.Stderr
+		r, w, err := os.Pipe()
+		if err != nil {
+			return err
+		}
+		if pipes.Stdin != nil {
+			go func() {
+				io.Copy(w, pipes.Stdin)
+				w.Close()
+			}()
+			p.Stdin = r
+		}
+		term = &execdriver.StdConsole{}
+	}
+	if err != nil {
+		return err
+	}
+	processConfig.Terminal = term
+	return nil
+}

+ 2 - 23
daemon/execdriver/native/exec.go

@@ -20,9 +20,6 @@ func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
 		return -1, fmt.Errorf("No active container exists with ID %s", c.ID)
 	}
 
-	var term execdriver.Terminal
-	var err error
-
 	p := &libcontainer.Process{
 		Args: append([]string{processConfig.Entrypoint}, processConfig.Arguments...),
 		Env:  c.ProcessConfig.Env,
@@ -34,29 +31,11 @@ func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
 		p.Capabilities = execdriver.GetAllCapabilities()
 	}
 
-	if processConfig.Tty {
-		config := active.Config()
-		rootuid, err := config.HostUID()
-		if err != nil {
-			return -1, err
-		}
-		cons, err := p.NewConsole(rootuid)
-		if err != nil {
-			return -1, err
-		}
-		term, err = NewTtyConsole(cons, pipes, rootuid)
-	} else {
-		p.Stdout = pipes.Stdout
-		p.Stderr = pipes.Stderr
-		p.Stdin = pipes.Stdin
-		term = &execdriver.StdConsole{}
-	}
-	if err != nil {
+	config := active.Config()
+	if err := setupPipes(&config, processConfig, p, pipes); err != nil {
 		return -1, err
 	}
 
-	processConfig.Terminal = term
-
 	if err := active.Start(p); err != nil {
 		return -1, err
 	}

+ 0 - 38
integration-cli/docker_cli_exec_test.go

@@ -38,44 +38,6 @@ func (s *DockerSuite) TestExec(c *check.C) {
 
 }
 
-func (s *DockerSuite) TestExecInteractiveStdinClose(c *check.C) {
-	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "busybox", "/bin/cat"))
-	if err != nil {
-		c.Fatal(err)
-	}
-
-	contId := strings.TrimSpace(out)
-
-	returnchan := make(chan struct{})
-
-	go func() {
-		var err error
-		cmd := exec.Command(dockerBinary, "exec", "-i", contId, "/bin/ls", "/")
-		cmd.Stdin = os.Stdin
-		if err != nil {
-			c.Fatal(err)
-		}
-
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			c.Fatal(err, string(out))
-		}
-
-		if string(out) == "" {
-			c.Fatalf("Output was empty, likely blocked by standard input")
-		}
-
-		returnchan <- struct{}{}
-	}()
-
-	select {
-	case <-returnchan:
-	case <-time.After(10 * time.Second):
-		c.Fatal("timed out running docker exec")
-	}
-
-}
-
 func (s *DockerSuite) TestExecInteractive(c *check.C) {
 
 	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top")

+ 47 - 0
integration-cli/docker_cli_exec_unix_test.go

@@ -0,0 +1,47 @@
+// +build !windows,!test_no_exec
+
+package main
+
+import (
+	"bytes"
+	"io"
+	"os/exec"
+	"strings"
+	"time"
+
+	"github.com/go-check/check"
+	"github.com/kr/pty"
+)
+
+// regression test for #12546
+func (s *DockerSuite) TestExecInteractiveStdinClose(c *check.C) {
+	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "busybox", "/bin/cat"))
+	if err != nil {
+		c.Fatal(err)
+	}
+	contId := strings.TrimSpace(out)
+
+	cmd := exec.Command(dockerBinary, "exec", "-i", contId, "echo", "-n", "hello")
+	p, err := pty.Start(cmd)
+	if err != nil {
+		c.Fatal(err)
+	}
+
+	b := bytes.NewBuffer(nil)
+	go io.Copy(b, p)
+
+	ch := make(chan error)
+	go func() { ch <- cmd.Wait() }()
+
+	select {
+	case err := <-ch:
+		if err != nil {
+			c.Errorf("cmd finished with error %v", err)
+		}
+		if output := b.String(); strings.TrimSpace(output) != "hello" {
+			c.Fatalf("Unexpected output %s", output)
+		}
+	case <-time.After(1 * time.Second):
+		c.Fatal("timed out running docker exec")
+	}
+}