Browse code

Move holdHijackConnection to the container package.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2016/08/30 02:36:29
Showing 10 changed files
... ...
@@ -57,31 +57,12 @@ func (cli *DockerCli) ConfigFile() *configfile.ConfigFile {
57 57
 	return cli.configFile
58 58
 }
59 59
 
60
-func (cli *DockerCli) setRawTerminal() error {
61
-	if err := cli.in.setRawTerminal(); err != nil {
62
-		return err
63
-	}
64
-	return cli.out.setRawTerminal()
65
-}
66
-
67
-func (cli *DockerCli) restoreTerminal(in io.Closer) error {
68
-	cli.in.restoreTerminal()
69
-	cli.out.restoreTerminal()
70
-	// WARNING: DO NOT REMOVE THE OS CHECK !!!
71
-	// For some reason this Close call blocks on darwin..
72
-	// As the client exists right after, simply discard the close
73
-	// until we find a better solution.
74
-	if in != nil && runtime.GOOS != "darwin" {
75
-		return in.Close()
76
-	}
77
-	return nil
78
-}
79
-
80 60
 // Initialize the dockerCli runs initialization that must happen after command
81 61
 // line flags are parsed.
82
-func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) (err error) {
62
+func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error {
83 63
 	cli.configFile = LoadDefaultConfigFile(cli.err)
84 64
 
65
+	var err error
85 66
 	cli.client, err = NewAPIClientFromFlags(opts.Common, cli.configFile)
86 67
 	if err != nil {
87 68
 		return err
... ...
@@ -110,7 +110,7 @@ func runAttach(dockerCli *client.DockerCli, opts *attachOptions) error {
110 110
 			logrus.Debugf("Error monitoring TTY size: %s", err)
111 111
 		}
112 112
 	}
113
-	if err := dockerCli.HoldHijackedConnection(ctx, c.Config.Tty, in, dockerCli.Out(), dockerCli.Err(), resp); err != nil {
113
+	if err := holdHijackedConnection(ctx, dockerCli, c.Config.Tty, in, dockerCli.Out(), dockerCli.Err(), resp); err != nil {
114 114
 		return err
115 115
 	}
116 116
 
... ...
@@ -10,9 +10,8 @@ import (
10 10
 	"github.com/docker/docker/api/client"
11 11
 	"github.com/docker/docker/api/types"
12 12
 	"github.com/docker/docker/cli"
13
-	"github.com/docker/docker/pkg/promise"
14 13
 	apiclient "github.com/docker/docker/client"
15
-	"github.com/docker/engine-api/types"
14
+	"github.com/docker/docker/pkg/promise"
16 15
 	"github.com/spf13/cobra"
17 16
 )
18 17
 
... ...
@@ -127,7 +126,7 @@ func runExec(dockerCli *client.DockerCli, opts *execOptions, container string, e
127 127
 	}
128 128
 	defer resp.Close()
129 129
 	errCh = promise.Go(func() error {
130
-		return dockerCli.HoldHijackedConnection(ctx, execConfig.Tty, in, out, stderr, resp)
130
+		return holdHijackedConnection(ctx, dockerCli, execConfig.Tty, in, out, stderr, resp)
131 131
 	})
132 132
 
133 133
 	if execConfig.Tty && dockerCli.In().IsTerminal() {
134 134
new file mode 100644
... ...
@@ -0,0 +1,121 @@
0
+package container
1
+
2
+import (
3
+	"io"
4
+	"runtime"
5
+	"sync"
6
+
7
+	"github.com/Sirupsen/logrus"
8
+	"github.com/docker/docker/api/client"
9
+	"github.com/docker/docker/api/types"
10
+	"github.com/docker/docker/pkg/stdcopy"
11
+	"golang.org/x/net/context"
12
+)
13
+
14
+type streams interface {
15
+	In() *client.InStream
16
+	Out() *client.OutStream
17
+}
18
+
19
+// holdHijackedConnection handles copying input to and output from streams to the
20
+// connection
21
+func holdHijackedConnection(ctx context.Context, streams streams, tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
22
+	var (
23
+		err         error
24
+		restoreOnce sync.Once
25
+	)
26
+	if inputStream != nil && tty {
27
+		if err := setRawTerminal(streams); err != nil {
28
+			return err
29
+		}
30
+		defer func() {
31
+			restoreOnce.Do(func() {
32
+				restoreTerminal(streams, inputStream)
33
+			})
34
+		}()
35
+	}
36
+
37
+	receiveStdout := make(chan error, 1)
38
+	if outputStream != nil || errorStream != nil {
39
+		go func() {
40
+			// When TTY is ON, use regular copy
41
+			if tty && outputStream != nil {
42
+				_, err = io.Copy(outputStream, resp.Reader)
43
+				// we should restore the terminal as soon as possible once connection end
44
+				// so any following print messages will be in normal type.
45
+				if inputStream != nil {
46
+					restoreOnce.Do(func() {
47
+						restoreTerminal(streams, inputStream)
48
+					})
49
+				}
50
+			} else {
51
+				_, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader)
52
+			}
53
+
54
+			logrus.Debug("[hijack] End of stdout")
55
+			receiveStdout <- err
56
+		}()
57
+	}
58
+
59
+	stdinDone := make(chan struct{})
60
+	go func() {
61
+		if inputStream != nil {
62
+			io.Copy(resp.Conn, inputStream)
63
+			// we should restore the terminal as soon as possible once connection end
64
+			// so any following print messages will be in normal type.
65
+			if tty {
66
+				restoreOnce.Do(func() {
67
+					restoreTerminal(streams, inputStream)
68
+				})
69
+			}
70
+			logrus.Debug("[hijack] End of stdin")
71
+		}
72
+
73
+		if err := resp.CloseWrite(); err != nil {
74
+			logrus.Debugf("Couldn't send EOF: %s", err)
75
+		}
76
+		close(stdinDone)
77
+	}()
78
+
79
+	select {
80
+	case err := <-receiveStdout:
81
+		if err != nil {
82
+			logrus.Debugf("Error receiveStdout: %s", err)
83
+			return err
84
+		}
85
+	case <-stdinDone:
86
+		if outputStream != nil || errorStream != nil {
87
+			select {
88
+			case err := <-receiveStdout:
89
+				if err != nil {
90
+					logrus.Debugf("Error receiveStdout: %s", err)
91
+					return err
92
+				}
93
+			case <-ctx.Done():
94
+			}
95
+		}
96
+	case <-ctx.Done():
97
+	}
98
+
99
+	return nil
100
+}
101
+
102
+func setRawTerminal(streams streams) error {
103
+	if err := streams.In().SetRawTerminal(); err != nil {
104
+		return err
105
+	}
106
+	return streams.Out().SetRawTerminal()
107
+}
108
+
109
+func restoreTerminal(streams streams, in io.Closer) error {
110
+	streams.In().RestoreTerminal()
111
+	streams.Out().RestoreTerminal()
112
+	// WARNING: DO NOT REMOVE THE OS CHECK !!!
113
+	// For some reason this Close call blocks on darwin..
114
+	// As the client exists right after, simply discard the close
115
+	// until we find a better solution.
116
+	if in != nil && runtime.GOOS != "darwin" {
117
+		return in.Close()
118
+	}
119
+	return nil
120
+}
... ...
@@ -203,7 +203,7 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions,
203 203
 		defer resp.Close()
204 204
 
205 205
 		errCh = promise.Go(func() error {
206
-			errHijack := dockerCli.HoldHijackedConnection(ctx, config.Tty, in, out, cerr, resp)
206
+			errHijack := holdHijackedConnection(ctx, dockerCli, config.Tty, in, out, cerr, resp)
207 207
 			if errHijack == nil {
208 208
 				return errAttach
209 209
 			}
... ...
@@ -95,7 +95,7 @@ func runStart(dockerCli *client.DockerCli, opts *startOptions) error {
95 95
 		}
96 96
 		defer resp.Close()
97 97
 		cErr := promise.Go(func() error {
98
-			errHijack := dockerCli.HoldHijackedConnection(ctx, c.Config.Tty, in, dockerCli.Out(), dockerCli.Err(), resp)
98
+			errHijack := holdHijackedConnection(ctx, dockerCli, c.Config.Tty, in, dockerCli.Out(), dockerCli.Err(), resp)
99 99
 			if errHijack == nil {
100 100
 				return errAttach
101 101
 			}
... ...
@@ -9,13 +9,13 @@ import (
9 9
 
10 10
 	"github.com/Sirupsen/logrus"
11 11
 	"github.com/docker/docker/api/client"
12
+	"github.com/docker/docker/api/types"
13
+	apiclient "github.com/docker/docker/client"
12 14
 	"github.com/docker/docker/pkg/signal"
13
-	apiclient "github.com/docker/engine-api/client"
14
-	"github.com/docker/engine-api/types"
15 15
 	"golang.org/x/net/context"
16 16
 )
17 17
 
18
-// ResizeTtyTo resizes tty to specific height and width
18
+// resizeTtyTo resizes tty to specific height and width
19 19
 func resizeTtyTo(ctx context.Context, client apiclient.ContainerAPIClient, id string, height, width int, isExec bool) {
20 20
 	if height == 0 && width == 0 {
21 21
 		return
22 22
deleted file mode 100644
... ...
@@ -1,95 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"io"
5
-	"sync"
6
-
7
-	"golang.org/x/net/context"
8
-
9
-	"github.com/Sirupsen/logrus"
10
-	"github.com/docker/docker/api/types"
11
-	"github.com/docker/docker/pkg/stdcopy"
12
-)
13
-
14
-// HoldHijackedConnection handles copying input to and output from streams to the
15
-// connection
16
-func (cli *DockerCli) HoldHijackedConnection(ctx context.Context, tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
17
-	var (
18
-		err         error
19
-		restoreOnce sync.Once
20
-	)
21
-	if inputStream != nil && tty {
22
-		if err := cli.setRawTerminal(); err != nil {
23
-			return err
24
-		}
25
-		defer func() {
26
-			restoreOnce.Do(func() {
27
-				cli.restoreTerminal(inputStream)
28
-			})
29
-		}()
30
-	}
31
-
32
-	receiveStdout := make(chan error, 1)
33
-	if outputStream != nil || errorStream != nil {
34
-		go func() {
35
-			// When TTY is ON, use regular copy
36
-			if tty && outputStream != nil {
37
-				_, err = io.Copy(outputStream, resp.Reader)
38
-				// we should restore the terminal as soon as possible once connection end
39
-				// so any following print messages will be in normal type.
40
-				if inputStream != nil {
41
-					restoreOnce.Do(func() {
42
-						cli.restoreTerminal(inputStream)
43
-					})
44
-				}
45
-			} else {
46
-				_, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader)
47
-			}
48
-
49
-			logrus.Debug("[hijack] End of stdout")
50
-			receiveStdout <- err
51
-		}()
52
-	}
53
-
54
-	stdinDone := make(chan struct{})
55
-	go func() {
56
-		if inputStream != nil {
57
-			io.Copy(resp.Conn, inputStream)
58
-			// we should restore the terminal as soon as possible once connection end
59
-			// so any following print messages will be in normal type.
60
-			if tty {
61
-				restoreOnce.Do(func() {
62
-					cli.restoreTerminal(inputStream)
63
-				})
64
-			}
65
-			logrus.Debug("[hijack] End of stdin")
66
-		}
67
-
68
-		if err := resp.CloseWrite(); err != nil {
69
-			logrus.Debugf("Couldn't send EOF: %s", err)
70
-		}
71
-		close(stdinDone)
72
-	}()
73
-
74
-	select {
75
-	case err := <-receiveStdout:
76
-		if err != nil {
77
-			logrus.Debugf("Error receiveStdout: %s", err)
78
-			return err
79
-		}
80
-	case <-stdinDone:
81
-		if outputStream != nil || errorStream != nil {
82
-			select {
83
-			case err := <-receiveStdout:
84
-				if err != nil {
85
-					logrus.Debugf("Error receiveStdout: %s", err)
86
-					return err
87
-				}
88
-			case <-ctx.Done():
89
-			}
90
-		}
91
-	case <-ctx.Done():
92
-	}
93
-
94
-	return nil
95
-}
... ...
@@ -36,7 +36,8 @@ func (i *InStream) IsTerminal() bool {
36 36
 	return i.isTerminal
37 37
 }
38 38
 
39
-func (i *InStream) setRawTerminal() (err error) {
39
+// SetRawTerminal sets raw mode on the input terminal
40
+func (i *InStream) SetRawTerminal() (err error) {
40 41
 	if os.Getenv("NORAW") != "" || !i.isTerminal {
41 42
 		return nil
42 43
 	}
... ...
@@ -44,7 +45,8 @@ func (i *InStream) setRawTerminal() (err error) {
44 44
 	return err
45 45
 }
46 46
 
47
-func (i *InStream) restoreTerminal() {
47
+// RestoreTerminal restores normal mode to the terminal
48
+func (i *InStream) RestoreTerminal() {
48 49
 	if i.state != nil {
49 50
 		term.RestoreTerminal(i.fd, i.state)
50 51
 	}
... ...
@@ -31,7 +31,8 @@ func (o *OutStream) IsTerminal() bool {
31 31
 	return o.isTerminal
32 32
 }
33 33
 
34
-func (o *OutStream) setRawTerminal() (err error) {
34
+// SetRawTerminal sets raw mode on the output terminal
35
+func (o *OutStream) SetRawTerminal() (err error) {
35 36
 	if os.Getenv("NORAW") != "" || !o.isTerminal {
36 37
 		return nil
37 38
 	}
... ...
@@ -39,7 +40,8 @@ func (o *OutStream) setRawTerminal() (err error) {
39 39
 	return err
40 40
 }
41 41
 
42
-func (o *OutStream) restoreTerminal() {
42
+// RestoreTerminal restores normal mode to the terminal
43
+func (o *OutStream) RestoreTerminal() {
43 44
 	if o.state != nil {
44 45
 		term.RestoreTerminal(o.fd, o.state)
45 46
 	}