Browse code

Move Attach from container to daemon

This moves the Attach method from the container to the daemon. This
method mostly supports the http attach logic and does not have anything
to do with the running of a container.
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/05/06 08:48:56
Showing 4 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,153 @@
0
+package daemon
1
+
2
+import (
3
+	"io"
4
+
5
+	"github.com/dotcloud/docker/utils"
6
+)
7
+
8
+func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
9
+	var (
10
+		cStdout, cStderr io.ReadCloser
11
+		nJobs            int
12
+		errors           = make(chan error, 3)
13
+	)
14
+
15
+	if stdin != nil && container.Config.OpenStdin {
16
+		nJobs += 1
17
+		if cStdin, err := container.StdinPipe(); err != nil {
18
+			errors <- err
19
+		} else {
20
+			go func() {
21
+				utils.Debugf("attach: stdin: begin")
22
+				defer utils.Debugf("attach: stdin: end")
23
+				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
24
+				if container.Config.StdinOnce && !container.Config.Tty {
25
+					defer cStdin.Close()
26
+				} else {
27
+					defer func() {
28
+						if cStdout != nil {
29
+							cStdout.Close()
30
+						}
31
+						if cStderr != nil {
32
+							cStderr.Close()
33
+						}
34
+					}()
35
+				}
36
+				if container.Config.Tty {
37
+					_, err = utils.CopyEscapable(cStdin, stdin)
38
+				} else {
39
+					_, err = io.Copy(cStdin, stdin)
40
+				}
41
+				if err == io.ErrClosedPipe {
42
+					err = nil
43
+				}
44
+				if err != nil {
45
+					utils.Errorf("attach: stdin: %s", err)
46
+				}
47
+				errors <- err
48
+			}()
49
+		}
50
+	}
51
+	if stdout != nil {
52
+		nJobs += 1
53
+		if p, err := container.StdoutPipe(); err != nil {
54
+			errors <- err
55
+		} else {
56
+			cStdout = p
57
+			go func() {
58
+				utils.Debugf("attach: stdout: begin")
59
+				defer utils.Debugf("attach: stdout: end")
60
+				// If we are in StdinOnce mode, then close stdin
61
+				if container.Config.StdinOnce && stdin != nil {
62
+					defer stdin.Close()
63
+				}
64
+				if stdinCloser != nil {
65
+					defer stdinCloser.Close()
66
+				}
67
+				_, err := io.Copy(stdout, cStdout)
68
+				if err == io.ErrClosedPipe {
69
+					err = nil
70
+				}
71
+				if err != nil {
72
+					utils.Errorf("attach: stdout: %s", err)
73
+				}
74
+				errors <- err
75
+			}()
76
+		}
77
+	} else {
78
+		go func() {
79
+			if stdinCloser != nil {
80
+				defer stdinCloser.Close()
81
+			}
82
+			if cStdout, err := container.StdoutPipe(); err != nil {
83
+				utils.Errorf("attach: stdout pipe: %s", err)
84
+			} else {
85
+				io.Copy(&utils.NopWriter{}, cStdout)
86
+			}
87
+		}()
88
+	}
89
+	if stderr != nil {
90
+		nJobs += 1
91
+		if p, err := container.StderrPipe(); err != nil {
92
+			errors <- err
93
+		} else {
94
+			cStderr = p
95
+			go func() {
96
+				utils.Debugf("attach: stderr: begin")
97
+				defer utils.Debugf("attach: stderr: end")
98
+				// If we are in StdinOnce mode, then close stdin
99
+				if container.Config.StdinOnce && stdin != nil {
100
+					defer stdin.Close()
101
+				}
102
+				if stdinCloser != nil {
103
+					defer stdinCloser.Close()
104
+				}
105
+				_, err := io.Copy(stderr, cStderr)
106
+				if err == io.ErrClosedPipe {
107
+					err = nil
108
+				}
109
+				if err != nil {
110
+					utils.Errorf("attach: stderr: %s", err)
111
+				}
112
+				errors <- err
113
+			}()
114
+		}
115
+	} else {
116
+		go func() {
117
+			if stdinCloser != nil {
118
+				defer stdinCloser.Close()
119
+			}
120
+
121
+			if cStderr, err := container.StderrPipe(); err != nil {
122
+				utils.Errorf("attach: stdout pipe: %s", err)
123
+			} else {
124
+				io.Copy(&utils.NopWriter{}, cStderr)
125
+			}
126
+		}()
127
+	}
128
+
129
+	return utils.Go(func() error {
130
+		defer func() {
131
+			if cStdout != nil {
132
+				cStdout.Close()
133
+			}
134
+			if cStderr != nil {
135
+				cStderr.Close()
136
+			}
137
+		}()
138
+
139
+		// FIXME: how to clean up the stdin goroutine without the unwanted side effect
140
+		// of closing the passed stdin? Add an intermediary io.Pipe?
141
+		for i := 0; i < nJobs; i += 1 {
142
+			utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
143
+			if err := <-errors; err != nil {
144
+				utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
145
+				return err
146
+			}
147
+			utils.Debugf("attach: job %d completed successfully", i+1)
148
+		}
149
+		utils.Debugf("attach: all jobs completed successfully")
150
+		return nil
151
+	})
152
+}
... ...
@@ -170,150 +170,6 @@ func (container *Container) WriteHostConfig() (err error) {
170 170
 	return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
171 171
 }
