Browse code

Move Server.ContainerAttach to Daemon.ContainerAttach

This is part of an effort to break apart the legacy server package. Help wanted!

Docker-DCO-1.1-Signed-off-by: Solomon Hykes <solomon@docker.com> (github: shykes)

Solomon Hykes authored on 2014/07/30 17:16:23
Showing 5 changed files
... ...
@@ -683,6 +683,11 @@ func (b *buildFile) run(c *daemon.Container) error {
683 683
 	var errCh chan error
684 684
 	if b.verbose {
685 685
 		errCh = utils.Go(func() error {
686
+			// FIXME: call the 'attach' job so that daemon.Attach can be made private
687
+			//
688
+			// FIXME (LK4D4): Also, maybe makes sense to call "logs" job, it is like attach
689
+			// but without hijacking for stdin. Also, with attach there can be race
690
+			// condition because of some output already was printed before it.
686 691
 			return <-b.daemon.Attach(c, nil, nil, b.outStream, b.errStream)
687 692
 		})
688 693
 	}
... ...
@@ -1,11 +1,122 @@
1 1
 package daemon
2 2
 
3 3
 import (
4
+	"encoding/json"
5
+	"fmt"
4 6
 	"io"
7
+	"os"
8
+	"time"
5 9
 
10
+	"github.com/docker/docker/engine"
6 11
 	"github.com/docker/docker/utils"
7 12
 )
8 13
 
14
+func (daemon *Daemon) ContainerAttach(job *engine.Job) engine.Status {
15
+	if len(job.Args) != 1 {
16
+		return job.Errorf("Usage: %s CONTAINER\n", job.Name)
17
+	}
18
+
19
+	var (
20
+		name   = job.Args[0]
21
+		logs   = job.GetenvBool("logs")
22
+		stream = job.GetenvBool("stream")
23
+		stdin  = job.GetenvBool("stdin")
24
+		stdout = job.GetenvBool("stdout")
25
+		stderr = job.GetenvBool("stderr")
26
+	)
27
+
28
+	container := daemon.Get(name)
29
+	if container == nil {
30
+		return job.Errorf("No such container: %s", name)
31
+	}
32
+
33
+	//logs
34
+	if logs {
35
+		cLog, err := container.ReadLog("json")
36
+		if err != nil && os.IsNotExist(err) {
37
+			// Legacy logs
38
+			utils.Debugf("Old logs format")
39
+			if stdout {
40
+				cLog, err := container.ReadLog("stdout")
41
+				if err != nil {
42
+					utils.Errorf("Error reading logs (stdout): %s", err)
43
+				} else if _, err := io.Copy(job.Stdout, cLog); err != nil {
44
+					utils.Errorf("Error streaming logs (stdout): %s", err)
45
+				}
46
+			}
47
+			if stderr {
48
+				cLog, err := container.ReadLog("stderr")
49
+				if err != nil {
50
+					utils.Errorf("Error reading logs (stderr): %s", err)
51
+				} else if _, err := io.Copy(job.Stderr, cLog); err != nil {
52
+					utils.Errorf("Error streaming logs (stderr): %s", err)
53
+				}
54
+			}
55
+		} else if err != nil {
56
+			utils.Errorf("Error reading logs (json): %s", err)
57
+		} else {
58
+			dec := json.NewDecoder(cLog)
59
+			for {
60
+				l := &utils.JSONLog{}
61
+
62
+				if err := dec.Decode(l); err == io.EOF {
63
+					break
64
+				} else if err != nil {
65
+					utils.Errorf("Error streaming logs: %s", err)
66
+					break
67
+				}
68
+				if l.Stream == "stdout" && stdout {
69
+					fmt.Fprintf(job.Stdout, "%s", l.Log)
70
+				}
71
+				if l.Stream == "stderr" && stderr {
72
+					fmt.Fprintf(job.Stderr, "%s", l.Log)
73
+				}
74
+			}
75
+		}
76
+	}
77
+
78
+	//stream
79
+	if stream {
80
+		var (
81
+			cStdin           io.ReadCloser
82
+			cStdout, cStderr io.Writer
83
+			cStdinCloser     io.Closer
84
+		)
85
+
86
+		if stdin {
87
+			r, w := io.Pipe()
88
+			go func() {
89
+				defer w.Close()
90
+				defer utils.Debugf("Closing buffered stdin pipe")
91
+				io.Copy(w, job.Stdin)
92
+			}()
93
+			cStdin = r
94
+			cStdinCloser = job.Stdin
95
+		}
96
+		if stdout {
97
+			cStdout = job.Stdout
98
+		}
99
+		if stderr {
100
+			cStderr = job.Stderr
101
+		}
102
+
103
+		<-daemon.Attach(container, cStdin, cStdinCloser, cStdout, cStderr)
104
+
105
+		// If we are in stdinonce mode, wait for the process to end
106
+		// otherwise, simply return
107
+		if container.Config.StdinOnce && !container.Config.Tty {
108
+			container.State.WaitStop(-1 * time.Second)
109
+		}
110
+	}
111
+	return engine.StatusOK
112
+}
113
+
114
+// FIXME: this should be private, and every outside subsystem
115
+// should go through the "container_attach" job. But that would require
116
+// that job to be properly documented, as well as the relationship betweem
117
+// Attach and ContainerAttach.
118
+//
119
+// This method is in use by builder/builder.go.
9 120
 func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
10 121
 	var (
11 122
 		cStdout, cStderr io.ReadCloser
... ...
@@ -105,7 +105,13 @@ type Daemon struct {
105 105
 
106 106
 // Install installs daemon capabilities to eng.
107 107
 func (daemon *Daemon) Install(eng *engine.Engine) error {
108
-	return eng.Register("container_inspect", daemon.ContainerInspect)
108
+	if err := eng.Register("container_inspect", daemon.ContainerInspect); err != nil {
109
+		return err
110
+	}
111
+	if err := eng.Register("attach", daemon.ContainerAttach); err != nil {
112
+		return err
113
+	}
114
+	return nil
109 115
 }
110 116
 
111 117
 // List returns an array of all containers registered in the daemon.
... ...
@@ -798,105 +798,6 @@ func (srv *Server) ContainerLogs(job *engine.Job) engine.Status {
798 798
 	return engine.StatusOK
799 799
 }
800 800
 
801
-func (srv *Server) ContainerAttach(job *engine.Job) engine.Status {
802
-	if len(job.Args) != 1 {
803
-		return job.Errorf("Usage: %s CONTAINER\n", job.Name)
804
-	}
805
-
806
-	var (
807
-		name   = job.Args[0]
808
-		logs   = job.GetenvBool("logs")
809
-		stream = job.GetenvBool("stream")
810
-		stdin  = job.GetenvBool("stdin")
811
-		stdout = job.GetenvBool("stdout")
812
-		stderr = job.GetenvBool("stderr")
813
-	)
814
-
815
-	container := srv.daemon.Get(name)
816
-	if container == nil {
817
-		return job.Errorf("No such container: %s", name)
818
-	}
819
-
820
-	//logs
821
-	if logs {
822
-		cLog, err := container.ReadLog("json")
823
-		if err != nil && os.IsNotExist(err) {
824
-			// Legacy logs
825
-			utils.Debugf("Old logs format")
826
-			if stdout {
827
-				cLog, err := container.ReadLog("stdout")
828
-				if err != nil {
829
-					utils.Errorf("Error reading logs (stdout): %s", err)
830
-				} else if _, err := io.Copy(job.Stdout, cLog); err != nil {
831
-					utils.Errorf("Error streaming logs (stdout): %s", err)
832
-				}
833
-			}
834
-			if stderr {
835
-				cLog, err := container.ReadLog("stderr")
836
-				if err != nil {
837
-					utils.Errorf("Error reading logs (stderr): %s", err)
838
-				} else if _, err := io.Copy(job.Stderr, cLog); err != nil {
839
-					utils.Errorf("Error streaming logs (stderr): %s", err)
840
-				}
841
-			}
842
-		} else if err != nil {
843
-			utils.Errorf("Error reading logs (json): %s", err)
844
-		} else {
845
-			dec := json.NewDecoder(cLog)
846
-			for {
847
-				l := &utils.JSONLog{}
848
-
849
-				if err := dec.Decode(l); err == io.EOF {
850
-					break
851
-				} else if err != nil {
852
-					utils.Errorf("Error streaming logs: %s", err)
853
-					break
854
-				}
855
-				if l.Stream == "stdout" && stdout {
856
-					fmt.Fprintf(job.Stdout, "%s", l.Log)
857
-				}
858
-				if l.Stream == "stderr" && stderr {
859
-					fmt.Fprintf(job.Stderr, "%s", l.Log)
860
-				}
861
-			}
862
-		}
863
-	}
864
-
865
-	//stream
866
-	if stream {
867
-		var (
868
-			cStdin           io.ReadCloser
869
-			cStdout, cStderr io.Writer
870
-			cStdinCloser     io.Closer
871
-		)
872
-
873
-		if stdin {
874
-			r, w := io.Pipe()
875
-			go func() {
876
-				defer w.Close()
877
-				defer utils.Debugf("Closing buffered stdin pipe")
878
-				io.Copy(w, job.Stdin)
879
-			}()
880
-			cStdin = r
881
-			cStdinCloser = job.Stdin
882
-		}
883
-		if stdout {
884
-			cStdout = job.Stdout
885
-		}
886
-		if stderr {
887
-			cStderr = job.Stderr
888
-		}
889
-
890
-		<-srv.daemon.Attach(container, cStdin, cStdinCloser, cStdout, cStderr)
891
-
892
-		// If we are in stdinonce mode, wait for the process to end
893
-		// otherwise, simply return
894
-		if container.Config.StdinOnce && !container.Config.Tty {
895
-			container.State.WaitStop(-1 * time.Second)
896
-		}
897
-	}
898
-	return engine.StatusOK
899
-}
900 801
 
901 802
 func (srv *Server) ContainerCopy(job *engine.Job) engine.Status {
902 803
 	if len(job.Args) != 2 {
... ...
@@ -105,7 +105,6 @@ func InitServer(job *engine.Job) engine.Status {
105 105
 		"history":          srv.ImageHistory,
106 106
 		"viz":              srv.ImagesViz,
107 107
 		"container_copy":   srv.ContainerCopy,
108
-		"attach":           srv.ContainerAttach,
109 108
 		"logs":             srv.ContainerLogs,
110 109
 		"changes":          srv.ContainerChanges,
111 110
 		"top":              srv.ContainerTop,