Docker-DCO-1.1-Signed-off-by: Victor Vieux <victor.vieux@docker.com> (github: vieux)
Victor Vieux authored on 2014/01/09 07:05:05... | ... |
@@ -4,26 +4,26 @@ |
4 | 4 |
TODO "/events": getEvents, N |
5 | 5 |
ok "/info": getInfo, 1 |
6 | 6 |
ok "/version": getVersion, 1 |
7 |
-ok "/images/json": getImagesJSON, N |
|
7 |
+ok "/images/json": getImagesJSON, N |
|
8 | 8 |
ok "/images/viz": getImagesViz, 0 yes |
9 |
-#3615 "/images/search": getImagesSearch, N |
|
10 |
-ok "/images/{name:.*}/get": getImagesGet, 0 |
|
11 |
-ok "/images/{name:.*}/history": getImagesHistory, N |
|
12 |
-TODO "/images/{name:.*}/json": getImagesByName, 1 |
|
9 |
+ok "/images/search": getImagesSearch, N |
|
10 |
+ok "/images/{name:.*}/get": getImagesGet, 0 |
|
11 |
+ok "/images/{name:.*}/history": getImagesHistory, N |
|
12 |
+... "/images/{name:.*}/json": getImagesByName, 1 |
|
13 | 13 |
TODO "/containers/ps": getContainersJSON, N |
14 | 14 |
TODO "/containers/json": getContainersJSON, 1 |
15 | 15 |
ok "/containers/{name:.*}/export": getContainersExport, 0 |
16 |
-... "/containers/{name:.*}/changes": getContainersChanges, N |
|
17 |
-TODO "/containers/{name:.*}/json": getContainersByName, 1 |
|
16 |
+#3616 "/containers/{name:.*}/changes": getContainersChanges, N |
|
17 |
+... "/containers/{name:.*}/json": getContainersByName, 1 |
|
18 | 18 |
TODO "/containers/{name:.*}/top": getContainersTop, N |
19 |
-#3512 "/containers/{name:.*}/attach/ws": wsContainersAttach, 0 yes |
|
19 |
+ok "/containers/{name:.*}/attach/ws": wsContainersAttach, 0 yes |
|
20 | 20 |
|
21 | 21 |
**POST** |
22 | 22 |
TODO "/auth": postAuth, 0 yes |
23 | 23 |
ok "/commit": postCommit, 0 |
24 | 24 |
TODO "/build": postBuild, 0 yes |
25 | 25 |
TODO "/images/create": postImagesCreate, N yes yes (pull) |
26 |
-#3559 "/images/{name:.*}/insert": postImagesInsert, N yes yes |
|
26 |
+ok "/images/{name:.*}/insert": postImagesInsert, N yes yes |
|
27 | 27 |
TODO "/images/load": postImagesLoad, 1 yes (stdin) |
28 | 28 |
TODO "/images/{name:.*}/push": postImagesPush, N yes |
29 | 29 |
ok "/images/{name:.*}/tag": postImagesTag, 0 |
... | ... |
@@ -34,8 +34,8 @@ ok "/containers/{name:.*}/start": postContainersStart, 0 |
34 | 34 |
ok "/containers/{name:.*}/stop": postContainersStop, 0 |
35 | 35 |
ok "/containers/{name:.*}/wait": postContainersWait, 0 |
36 | 36 |
ok "/containers/{name:.*}/resize": postContainersResize, 0 |
37 |
-#3512 "/containers/{name:.*}/attach": postContainersAttach, 0 yes |
|
38 |
-#3560 "/containers/{name:.*}/copy": postContainersCopy, 0 yes |
|
37 |
+ok "/containers/{name:.*}/attach": postContainersAttach, 0 yes |
|
38 |
+ok "/containers/{name:.*}/copy": postContainersCopy, 0 yes |
|
39 | 39 |
|
40 | 40 |
**DELETE** |
41 | 41 |
ok "/containers/{name:.*}": deleteContainers, 0 |
... | ... |
@@ -769,33 +769,11 @@ func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r |
769 | 769 |
if err := parseForm(r); err != nil { |
770 | 770 |
return err |
771 | 771 |
} |
772 |
- logs, err := getBoolParam(r.Form.Get("logs")) |
|
773 |
- if err != nil { |
|
774 |
- return err |
|
775 |
- } |
|
776 |
- stream, err := getBoolParam(r.Form.Get("stream")) |
|
777 |
- if err != nil { |
|
778 |
- return err |
|
779 |
- } |
|
780 |
- stdin, err := getBoolParam(r.Form.Get("stdin")) |
|
781 |
- if err != nil { |
|
782 |
- return err |
|
783 |
- } |
|
784 |
- stdout, err := getBoolParam(r.Form.Get("stdout")) |
|
785 |
- if err != nil { |
|
786 |
- return err |
|
787 |
- } |
|
788 |
- stderr, err := getBoolParam(r.Form.Get("stderr")) |
|
789 |
- if err != nil { |
|
790 |
- return err |
|
791 |
- } |
|
792 |
- |
|
793 | 772 |
if vars == nil { |
794 | 773 |
return fmt.Errorf("Missing parameter") |
795 | 774 |
} |
796 |
- name := vars["name"] |
|
797 | 775 |
|
798 |
- c, err := srv.ContainerInspect(name) |
|
776 |
+ c, err := srv.ContainerInspect(vars["name"]) |
|
799 | 777 |
if err != nil { |
800 | 778 |
return err |
801 | 779 |
} |
... | ... |
@@ -830,51 +808,46 @@ func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r |
830 | 830 |
errStream = outStream |
831 | 831 |
} |
832 | 832 |
|
833 |
- if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, inStream, outStream, errStream); err != nil { |
|
833 |
+ job := srv.Eng.Job("attach", vars["name"]) |
|
834 |
+ job.Setenv("logs", r.Form.Get("logs")) |
|
835 |
+ job.Setenv("stream", r.Form.Get("stream")) |
|
836 |
+ job.Setenv("stdin", r.Form.Get("stdin")) |
|
837 |
+ job.Setenv("stdout", r.Form.Get("stdout")) |
|
838 |
+ job.Setenv("stderr", r.Form.Get("stderr")) |
|
839 |
+ job.Stdin.Add(inStream) |
|
840 |
+ job.Stdout.Add(outStream) |
|
841 |
+ job.Stderr.Add(errStream) |
|
842 |
+ if err := job.Run(); err != nil { |
|
834 | 843 |
fmt.Fprintf(outStream, "Error: %s\n", err) |
844 |
+ |
|
835 | 845 |
} |
836 | 846 |
return nil |
837 | 847 |
} |
838 | 848 |
|
839 | 849 |
func wsContainersAttach(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { |
840 |
- |
|
841 | 850 |
if err := parseForm(r); err != nil { |
842 | 851 |
return err |
843 | 852 |
} |
844 |
- logs, err := getBoolParam(r.Form.Get("logs")) |
|
845 |
- if err != nil { |
|
846 |
- return err |
|
847 |
- } |
|
848 |
- stream, err := getBoolParam(r.Form.Get("stream")) |
|
849 |
- if err != nil { |
|
850 |
- return err |
|
851 |
- } |
|
852 |
- stdin, err := getBoolParam(r.Form.Get("stdin")) |
|
853 |
- if err != nil { |
|
854 |
- return err |
|
855 |
- } |
|
856 |
- stdout, err := getBoolParam(r.Form.Get("stdout")) |
|
857 |
- if err != nil { |
|
858 |
- return err |
|
859 |
- } |
|
860 |
- stderr, err := getBoolParam(r.Form.Get("stderr")) |
|
861 |
- if err != nil { |
|
862 |
- return err |
|
863 |
- } |
|
864 |
- |
|
865 | 853 |
if vars == nil { |
866 | 854 |
return fmt.Errorf("Missing parameter") |
867 | 855 |
} |
868 |
- name := vars["name"] |
|
869 | 856 |
|
870 |
- if _, err := srv.ContainerInspect(name); err != nil { |
|
857 |
+ if _, err := srv.ContainerInspect(vars["name"]); err != nil { |
|
871 | 858 |
return err |
872 | 859 |
} |
873 | 860 |
|
874 | 861 |
h := websocket.Handler(func(ws *websocket.Conn) { |
875 | 862 |
defer ws.Close() |
876 |
- |
|
877 |
- if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, ws, ws, ws); err != nil { |
|
863 |
+ job := srv.Eng.Job("attach", vars["name"]) |
|
864 |
+ job.Setenv("logs", r.Form.Get("logs")) |
|
865 |
+ job.Setenv("stream", r.Form.Get("stream")) |
|
866 |
+ job.Setenv("stdin", r.Form.Get("stdin")) |
|
867 |
+ job.Setenv("stdout", r.Form.Get("stdout")) |
|
868 |
+ job.Setenv("stderr", r.Form.Get("stderr")) |
|
869 |
+ job.Stdin.Add(ws) |
|
870 |
+ job.Stdout.Add(ws) |
|
871 |
+ job.Stderr.Add(ws) |
|
872 |
+ if err := job.Run(); err != nil { |
|
878 | 873 |
utils.Errorf("Error: %s", err) |
879 | 874 |
} |
880 | 875 |
}) |
... | ... |
@@ -141,6 +141,17 @@ func (i *Input) Read(p []byte) (n int, err error) { |
141 | 141 |
return i.src.Read(p) |
142 | 142 |
} |
143 | 143 |
|
144 |
+// Closes the src |
|
145 |
+// Not thread safe on purpose |
|
146 |
+func (i *Input) Close() error { |
|
147 |
+ if i.src != nil { |
|
148 |
+ if closer, ok := i.src.(io.WriteCloser); ok { |
|
149 |
+ return closer.Close() |
|
150 |
+ } |
|
151 |
+ } |
|
152 |
+ return nil |
|
153 |
+} |
|
154 |
+ |
|
144 | 155 |
// Add attaches a new source to the input. |
145 | 156 |
// Add can only be called once per input. Subsequent calls will |
146 | 157 |
// return an error. |
... | ... |
@@ -147,6 +147,10 @@ func jobInitApi(job *engine.Job) engine.Status { |
147 | 147 |
job.Error(err) |
148 | 148 |
return engine.StatusErr |
149 | 149 |
} |
150 |
+ if err := job.Eng.Register("attach", srv.ContainerAttach); err != nil { |
|
151 |
+ job.Error(err) |
|
152 |
+ return engine.StatusErr |
|
153 |
+ } |
|
150 | 154 |
return engine.StatusOK |
151 | 155 |
} |
152 | 156 |
|
... | ... |
@@ -1980,10 +1984,25 @@ func (srv *Server) ContainerResize(job *engine.Job) engine.Status { |
1980 | 1980 |
return engine.StatusErr |
1981 | 1981 |
} |
1982 | 1982 |
|
1983 |
-func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, stderr bool, inStream io.ReadCloser, outStream, errStream io.Writer) error { |
|
1983 |
+func (srv *Server) ContainerAttach(job *engine.Job) engine.Status { |
|
1984 |
+ if len(job.Args) != 1 { |
|
1985 |
+ job.Errorf("Usage: %s CONTAINER\n", job.Name) |
|
1986 |
+ return engine.StatusErr |
|
1987 |
+ } |
|
1988 |
+ |
|
1989 |
+ var ( |
|
1990 |
+ name = job.Args[0] |
|
1991 |
+ logs = job.GetenvBool("logs") |
|
1992 |
+ stream = job.GetenvBool("stream") |
|
1993 |
+ stdin = job.GetenvBool("stdin") |
|
1994 |
+ stdout = job.GetenvBool("stdout") |
|
1995 |
+ stderr = job.GetenvBool("stderr") |
|
1996 |
+ ) |
|
1997 |
+ |
|
1984 | 1998 |
container := srv.runtime.Get(name) |
1985 | 1999 |
if container == nil { |
1986 |
- return fmt.Errorf("No such container: %s", name) |
|
2000 |
+ job.Errorf("No such container: %s", name) |
|
2001 |
+ return engine.StatusErr |
|
1987 | 2002 |
} |
1988 | 2003 |
|
1989 | 2004 |
//logs |
... | ... |
@@ -1991,12 +2010,12 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std |
1991 | 1991 |
cLog, err := container.ReadLog("json") |
1992 | 1992 |
if err != nil && os.IsNotExist(err) { |
1993 | 1993 |
// Legacy logs |
1994 |
- utils.Errorf("Old logs format") |
|
1994 |
+ utils.Debugf("Old logs format") |
|
1995 | 1995 |
if stdout { |
1996 | 1996 |
cLog, err := container.ReadLog("stdout") |
1997 | 1997 |
if err != nil { |
1998 | 1998 |
utils.Errorf("Error reading logs (stdout): %s", err) |
1999 |
- } else if _, err := io.Copy(outStream, cLog); err != nil { |
|
1999 |
+ } else if _, err := io.Copy(job.Stdout, cLog); err != nil { |
|
2000 | 2000 |
utils.Errorf("Error streaming logs (stdout): %s", err) |
2001 | 2001 |
} |
2002 | 2002 |
} |
... | ... |
@@ -2004,7 +2023,7 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std |
2004 | 2004 |
cLog, err := container.ReadLog("stderr") |
2005 | 2005 |
if err != nil { |
2006 | 2006 |
utils.Errorf("Error reading logs (stderr): %s", err) |
2007 |
- } else if _, err := io.Copy(errStream, cLog); err != nil { |
|
2007 |
+ } else if _, err := io.Copy(job.Stderr, cLog); err != nil { |
|
2008 | 2008 |
utils.Errorf("Error streaming logs (stderr): %s", err) |
2009 | 2009 |
} |
2010 | 2010 |
} |
... | ... |
@@ -2022,10 +2041,10 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std |
2022 | 2022 |
break |
2023 | 2023 |
} |
2024 | 2024 |
if l.Stream == "stdout" && stdout { |
2025 |
- fmt.Fprintf(outStream, "%s", l.Log) |
|
2025 |
+ fmt.Fprintf(job.Stdout, "%s", l.Log) |
|
2026 | 2026 |
} |
2027 | 2027 |
if l.Stream == "stderr" && stderr { |
2028 |
- fmt.Fprintf(errStream, "%s", l.Log) |
|
2028 |
+ fmt.Fprintf(job.Stderr, "%s", l.Log) |
|
2029 | 2029 |
} |
2030 | 2030 |
} |
2031 | 2031 |
} |
... | ... |
@@ -2034,7 +2053,8 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std |
2034 | 2034 |
//stream |
2035 | 2035 |
if stream { |
2036 | 2036 |
if container.State.IsGhost() { |
2037 |
- return fmt.Errorf("Impossible to attach to a ghost container") |
|
2037 |
+ job.Errorf("Impossible to attach to a ghost container") |
|
2038 |
+ return engine.StatusErr |
|
2038 | 2039 |
} |
2039 | 2040 |
|
2040 | 2041 |
var ( |
... | ... |
@@ -2048,16 +2068,16 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std |
2048 | 2048 |
go func() { |
2049 | 2049 |
defer w.Close() |
2050 | 2050 |
defer utils.Debugf("Closing buffered stdin pipe") |
2051 |
- io.Copy(w, inStream) |
|
2051 |
+ io.Copy(w, job.Stdin) |
|
2052 | 2052 |
}() |
2053 | 2053 |
cStdin = r |
2054 |
- cStdinCloser = inStream |
|
2054 |
+ cStdinCloser = job.Stdin |
|
2055 | 2055 |
} |
2056 | 2056 |
if stdout { |
2057 |
- cStdout = outStream |
|
2057 |
+ cStdout = job.Stdout |
|
2058 | 2058 |
} |
2059 | 2059 |
if stderr { |
2060 |
- cStderr = errStream |
|
2060 |
+ cStderr = job.Stderr |
|
2061 | 2061 |
} |
2062 | 2062 |
|
2063 | 2063 |
<-container.Attach(cStdin, cStdinCloser, cStdout, cStderr) |
... | ... |
@@ -2068,7 +2088,7 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std |
2068 | 2068 |
container.Wait() |
2069 | 2069 |
} |
2070 | 2070 |
} |
2071 |
- return nil |
|
2071 |
+ return engine.StatusOK |
|
2072 | 2072 |
} |
2073 | 2073 |
|
2074 | 2074 |
func (srv *Server) ContainerInspect(name string) (*Container, error) { |