Docker-DCO-1.1-Signed-off-by: Victor Vieux <victor.vieux@docker.com> (github: vieux)
| ... | ... |
@@ -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) {
|