172 172
 
173
-func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
174
-	var cStdout, cStderr io.ReadCloser
175
-
176
-	var nJobs int
177
-	errors := make(chan error, 3)
178
-	if stdin != nil && container.Config.OpenStdin {
179
-		nJobs += 1
180
-		if cStdin, err := container.StdinPipe(); err != nil {
181
-			errors <- err
182
-		} else {
183
-			go func() {
184
-				utils.Debugf("attach: stdin: begin")
185
-				defer utils.Debugf("attach: stdin: end")
186
-				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
187
-				if container.Config.StdinOnce && !container.Config.Tty {
188
-					defer cStdin.Close()
189
-				} else {
190
-					defer func() {
191
-						if cStdout != nil {
192
-							cStdout.Close()
193
-						}
194
-						if cStderr != nil {
195
-							cStderr.Close()
196
-						}
197
-					}()
198
-				}
199
-				if container.Config.Tty {
200
-					_, err = utils.CopyEscapable(cStdin, stdin)
201
-				} else {
202
-					_, err = io.Copy(cStdin, stdin)
203
-				}
204
-				if err == io.ErrClosedPipe {
205
-					err = nil
206
-				}
207
-				if err != nil {
208
-					utils.Errorf("attach: stdin: %s", err)
209
-				}
210
-				errors <- err
211
-			}()
212
-		}
213
-	}
214
-	if stdout != nil {
215
-		nJobs += 1
216
-		if p, err := container.StdoutPipe(); err != nil {
217
-			errors <- err
218
-		} else {
219
-			cStdout = p
220
-			go func() {
221
-				utils.Debugf("attach: stdout: begin")
222
-				defer utils.Debugf("attach: stdout: end")
223
-				// If we are in StdinOnce mode, then close stdin
224
-				if container.Config.StdinOnce && stdin != nil {
225
-					defer stdin.Close()
226
-				}
227
-				if stdinCloser != nil {
228
-					defer stdinCloser.Close()
229
-				}
230
-				_, err := io.Copy(stdout, cStdout)
231
-				if err == io.ErrClosedPipe {
232
-					err = nil
233
-				}
234
-				if err != nil {
235
-					utils.Errorf("attach: stdout: %s", err)
236
-				}
237
-				errors <- err
238
-			}()
239
-		}
240
-	} else {
241
-		go func() {
242
-			if stdinCloser != nil {
243
-				defer stdinCloser.Close()
244
-			}
245
-			if cStdout, err := container.StdoutPipe(); err != nil {
246
-				utils.Errorf("attach: stdout pipe: %s", err)
247
-			} else {
248
-				io.Copy(&utils.NopWriter{}, cStdout)
249
-			}
250
-		}()
251
-	}
252
-	if stderr != nil {
253
-		nJobs += 1
254
-		if p, err := container.StderrPipe(); err != nil {
255
-			errors <- err
256
-		} else {
257
-			cStderr = p
258
-			go func() {
259
-				utils.Debugf("attach: stderr: begin")
260
-				defer utils.Debugf("attach: stderr: end")
261
-				// If we are in StdinOnce mode, then close stdin
262
-				if container.Config.StdinOnce && stdin != nil {
263
-					defer stdin.Close()
264
-				}
265
-				if stdinCloser != nil {
266
-					defer stdinCloser.Close()
267
-				}
268
-				_, err := io.Copy(stderr, cStderr)
269
-				if err == io.ErrClosedPipe {
270
-					err = nil
271
-				}
272
-				if err != nil {
273
-					utils.Errorf("attach: stderr: %s", err)
274
-				}
275
-				errors <- err
276
-			}()
277
-		}
278
-	} else {
279
-		go func() {
280
-			if stdinCloser != nil {
281
-				defer stdinCloser.Close()
282
-			}
283
-
284
-			if cStderr, err := container.StderrPipe(); err != nil {
285
-				utils.Errorf("attach: stdout pipe: %s", err)
286
-			} else {
287
-				io.Copy(&utils.NopWriter{}, cStderr)
288
-			}
289
-		}()
290
-	}
291
-
292
-	return utils.Go(func() error {
293
-		defer func() {
294
-			if cStdout != nil {
295
-				cStdout.Close()
296
-			}
297
-			if cStderr != nil {
298
-				cStderr.Close()
299
-			}
300
-		}()
301
-
302
-		// FIXME: how to clean up the stdin goroutine without the unwanted side effect
303
-		// of closing the passed stdin? Add an intermediary io.Pipe?
304
-		for i := 0; i < nJobs; i += 1 {
305
-			utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
306
-			if err := <-errors; err != nil {
307
-				utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
308
-				return err
309
-			}
310
-			utils.Debugf("attach: job %d completed successfully", i+1)
311
-		}
312
-		utils.Debugf("attach: all jobs completed successfully")
313
-		return nil
314
-	})
315
-}
316
-
317 173
 func populateCommand(c *Container, env []string) error {
318 174
 	var (
319 175
 		en      *execdriver.Network
... ...
@@ -6,12 +6,6 @@ import (
6 6
 	"encoding/json"
7 7
 	"errors"
8 8
 	"fmt"
9
-	"github.com/dotcloud/docker/archive"
10
-	"github.com/dotcloud/docker/daemon"
11
-	"github.com/dotcloud/docker/nat"
12
-	"github.com/dotcloud/docker/registry"
13
-	"github.com/dotcloud/docker/runconfig"
14
-	"github.com/dotcloud/docker/utils"
15 9
 	"io"
16 10
 	"io/ioutil"
17 11
 	"net/url"
... ...
@@ -22,6 +16,13 @@ import (
22 22
 	"regexp"
23 23
 	"sort"
24 24
 	"strings"
25
+
26
+	"github.com/dotcloud/docker/archive"
27
+	"github.com/dotcloud/docker/daemon"
28
+	"github.com/dotcloud/docker/nat"
29
+	"github.com/dotcloud/docker/registry"
30
+	"github.com/dotcloud/docker/runconfig"
31
+	"github.com/dotcloud/docker/utils"
25 32
 )
26 33
 
27 34
 var (
... ...
@@ -644,10 +645,9 @@ func (b *buildFile) create() (*daemon.Container, error) {
644 644
 
645 645
 func (b *buildFile) run(c *daemon.Container) error {
646 646
 	var errCh chan error
647
-
648 647
 	if b.verbose {
649 648
 		errCh = utils.Go(func() error {
650
-			return <-c.Attach(nil, nil, b.outStream, b.errStream)
649
+			return <-b.daemon.Attach(c, nil, nil, b.outStream, b.errStream)
651 650
 		})
652 651
 	}
653 652
 
... ...
@@ -2369,7 +2369,7 @@ func (srv *Server) ContainerAttach(job *engine.Job) engine.Status {
2369 2369
 			cStderr = job.Stderr
2370 2370
 		}
2371 2371
 
2372
-		<-container.Attach(cStdin, cStdinCloser, cStdout, cStderr)
2372
+		<-srv.daemon.Attach(container, cStdin, cStdinCloser, cStdout, cStderr)
2373 2373
 
2374 2374
 		// If we are in stdinonce mode, wait for the process to end
2375 2375
 		// otherwise, simply return