Browse code

Merge pull request #7344 from shykes/cleanup-server-attach

Move container-related jobs out of deprecated server/ package

Victor Vieux authored on 2014/08/01 07:56:48
Showing 7 changed files
... ...
@@ -684,6 +684,11 @@ func (b *buildFile) run(c *daemon.Container) error {
684 684
 	var errCh chan error
685 685
 	if b.verbose {
686 686
 		errCh = utils.Go(func() error {
687
+			// FIXME: call the 'attach' job so that daemon.Attach can be made private
688
+			//
689
+			// FIXME (LK4D4): Also, maybe makes sense to call "logs" job, it is like attach
690
+			// but without hijacking for stdin. Also, with attach there can be race
691
+			// condition because of some output already was printed before it.
687 692
 			return <-b.daemon.Attach(c, nil, nil, b.outStream, b.errStream)
688 693
 		})
689 694
 	}
... ...
@@ -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,19 @@ 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
+	if err := eng.Register("pause", daemon.ContainerPause); err != nil {
115
+		return err
116
+	}
117
+	if err := eng.Register("unpause", daemon.ContainerUnpause); err != nil {
118
+		return err
119
+	}
120
+	return nil
109 121
 }
110 122
 
111 123
 // List returns an array of all containers registered in the daemon.
112 124
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+package daemon
1
+
2
+import (
3
+	"github.com/docker/docker/engine"
4
+)
5
+
6
+func (daemon *Daemon) ContainerPause(job *engine.Job) engine.Status {
7
+	if len(job.Args) != 1 {
8
+		return job.Errorf("Usage: %s CONTAINER", job.Name)
9
+	}
10
+	name := job.Args[0]
11
+	container := daemon.Get(name)
12
+	if container == nil {
13
+		return job.Errorf("No such container: %s", name)
14
+	}
15
+	if err := container.Pause(); err != nil {
16
+		return job.Errorf("Cannot pause container %s: %s", name, err)
17
+	}
18
+	job.Eng.Job("log", "pause", container.ID, daemon.Repositories().ImageName(container.Image)).Run()
19
+	return engine.StatusOK
20
+}
21
+
22
+func (daemon *Daemon) ContainerUnpause(job *engine.Job) engine.Status {
23
+	if n := len(job.Args); n < 1 || n > 2 {
24
+		return job.Errorf("Usage: %s CONTAINER", job.Name)
25
+	}
26
+	name := job.Args[0]
27
+	container := daemon.Get(name)
28
+	if container == nil {
29
+		return job.Errorf("No such container: %s", name)
30
+	}
31
+	if err := container.Unpause(); err != nil {
32
+		return job.Errorf("Cannot unpause container %s: %s", name, err)
33
+	}
34
+	job.Eng.Job("log", "unpause", container.ID, daemon.Repositories().ImageName(container.Image)).Run()
35
+	return engine.StatusOK
36
+}
... ...
@@ -31,38 +31,6 @@ import (
31 31
 	"github.com/docker/docker/utils"
32 32
 )
33 33
 
34
-func (srv *Server) ContainerPause(job *engine.Job) engine.Status {
35
-	if len(job.Args) != 1 {
36
-		return job.Errorf("Usage: %s CONTAINER", job.Name)
37
-	}
38
-	name := job.Args[0]
39
-	container := srv.daemon.Get(name)
40
-	if container == nil {
41
-		return job.Errorf("No such container: %s", name)
42
-	}
43
-	if err := container.Pause(); err != nil {
44
-		return job.Errorf("Cannot pause container %s: %s", name, err)
45
-	}
46
-	srv.LogEvent("pause", container.ID, srv.daemon.Repositories().ImageName(container.Image))
47
-	return engine.StatusOK
48
-}
49
-
50
-func (srv *Server) ContainerUnpause(job *engine.Job) engine.Status {
51
-	if n := len(job.Args); n < 1 || n > 2 {
52
-		return job.Errorf("Usage: %s CONTAINER", job.Name)
53
-	}
54
-	name := job.Args[0]
55
-	container := srv.daemon.Get(name)
56
-	if container == nil {
57
-		return job.Errorf("No such container: %s", name)
58
-	}
59
-	if err := container.Unpause(); err != nil {
60
-		return job.Errorf("Cannot unpause container %s: %s", name, err)
61
-	}
62
-	srv.LogEvent("unpause", container.ID, srv.daemon.Repositories().ImageName(container.Image))
63
-	return engine.StatusOK
64
-}
65
-
66 34
 // ContainerKill send signal to the container
67 35
 // If no signal is given (sig 0), then Kill with SIGKILL and wait
68 36
 // for the container to exit.
... ...
@@ -798,106 +766,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
-
901 801
 func (srv *Server) ContainerCopy(job *engine.Job) engine.Status {
902 802
 	if len(job.Args) != 2 {
903 803
 		return job.Errorf("Usage: %s CONTAINER RESOURCE\n", job.Name)
... ...
@@ -71,6 +71,16 @@ func (srv *Server) Events(job *engine.Job) engine.Status {
71 71
 	}
72 72
 }
73 73
 
74
+// FIXME: this is a shim to allow breaking up other parts of Server without
75
+// dragging the sphagetti dependency along.
76
+func (srv *Server) Log(job *engine.Job) engine.Status {
77
+	if len(job.Args) != 3 {
78
+		return job.Errorf("usage: %s ACTION ID FROM", job.Name)
79
+	}
80
+	srv.LogEvent(job.Args[0], job.Args[1], job.Args[2])
81
+	return engine.StatusOK
82
+}
83
+
74 84
 func (srv *Server) LogEvent(action, id, from string) *utils.JSONMessage {
75 85
 	now := time.Now().UTC().Unix()
76 86
 	jm := utils.JSONMessage{Status: action, ID: id, From: from, Time: now}
... ...
@@ -92,8 +92,6 @@ func InitServer(job *engine.Job) engine.Status {
92 92
 		"restart":          srv.ContainerRestart,
93 93
 		"start":            srv.ContainerStart,
94 94
 		"kill":             srv.ContainerKill,
95
-		"pause":            srv.ContainerPause,
96
-		"unpause":          srv.ContainerUnpause,
97 95
 		"wait":             srv.ContainerWait,
98 96
 		"tag":              srv.ImageTag, // FIXME merge with "image_tag"
99 97
 		"resize":           srv.ContainerResize,
... ...
@@ -105,7 +103,7 @@ 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,
108
+		"log":              srv.Log,
109 109
 		"logs":             srv.ContainerLogs,
110 110
 		"changes":          srv.ContainerChanges,
111 111
 		"top":              srv.ContainerTop,