From 82313b1de9041896e33ddd8fab63924fb7bdebc3 Mon Sep 17 00:00:00 2001 From: odk- Date: Fri, 10 May 2013 10:18:01 +0200 Subject: [PATCH 01/15] full container.Id display when notrunc is used --- server.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server.go b/server.go index 3e95d5849d..e96497bff3 100644 --- a/server.go +++ b/server.go @@ -262,7 +262,12 @@ func (srv *Server) Containers(all, trunc_cmd, only_ids bool, n int, since, befor displayed++ c := ApiContainers{ - Id: container.ShortId(), + Id: container.Id, + } + if trunc_cmd { + c = ApiContainers{ + Id: container.ShortId(), + } } if !only_ids { From dbc899130cbe112046584f08a9733b688aa77003 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 10 May 2013 20:20:49 +0200 Subject: [PATCH 02/15] refactor api.go --- api.go | 285 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 154 insertions(+), 131 deletions(-) diff --git a/api.go b/api.go index d5396a5851..07a9c97b8e 100644 --- a/api.go +++ b/api.go @@ -39,22 +39,24 @@ func httpError(w http.ResponseWriter, err error) { } } -func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &auth.AuthConfig{ Username: srv.runtime.authConfig.Username, Email: srv.runtime.authConfig.Email, } b, err := json.Marshal(config) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &auth.AuthConfig{} if err := json.NewDecoder(r.Body).Decode(config); err != nil { - return nil, err + return err } if config.Username == srv.runtime.authConfig.Username { @@ -64,7 +66,7 @@ func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[stri newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root) status, err := auth.Login(newAuthConfig) if err != nil { - return nil, err + return err } else { srv.runtime.graph.getHttpClient().Jar = cookiejar.NewCookieJar() srv.runtime.authConfig = newAuthConfig @@ -72,38 +74,42 @@ func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[stri if status != "" { b, err := json.Marshal(&ApiAuth{Status: status}) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func getVersion(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getVersion(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { m := srv.DockerVersion() b, err := json.Marshal(m) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postContainersKill(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersKill(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ContainerKill(name); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] @@ -111,12 +117,12 @@ func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, va Debugf("%s", err.Error()) //return nil, err } - return nil, nil + return nil } -func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } all := r.Form.Get("all") == "1" @@ -125,66 +131,74 @@ func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map outs, err := srv.Images(all, only_ids, filter) if err != nil { - return nil, err + return err } b, err := json.Marshal(outs) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getImagesViz(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesViz(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := srv.ImagesViz(w); err != nil { - return nil, err + return err } - return nil, nil + return nil } -func getInfo(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getInfo(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { out := srv.DockerInfo() b, err := json.Marshal(out) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getImagesHistory(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesHistory(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] outs, err := srv.ImageHistory(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(outs) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getContainersChanges(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getContainersChanges(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] changesStr, err := srv.ContainerChanges(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(changesStr) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } all := r.Form.Get("all") == "1" trunc_cmd := r.Form.Get("trunc_cmd") != "0" @@ -199,33 +213,35 @@ func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars m outs := srv.Containers(all, trunc_cmd, only_ids, n, since, before) b, err := json.Marshal(outs) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postImagesTag(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postImagesTag(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } repo := r.Form.Get("repo") tag := r.Form.Get("tag") if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] force := r.Form.Get("force") == "1" if err := srv.ContainerTag(name, repo, tag, force); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusCreated) - return nil, nil + return nil } -func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } var config Config if err := json.NewDecoder(r.Body).Decode(&config); err != nil { @@ -238,20 +254,22 @@ func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st comment := r.Form.Get("comment") id, err := srv.ContainerCommit(container, repo, tag, author, comment, &config) if err != nil { - return nil, err + return err } b, err := json.Marshal(ApiId{id}) if err != nil { - return nil, err + return err } w.WriteHeader(http.StatusCreated) - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } // Creates an image from Pull or from Import -func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } src := r.Form.Get("fromSrc") @@ -261,7 +279,7 @@ func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") @@ -275,95 +293,97 @@ func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars fmt.Fprintf(out, "Error: %s\n", err) } } - return nil, nil + return nil } -func getImagesSearch(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesSearch(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } term := r.Form.Get("term") outs, err := srv.ImagesSearch(term) if err != nil { - return nil, err + return err } b, err := json.Marshal(outs) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postImagesInsert(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postImagesInsert(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } url := r.Form.Get("url") path := r.Form.Get("path") if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") if err := srv.ImageInsert(name, url, path, out); err != nil { fmt.Fprintf(out, "Error: %s\n", err) } - return nil, nil + return nil } -func postImagesPush(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postImagesPush(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } registry := r.Form.Get("registry") if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") if err := srv.ImagePush(name, registry, out); err != nil { fmt.Fprintln(out, "Error: %s\n", err) } - return nil, nil + return nil } -func postBuild(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postBuild(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") if err := srv.ImageCreateFromFile(in, out); err != nil { fmt.Fprintln(out, "Error: %s\n", err) } - return nil, nil + return nil } -func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &Config{} if err := json.NewDecoder(r.Body).Decode(config); err != nil { - return nil, err + return err } id, err := srv.ContainerCreate(config) if err != nil { - return nil, err + return err } out := &ApiRun{ @@ -379,75 +399,77 @@ func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, v } b, err := json.Marshal(out) if err != nil { - return nil, err + return err } w.WriteHeader(http.StatusCreated) - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postContainersRestart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersRestart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } t, err := strconv.Atoi(r.Form.Get("t")) if err != nil || t < 0 { t = 10 } if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ContainerRestart(name, t); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func deleteContainers(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func deleteContainers(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] removeVolume := r.Form.Get("v") == "1" if err := srv.ContainerDestroy(name, removeVolume); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func deleteImages(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func deleteImages(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ImageDelete(name); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func postContainersStart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersStart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ContainerStart(name); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func postContainersStop(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersStop(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } t, err := strconv.Atoi(r.Form.Get("t")) if err != nil || t < 0 { @@ -455,36 +477,38 @@ func postContainersStop(srv *Server, w http.ResponseWriter, r *http.Request, var } if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ContainerStop(name, t); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func postContainersWait(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersWait(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] status, err := srv.ContainerWait(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(&ApiWait{StatusCode: status}) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } logs := r.Form.Get("logs") == "1" stream := r.Form.Get("stream") == "1" @@ -492,13 +516,13 @@ func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, v stdout := r.Form.Get("stdout") == "1" stderr := r.Form.Get("stderr") == "1" if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() @@ -506,48 +530,52 @@ func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, v if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, in, out); err != nil { fmt.Fprintf(out, "Error: %s\n", err) } - return nil, nil + return nil } -func getContainersByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getContainersByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] container, err := srv.ContainerInspect(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(container) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getImagesByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] image, err := srv.ImageInspect(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(image) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } func ListenAndServe(addr string, srv *Server, logging bool) error { r := mux.NewRouter() log.Printf("Listening for HTTP on %s\n", addr) - m := map[string]map[string]func(*Server, http.ResponseWriter, *http.Request, map[string]string) ([]byte, error){ + m := map[string]map[string]func(*Server, http.ResponseWriter, *http.Request, map[string]string) error{ "GET": { "/auth": getAuth, "/version": getVersion, @@ -602,14 +630,9 @@ func ListenAndServe(addr string, srv *Server, logging bool) error { Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], VERSION) } } - json, err := localFct(srv, w, r, mux.Vars(r)) - if err != nil { + if err := localFct(srv, w, r, mux.Vars(r)); err != nil { httpError(w, err) } - if json != nil { - w.Header().Set("Content-Type", "application/json") - w.Write(json) - } }) } } From 67cdfc0c834fcac7d288124611642df14aac075c Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 10 May 2013 21:11:59 +0200 Subject: [PATCH 03/15] add writeJson --- api.go | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/api.go b/api.go index 07a9c97b8e..bb95bb1bc8 100644 --- a/api.go +++ b/api.go @@ -39,6 +39,11 @@ func httpError(w http.ResponseWriter, err error) { } } +func writeJson(w http.ResponseWriter, b []byte) { + w.Header().Set("Content-Type", "application/json") + w.Write(b) +} + func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &auth.AuthConfig{ Username: srv.runtime.authConfig.Username, @@ -48,8 +53,7 @@ func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[strin if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -76,8 +80,7 @@ func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[stri if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } w.WriteHeader(http.StatusNoContent) @@ -90,8 +93,7 @@ func getVersion(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -137,8 +139,7 @@ func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -155,8 +156,7 @@ func getInfo(srv *Server, w http.ResponseWriter, r *http.Request, vars map[strin if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -173,8 +173,7 @@ func getImagesHistory(srv *Server, w http.ResponseWriter, r *http.Request, vars if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -191,8 +190,7 @@ func getContainersChanges(srv *Server, w http.ResponseWriter, r *http.Request, v if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -215,8 +213,7 @@ func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars m if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -261,8 +258,7 @@ func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st return err } w.WriteHeader(http.StatusCreated) - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -310,8 +306,7 @@ func getImagesSearch(srv *Server, w http.ResponseWriter, r *http.Request, vars m if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -402,8 +397,7 @@ func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, v return err } w.WriteHeader(http.StatusCreated) - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -501,8 +495,7 @@ func postContainersWait(srv *Server, w http.ResponseWriter, r *http.Request, var if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -547,8 +540,7 @@ func getContainersByName(srv *Server, w http.ResponseWriter, r *http.Request, va if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -566,8 +558,7 @@ func getImagesByName(srv *Server, w http.ResponseWriter, r *http.Request, vars m if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } From 5bec9275c01f646ba6a5afd19ea80a38c41604a7 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Fri, 10 May 2013 12:28:07 -0700 Subject: [PATCH 04/15] Improve remote api unit tests --- api.go | 8 +- api_test.go | 318 ++++++++++++++++++++++++++++------------------------ 2 files changed, 176 insertions(+), 150 deletions(-) diff --git a/api.go b/api.go index d5396a5851..9485fca051 100644 --- a/api.go +++ b/api.go @@ -227,8 +227,8 @@ func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st if err := parseForm(r); err != nil { return nil, err } - var config Config - if err := json.NewDecoder(r.Body).Decode(&config); err != nil { + config := &Config{} + if err := json.NewDecoder(r.Body).Decode(config); err != nil { Debugf("%s", err.Error()) } repo := r.Form.Get("repo") @@ -236,11 +236,11 @@ func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st container := r.Form.Get("container") author := r.Form.Get("author") comment := r.Form.Get("comment") - id, err := srv.ContainerCommit(container, repo, tag, author, comment, &config) + id, err := srv.ContainerCommit(container, repo, tag, author, comment, config) if err != nil { return nil, err } - b, err := json.Marshal(ApiId{id}) + b, err := json.Marshal(&ApiId{id}) if err != nil { return nil, err } diff --git a/api_test.go b/api_test.go index eb6cdd3b10..355e93a511 100644 --- a/api_test.go +++ b/api_test.go @@ -1,6 +1,7 @@ package docker import ( + "archive/tar" "bufio" "bytes" "encoding/json" @@ -139,8 +140,8 @@ func TestGetImagesJson(t *testing.T) { t.Errorf("Excepted 1 image, %d found", len(images)) } - if images[0].Repository != "docker-ut" { - t.Errorf("Excepted image docker-ut, %s found", images[0].Repository) + if images[0].Repository != unitTestImageName { + t.Errorf("Excepted image %s, %s found", unitTestImageName, images[0].Repository) } // only_ids=1&all=1 @@ -168,8 +169,8 @@ func TestGetImagesJson(t *testing.T) { t.Errorf("Excepted no image Repository, %s found", images2[0].Repository) } - if images2[0].Id == "" { - t.Errorf("Excepted image Id, %s found", images2[0].Id) + if images2[0].Id != GetTestImage(runtime).Id { + t.Errorf("Retrieved image Id differs, expected %s, received %d", GetTestImage(runtime).Id, images2[0].Id) } // filter=a @@ -244,7 +245,6 @@ func TestGetImagesSearch(t *testing.T) { } results := []ApiSearch{} - err = json.Unmarshal(body, &results) if err != nil { t.Fatal(err) @@ -269,7 +269,6 @@ func TestGetImagesHistory(t *testing.T) { } history := []ApiHistory{} - err = json.Unmarshal(body, &history) if err != nil { t.Fatal(err) @@ -299,7 +298,7 @@ func TestGetImagesByName(t *testing.T) { if err != nil { t.Fatal(err) } - if img.Comment != "Imported from http://get.docker.io/images/busybox" { + if img.Id != GetTestImage(runtime).Id || img.Comment != "Imported from http://get.docker.io/images/busybox" { t.Errorf("Error inspecting image") } } @@ -359,7 +358,7 @@ func TestGetContainersExport(t *testing.T) { container, err := builder.Create( &Config{ Image: GetTestImage(runtime).Id, - Cmd: []string{"/bin/rm", "/etc/passwd"}, + Cmd: []string{"touch", "/test"}, }, ) if err != nil { @@ -382,8 +381,22 @@ func TestGetContainersExport(t *testing.T) { t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code) } - if r.Body == nil { - t.Fatalf("Body expected, found 0") + found := false + for tarReader := tar.NewReader(r.Body); ; { + h, err := tarReader.Next() + if err != nil { + if err == io.EOF { + break + } + t.Fatal(err) + } + if h.Name == "./test" { + found = true + break + } + } + if !found { + t.Fatalf("The created test file has not been found in the exported image") } } @@ -450,7 +463,7 @@ func TestGetContainersByName(t *testing.T) { container, err := builder.Create( &Config{ Image: GetTestImage(runtime).Id, - Cmd: []string{"/bin/rm", "/etc/passwd"}, + Cmd: []string{"echo", "test"}, }, ) if err != nil { @@ -462,10 +475,13 @@ func TestGetContainersByName(t *testing.T) { if err != nil { t.Fatal(err) } - outContainer := Container{} - if err := json.Unmarshal(body, &outContainer); err != nil { + outContainer := &Container{} + if err := json.Unmarshal(body, outContainer); err != nil { t.Fatal(err) } + if outContainer.Id != container.Id { + t.Fatalf("Wrong containers retrieved. Expected %s, recieved %s", container.Id, outContainer.Id) + } } func TestPostAuth(t *testing.T) { @@ -516,7 +532,7 @@ func TestPostCommit(t *testing.T) { container, err := builder.Create( &Config{ Image: GetTestImage(runtime).Id, - Cmd: []string{"/bin/rm", "/etc/passwd"}, + Cmd: []string{"touch", "/test"}, }, ) if err != nil { @@ -537,13 +553,17 @@ func TestPostCommit(t *testing.T) { if err != nil { t.Fatal(err) } - - if body == nil { - t.Fatalf("Body expected, received: 0\n") - } if r.Code != http.StatusCreated { t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code) } + + apiId := &ApiId{} + if err := json.Unmarshal(body, apiId); err != nil { + t.Fatal(err) + } + if _, err := runtime.graph.Get(apiId.Id); err != nil { + t.Fatalf("The image has not been commited") + } } func TestPostBuild(t *testing.T) { @@ -601,163 +621,169 @@ func TestPostBuild(t *testing.T) { } func TestPostImagesCreate(t *testing.T) { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } - defer nuke(runtime) + // FIXME: Use the staging in order to perform tests - srv := &Server{runtime: runtime} + // runtime, err := newTestRuntime() + // if err != nil { + // t.Fatal(err) + // } + // defer nuke(runtime) - stdin, stdinPipe := io.Pipe() - stdout, stdoutPipe := io.Pipe() + // srv := &Server{runtime: runtime} - c1 := make(chan struct{}) - go func() { - r := &hijackTester{ - ResponseRecorder: httptest.NewRecorder(), - in: stdin, - out: stdoutPipe, - } + // stdin, stdinPipe := io.Pipe() + // stdout, stdoutPipe := io.Pipe() - req, err := http.NewRequest("POST", "/images/create?fromImage=docker-ut", bytes.NewReader([]byte{})) - if err != nil { - t.Fatal(err) - } + // c1 := make(chan struct{}) + // go func() { + // defer close(c1) - body, err := postImagesCreate(srv, r, req, nil) - close(c1) - if err != nil { - t.Fatal(err) - } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } - }() + // r := &hijackTester{ + // ResponseRecorder: httptest.NewRecorder(), + // in: stdin, + // out: stdoutPipe, + // } - // Acknowledge hijack - setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() { - stdout.Read([]byte{}) - stdout.Read(make([]byte, 4096)) - }) + // req, err := http.NewRequest("POST", "/images/create?fromImage="+unitTestImageName, bytes.NewReader([]byte{})) + // if err != nil { + // t.Fatal(err) + // } - setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() { - reader := bufio.NewReader(stdout) - line, err := reader.ReadString('\n') - if err != nil { - t.Fatal(err) - } - if !strings.HasPrefix(line, "Pulling repository docker-ut from") { - t.Fatalf("Expected Pulling repository docker-ut from..., found %s", line) - } - }) + // body, err := postImagesCreate(srv, r, req, nil) + // if err != nil { + // t.Fatal(err) + // } + // if body != nil { + // t.Fatalf("No body expected, received: %s\n", body) + // } + // }() - // Close pipes (client disconnects) - if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil { - t.Fatal(err) - } + // // Acknowledge hijack + // setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() { + // stdout.Read([]byte{}) + // stdout.Read(make([]byte, 4096)) + // }) - // Wait for imagesCreate to finish, the client disconnected, therefore, Create finished his job - setTimeout(t, "Waiting for imagesCreate timed out", 10*time.Second, func() { - <-c1 - }) + // setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() { + // reader := bufio.NewReader(stdout) + // line, err := reader.ReadString('\n') + // if err != nil { + // t.Fatal(err) + // } + // if !strings.HasPrefix(line, "Pulling repository d from") { + // t.Fatalf("Expected Pulling repository docker-ut from..., found %s", line) + // } + // }) + + // // Close pipes (client disconnects) + // if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil { + // t.Fatal(err) + // } + + // // Wait for imagesCreate to finish, the client disconnected, therefore, Create finished his job + // setTimeout(t, "Waiting for imagesCreate timed out", 10*time.Second, func() { + // <-c1 + // }) } -func TestPostImagesInsert(t *testing.T) { - //FIXME: Implement this test (or remove this endpoint) - t.Log("Test not implemented") -} +// func TestPostImagesInsert(t *testing.T) { +// //FIXME: Implement this test (or remove this endpoint) +// t.Log("Test not implemented") +// } func TestPostImagesPush(t *testing.T) { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } - defer nuke(runtime) + //FIXME: Use staging in order to perform tests + // runtime, err := newTestRuntime() + // if err != nil { + // t.Fatal(err) + // } + // defer nuke(runtime) - srv := &Server{runtime: runtime} + // srv := &Server{runtime: runtime} - stdin, stdinPipe := io.Pipe() - stdout, stdoutPipe := io.Pipe() + // stdin, stdinPipe := io.Pipe() + // stdout, stdoutPipe := io.Pipe() - c1 := make(chan struct{}) - go func() { - r := &hijackTester{ - ResponseRecorder: httptest.NewRecorder(), - in: stdin, - out: stdoutPipe, - } + // c1 := make(chan struct{}) + // go func() { + // r := &hijackTester{ + // ResponseRecorder: httptest.NewRecorder(), + // in: stdin, + // out: stdoutPipe, + // } - req, err := http.NewRequest("POST", "/images/docker-ut/push", bytes.NewReader([]byte{})) - if err != nil { - t.Fatal(err) - } + // req, err := http.NewRequest("POST", "/images/docker-ut/push", bytes.NewReader([]byte{})) + // if err != nil { + // t.Fatal(err) + // } - body, err := postImagesPush(srv, r, req, map[string]string{"name": "docker-ut"}) - close(c1) - if err != nil { - t.Fatal(err) - } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } - }() + // body, err := postImagesPush(srv, r, req, map[string]string{"name": "docker-ut"}) + // close(c1) + // if err != nil { + // t.Fatal(err) + // } + // if body != nil { + // t.Fatalf("No body expected, received: %s\n", body) + // } + // }() - // Acknowledge hijack - setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() { - stdout.Read([]byte{}) - stdout.Read(make([]byte, 4096)) - }) + // // Acknowledge hijack + // setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() { + // stdout.Read([]byte{}) + // stdout.Read(make([]byte, 4096)) + // }) - setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() { - reader := bufio.NewReader(stdout) - line, err := reader.ReadString('\n') - if err != nil { - t.Fatal(err) - } - if !strings.HasPrefix(line, "Processing checksum") { - t.Fatalf("Processing checksum..., found %s", line) - } - }) + // setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() { + // reader := bufio.NewReader(stdout) + // line, err := reader.ReadString('\n') + // if err != nil { + // t.Fatal(err) + // } + // if !strings.HasPrefix(line, "Processing checksum") { + // t.Fatalf("Processing checksum..., found %s", line) + // } + // }) - // Close pipes (client disconnects) - if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil { - t.Fatal(err) - } + // // Close pipes (client disconnects) + // if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil { + // t.Fatal(err) + // } - // Wait for imagesPush to finish, the client disconnected, therefore, Push finished his job - setTimeout(t, "Waiting for imagesPush timed out", 10*time.Second, func() { - <-c1 - }) + // // Wait for imagesPush to finish, the client disconnected, therefore, Push finished his job + // setTimeout(t, "Waiting for imagesPush timed out", 10*time.Second, func() { + // <-c1 + // }) } func TestPostImagesTag(t *testing.T) { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } - defer nuke(runtime) + // FIXME: Use staging in order to perform tests - srv := &Server{runtime: runtime} + // runtime, err := newTestRuntime() + // if err != nil { + // t.Fatal(err) + // } + // defer nuke(runtime) - r := httptest.NewRecorder() + // srv := &Server{runtime: runtime} - req, err := http.NewRequest("POST", "/images/docker-ut/tag?repo=testrepo&tag=testtag", bytes.NewReader([]byte{})) - if err != nil { - t.Fatal(err) - } + // r := httptest.NewRecorder() - body, err := postImagesTag(srv, r, req, map[string]string{"name": "docker-ut"}) - if err != nil { - t.Fatal(err) - } + // req, err := http.NewRequest("POST", "/images/docker-ut/tag?repo=testrepo&tag=testtag", bytes.NewReader([]byte{})) + // if err != nil { + // t.Fatal(err) + // } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } - if r.Code != http.StatusCreated { - t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code) - } + // body, err := postImagesTag(srv, r, req, map[string]string{"name": "docker-ut"}) + // if err != nil { + // t.Fatal(err) + // } + + // if body != nil { + // t.Fatalf("No body expected, received: %s\n", body) + // } + // if r.Code != http.StatusCreated { + // t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code) + // } } func TestPostContainersCreate(t *testing.T) { @@ -1165,7 +1191,7 @@ func TestPostContainersAttach(t *testing.T) { container.Wait() } -// FIXME: Test deleting runnign container +// FIXME: Test deleting running container // FIXME: Test deleting container with volume // FIXME: Test deleting volume in use by other container func TestDeleteContainers(t *testing.T) { From ae80c37054835dc0cd55f81c9f97ca07ed80081c Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Fri, 10 May 2013 13:58:21 -0700 Subject: [PATCH 05/15] Small fix within TestGetImagesJson --- api_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/api_test.go b/api_test.go index 355e93a511..1b139b7d63 100644 --- a/api_test.go +++ b/api_test.go @@ -12,7 +12,6 @@ import ( "net/http/httptest" "os" "path" - "strings" "testing" "time" ) @@ -169,8 +168,8 @@ func TestGetImagesJson(t *testing.T) { t.Errorf("Excepted no image Repository, %s found", images2[0].Repository) } - if images2[0].Id != GetTestImage(runtime).Id { - t.Errorf("Retrieved image Id differs, expected %s, received %d", GetTestImage(runtime).Id, images2[0].Id) + if images2[0].Id != GetTestImage(runtime).ShortId() { + t.Errorf("Retrieved image Id differs, expected %s, received %s", GetTestImage(runtime).ShortId(), images2[0].Id) } // filter=a From 052a15ace9bd6391ef1e935f949f986ee9840d47 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Fri, 10 May 2013 14:25:45 -0700 Subject: [PATCH 06/15] - Registry: Fix the checksums file path --- registry.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry.go b/registry.go index 49fb5710a1..b8a3e10599 100644 --- a/registry.go +++ b/registry.go @@ -316,7 +316,7 @@ func (graph *Graph) PullRepository(stdout io.Writer, remote, askedTag string, re err = func() error { localChecksums := make(map[string]string) remoteChecksums := []ImgListJson{} - checksumDictPth := path.Join(graph.Root, "..", "checksums") + checksumDictPth := path.Join(graph.Root, "checksums") if err := json.Unmarshal(checksumsJson, &remoteChecksums); err != nil { return err From a98eafaf58ea250d6cd75d2f175f66d705d4a0eb Mon Sep 17 00:00:00 2001 From: Paul Bowsher Date: Fri, 10 May 2013 22:49:42 +0100 Subject: [PATCH 07/15] Expand upon Builder documentation and tidy Standardizes on uppercase for instructions, gives example usage. Wrap at 80 columns --- docs/sources/builder/basics.rst | 113 +++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 38 deletions(-) diff --git a/docs/sources/builder/basics.rst b/docs/sources/builder/basics.rst index f7ce07926f..2e77822982 100644 --- a/docs/sources/builder/basics.rst +++ b/docs/sources/builder/basics.rst @@ -4,83 +4,120 @@ Docker Builder .. contents:: Table of Contents -1. Format +Docker Builder specifes a simple DSL which allows you to automate the steps you +would normally manually take to create an image. Docker Build will run your +steps and commit them along the way, giving you a final image. + +1. Usage +======== + +To use Docker Builder, assemble the steps into a text file (commonly referred to +as a Dockerfile) and supply this to `docker build` on STDIN, like so: + + ``docker build < Dockerfile`` + +Docker will run your steps one-by-one, committing the result if necessary, +before finally outputting the ID of your new image. + +2. Format ========= -The Docker builder format is quite simple: +The Dockerfile format is quite simple: ``instruction arguments`` -The first instruction must be `FROM` +The Instruction is not case-sensitive, however convention is for them to be +UPPERCASE in order to distinguish them from arguments more easily. -All instruction are to be placed in a file named `Dockerfile` +Dockerfiles are evaluated in order, therefore the first instruction must be +`FROM` in order to specify the base image from which you are building. -In order to place comments within a Dockerfile, simply prefix the line with "`#`" +Docker will ignore lines in Dockerfiles prefixed with "`#`", so you may add +comment lines. A comment marker in the rest of the line will be treated as an +argument. 2. Instructions =============== -Docker builder comes with a set of instructions: - -1. FROM: Set from what image to build -2. RUN: Execute a command -3. INSERT: Insert a remote file (http) into the image +Docker builder comes with a set of instructions, described below. 2.1 FROM -------- + ``FROM `` -The `FROM` instruction must be the first one in order for Builder to know from where to run commands. +The `FROM` instruction sets the base image for subsequent instructions. As such, +a valid Dockerfile must have it as its first instruction. -`FROM` can also be used in order to build multiple images within a single Dockerfile +`FROM` can be included multiple times within a single Dockerfile in order to +create multiple images. Simply make a note of the last image id output by the +commit before each new `FROM` command. 2.2 MAINTAINER -------------- + ``MAINTAINER `` -The `MAINTAINER` instruction allow you to set the Author field of the generated images. -This instruction is never automatically reset. +The `MAINTAINER` instruction allows you to set the Author field of the generated +images. 2.3 RUN ------- + ``RUN `` -The `RUN` instruction is the main one, it allows you to execute any commands on the `FROM` image and to save the results. -You can use as many `RUN` as you want within a Dockerfile, the commands will be executed on the result of the previous command. +The `RUN` instruction will execute any commands on the current image and commit +the results. The resulting committed image will be used for the next step in the +Dockerfile. +Layering `RUN` instructions and generating commits conforms to the +core concepts of Docker where commits are cheap and containers can be created +from any point in an image's history, much like source control. 2.4 CMD ------- + ``CMD `` The `CMD` instruction sets the command to be executed when running the image. -It is equivalent to do `docker commit -run '{"Cmd": }'` outside the builder. +This is functionally equivalent to running +`docker commit -run '{"Cmd": }'` outside the builder. .. note:: - Do not confuse `RUN` with `CMD`. `RUN` actually run a command and save the result, `CMD` does not execute anything. + Don't confuse `RUN` with `CMD`. `RUN` actually runs a command and commits + the result; `CMD` does not execute anything at build time, but specifies the + intended command for the image. 2.5 EXPOSE ---------- + ``EXPOSE [...]`` -The `EXPOSE` instruction sets ports to be publicly exposed when running the image. -This is equivalent to do `docker commit -run '{"PortSpecs": ["", ""]}'` outside the builder. +The `EXPOSE` instruction sets ports to be publicly exposed when running the +image. This is functionally equivalent to running +`docker commit -run '{"PortSpecs": ["", ""]}'` outside the builder. 2.6 ENV ------- + ``ENV `` -The `ENV` instruction set as environment variable `` with the value ``. This value will be passed to all future ``RUN`` instructions. +The `ENV` instruction sets the environment variable `` to the value +``. This value will be passed to all future ``RUN`` instructions. This is +functionally equivalent to prefixing the command with `=` .. note:: - The environment variables are local to the Dockerfile, they will not be set as autorun. + The environment variables are local to the Dockerfile, they will not persist + when a container is run from the resulting image. 2.7 INSERT ---------- ``INSERT `` -The `INSERT` instruction will download the file at the given url and place it within the image at the given path. +The `INSERT` instruction will download the file from the given url to the given +path within the image. It is similar to `RUN curl -o `, assuming +curl was installed within the image. .. note:: The path must include the file name. @@ -96,15 +133,15 @@ The `INSERT` instruction will download the file at the given url and place it wi # VERSION 0.0.1 # DOCKER-VERSION 0.2 - from ubuntu - maintainer Guillaume J. Charmes "guillaume@dotcloud.com" + FROM ubuntu + MAINTAINER Guillaume J. Charmes "guillaume@dotcloud.com" # make sure the package repository is up to date - run echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list - run apt-get update + RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list + RUN apt-get update - run apt-get install -y inotify-tools nginx apache2 openssh-server - insert https://raw.github.com/creack/docker-vps/master/nginx-wrapper.sh /usr/sbin/nginx-wrapper + RUN apt-get install -y inotify-tools nginx apache2 openssh-server + INSERT https://raw.github.com/creack/docker-vps/master/nginx-wrapper.sh /usr/sbin/nginx-wrapper :: @@ -113,18 +150,18 @@ The `INSERT` instruction will download the file at the given url and place it wi # VERSION 0.3 # DOCKER-VERSION 0.2 - from ubuntu + FROM ubuntu # make sure the package repository is up to date - run echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list - run apt-get update + RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list + RUN apt-get update # Install vnc, xvfb in order to create a 'fake' display and firefox - run apt-get install -y x11vnc xvfb firefox - run mkdir /.vnc + RUN apt-get install -y x11vnc xvfb firefox + RUN mkdir /.vnc # Setup a password - run x11vnc -storepasswd 1234 ~/.vnc/passwd + RUN x11vnc -storepasswd 1234 ~/.vnc/passwd # Autostart firefox (might not be the best way to do it, but it does the trick) - run bash -c 'echo "firefox" >> /.bashrc' + RUN bash -c 'echo "firefox" >> /.bashrc' - expose 5900 - cmd ["x11vnc", "-forever", "-usepw", "-create"] + EXPOSE 5900 + CMD ["x11vnc", "-forever", "-usepw", "-create"] From 7cc082347f4adf3188c9614a9e9a82c2d6ff5656 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 10 May 2013 20:20:49 +0200 Subject: [PATCH 08/15] refactor api.go --- api.go | 285 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 154 insertions(+), 131 deletions(-) diff --git a/api.go b/api.go index 9485fca051..84975bffa5 100644 --- a/api.go +++ b/api.go @@ -39,22 +39,24 @@ func httpError(w http.ResponseWriter, err error) { } } -func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &auth.AuthConfig{ Username: srv.runtime.authConfig.Username, Email: srv.runtime.authConfig.Email, } b, err := json.Marshal(config) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &auth.AuthConfig{} if err := json.NewDecoder(r.Body).Decode(config); err != nil { - return nil, err + return err } if config.Username == srv.runtime.authConfig.Username { @@ -64,7 +66,7 @@ func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[stri newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root) status, err := auth.Login(newAuthConfig) if err != nil { - return nil, err + return err } else { srv.runtime.graph.getHttpClient().Jar = cookiejar.NewCookieJar() srv.runtime.authConfig = newAuthConfig @@ -72,38 +74,42 @@ func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[stri if status != "" { b, err := json.Marshal(&ApiAuth{Status: status}) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func getVersion(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getVersion(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { m := srv.DockerVersion() b, err := json.Marshal(m) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postContainersKill(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersKill(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ContainerKill(name); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] @@ -111,12 +117,12 @@ func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, va Debugf("%s", err.Error()) //return nil, err } - return nil, nil + return nil } -func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } all := r.Form.Get("all") == "1" @@ -125,66 +131,74 @@ func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map outs, err := srv.Images(all, only_ids, filter) if err != nil { - return nil, err + return err } b, err := json.Marshal(outs) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getImagesViz(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesViz(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := srv.ImagesViz(w); err != nil { - return nil, err + return err } - return nil, nil + return nil } -func getInfo(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getInfo(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { out := srv.DockerInfo() b, err := json.Marshal(out) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getImagesHistory(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesHistory(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] outs, err := srv.ImageHistory(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(outs) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getContainersChanges(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getContainersChanges(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] changesStr, err := srv.ContainerChanges(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(changesStr) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } all := r.Form.Get("all") == "1" trunc_cmd := r.Form.Get("trunc_cmd") != "0" @@ -199,33 +213,35 @@ func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars m outs := srv.Containers(all, trunc_cmd, only_ids, n, since, before) b, err := json.Marshal(outs) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postImagesTag(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postImagesTag(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } repo := r.Form.Get("repo") tag := r.Form.Get("tag") if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] force := r.Form.Get("force") == "1" if err := srv.ContainerTag(name, repo, tag, force); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusCreated) - return nil, nil + return nil } -func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } config := &Config{} if err := json.NewDecoder(r.Body).Decode(config); err != nil { @@ -238,20 +254,22 @@ func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st comment := r.Form.Get("comment") id, err := srv.ContainerCommit(container, repo, tag, author, comment, config) if err != nil { - return nil, err + return err } b, err := json.Marshal(&ApiId{id}) if err != nil { - return nil, err + return err } w.WriteHeader(http.StatusCreated) - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } // Creates an image from Pull or from Import -func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } src := r.Form.Get("fromSrc") @@ -261,7 +279,7 @@ func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") @@ -275,95 +293,97 @@ func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars fmt.Fprintf(out, "Error: %s\n", err) } } - return nil, nil + return nil } -func getImagesSearch(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesSearch(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } term := r.Form.Get("term") outs, err := srv.ImagesSearch(term) if err != nil { - return nil, err + return err } b, err := json.Marshal(outs) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postImagesInsert(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postImagesInsert(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } url := r.Form.Get("url") path := r.Form.Get("path") if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") if err := srv.ImageInsert(name, url, path, out); err != nil { fmt.Fprintf(out, "Error: %s\n", err) } - return nil, nil + return nil } -func postImagesPush(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postImagesPush(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } registry := r.Form.Get("registry") if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") if err := srv.ImagePush(name, registry, out); err != nil { fmt.Fprintln(out, "Error: %s\n", err) } - return nil, nil + return nil } -func postBuild(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postBuild(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") if err := srv.ImageCreateFromFile(in, out); err != nil { fmt.Fprintln(out, "Error: %s\n", err) } - return nil, nil + return nil } -func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &Config{} if err := json.NewDecoder(r.Body).Decode(config); err != nil { - return nil, err + return err } id, err := srv.ContainerCreate(config) if err != nil { - return nil, err + return err } out := &ApiRun{ @@ -379,75 +399,77 @@ func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, v } b, err := json.Marshal(out) if err != nil { - return nil, err + return err } w.WriteHeader(http.StatusCreated) - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postContainersRestart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersRestart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } t, err := strconv.Atoi(r.Form.Get("t")) if err != nil || t < 0 { t = 10 } if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ContainerRestart(name, t); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func deleteContainers(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func deleteContainers(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] removeVolume := r.Form.Get("v") == "1" if err := srv.ContainerDestroy(name, removeVolume); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func deleteImages(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func deleteImages(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ImageDelete(name); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func postContainersStart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersStart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ContainerStart(name); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func postContainersStop(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersStop(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } t, err := strconv.Atoi(r.Form.Get("t")) if err != nil || t < 0 { @@ -455,36 +477,38 @@ func postContainersStop(srv *Server, w http.ResponseWriter, r *http.Request, var } if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] if err := srv.ContainerStop(name, t); err != nil { - return nil, err + return err } w.WriteHeader(http.StatusNoContent) - return nil, nil + return nil } -func postContainersWait(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersWait(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] status, err := srv.ContainerWait(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(&ApiWait{StatusCode: status}) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { - return nil, err + return err } logs := r.Form.Get("logs") == "1" stream := r.Form.Get("stream") == "1" @@ -492,13 +516,13 @@ func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, v stdout := r.Form.Get("stdout") == "1" stderr := r.Form.Get("stderr") == "1" if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] in, out, err := hijackServer(w) if err != nil { - return nil, err + return err } defer in.Close() @@ -506,48 +530,52 @@ func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, v if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, in, out); err != nil { fmt.Fprintf(out, "Error: %s\n", err) } - return nil, nil + return nil } -func getContainersByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getContainersByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] container, err := srv.ContainerInspect(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(container) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } -func getImagesByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { +func getImagesByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { - return nil, fmt.Errorf("Missing parameter") + return fmt.Errorf("Missing parameter") } name := vars["name"] image, err := srv.ImageInspect(name) if err != nil { - return nil, err + return err } b, err := json.Marshal(image) if err != nil { - return nil, err + return err } - return b, nil + w.Header().Set("Content-Type", "application/json") + w.Write(b) + return nil } func ListenAndServe(addr string, srv *Server, logging bool) error { r := mux.NewRouter() log.Printf("Listening for HTTP on %s\n", addr) - m := map[string]map[string]func(*Server, http.ResponseWriter, *http.Request, map[string]string) ([]byte, error){ + m := map[string]map[string]func(*Server, http.ResponseWriter, *http.Request, map[string]string) error{ "GET": { "/auth": getAuth, "/version": getVersion, @@ -602,14 +630,9 @@ func ListenAndServe(addr string, srv *Server, logging bool) error { Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], VERSION) } } - json, err := localFct(srv, w, r, mux.Vars(r)) - if err != nil { + if err := localFct(srv, w, r, mux.Vars(r)); err != nil { httpError(w, err) } - if json != nil { - w.Header().Set("Content-Type", "application/json") - w.Write(json) - } }) } } From f7beba3accf22f1549aef9ed70bbde2afbdc4af0 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 10 May 2013 21:11:59 +0200 Subject: [PATCH 09/15] add writeJson --- api.go | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/api.go b/api.go index 84975bffa5..2198a0963a 100644 --- a/api.go +++ b/api.go @@ -39,6 +39,11 @@ func httpError(w http.ResponseWriter, err error) { } } +func writeJson(w http.ResponseWriter, b []byte) { + w.Header().Set("Content-Type", "application/json") + w.Write(b) +} + func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &auth.AuthConfig{ Username: srv.runtime.authConfig.Username, @@ -48,8 +53,7 @@ func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[strin if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -76,8 +80,7 @@ func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[stri if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } w.WriteHeader(http.StatusNoContent) @@ -90,8 +93,7 @@ func getVersion(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -137,8 +139,7 @@ func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -155,8 +156,7 @@ func getInfo(srv *Server, w http.ResponseWriter, r *http.Request, vars map[strin if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -173,8 +173,7 @@ func getImagesHistory(srv *Server, w http.ResponseWriter, r *http.Request, vars if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -191,8 +190,7 @@ func getContainersChanges(srv *Server, w http.ResponseWriter, r *http.Request, v if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -215,8 +213,7 @@ func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars m if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -261,8 +258,7 @@ func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st return err } w.WriteHeader(http.StatusCreated) - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -310,8 +306,7 @@ func getImagesSearch(srv *Server, w http.ResponseWriter, r *http.Request, vars m if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -402,8 +397,7 @@ func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, v return err } w.WriteHeader(http.StatusCreated) - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -501,8 +495,7 @@ func postContainersWait(srv *Server, w http.ResponseWriter, r *http.Request, var if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -547,8 +540,7 @@ func getContainersByName(srv *Server, w http.ResponseWriter, r *http.Request, va if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } @@ -566,8 +558,7 @@ func getImagesByName(srv *Server, w http.ResponseWriter, r *http.Request, vars m if err != nil { return err } - w.Header().Set("Content-Type", "application/json") - w.Write(b) + writeJson(w, b) return nil } From b99446831f576d626f78be7baea09af8520d125b Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Fri, 10 May 2013 15:24:07 -0700 Subject: [PATCH 10/15] Update api_test.go to reflect new api.go --- api_test.go | 192 +++++++++++++++++++--------------------------------- 1 file changed, 71 insertions(+), 121 deletions(-) diff --git a/api_test.go b/api_test.go index 1b139b7d63..68e60adc21 100644 --- a/api_test.go +++ b/api_test.go @@ -43,13 +43,9 @@ func TestGetAuth(t *testing.T) { t.Fatal(err) } - body, err := postAuth(srv, r, req, nil) - if err != nil { + if err := postAuth(srv, r, req, nil); err != nil { t.Fatal(err) } - if body == nil { - t.Fatalf("No body received\n") - } if r.Code != http.StatusOK && r.Code != 0 { t.Fatalf("%d OK or 0 expected, received %d\n", http.StatusOK, r.Code) } @@ -70,15 +66,14 @@ func TestGetVersion(t *testing.T) { srv := &Server{runtime: runtime} - body, err := getVersion(srv, nil, nil, nil) - if err != nil { + r := httptest.NewRecorder() + + if err := getVersion(srv, r, nil, nil); err != nil { t.Fatal(err) } v := &ApiVersion{} - - err = json.Unmarshal(body, v) - if err != nil { + if err = json.Unmarshal(r.Body.Bytes(), v); err != nil { t.Fatal(err) } if v.Version != VERSION { @@ -95,12 +90,14 @@ func TestGetInfo(t *testing.T) { srv := &Server{runtime: runtime} - body, err := getInfo(srv, nil, nil, nil) - if err != nil { + r := httptest.NewRecorder() + + if err := getInfo(srv, r, nil, nil); err != nil { t.Fatal(err) } + infos := &ApiInfo{} - err = json.Unmarshal(body, infos) + err = json.Unmarshal(r.Body.Bytes(), infos) if err != nil { t.Fatal(err) } @@ -124,14 +121,14 @@ func TestGetImagesJson(t *testing.T) { t.Fatal(err) } - body, err := getImagesJson(srv, nil, req, nil) - if err != nil { + r := httptest.NewRecorder() + + if err := getImagesJson(srv, r, req, nil); err != nil { t.Fatal(err) } images := []ApiImages{} - err = json.Unmarshal(body, &images) - if err != nil { + if err := json.Unmarshal(r.Body.Bytes(), &images); err != nil { t.Fatal(err) } @@ -143,20 +140,20 @@ func TestGetImagesJson(t *testing.T) { t.Errorf("Excepted image %s, %s found", unitTestImageName, images[0].Repository) } + r2 := httptest.NewRecorder() + // only_ids=1&all=1 req2, err := http.NewRequest("GET", "/images/json?only_ids=1&all=1", nil) if err != nil { t.Fatal(err) } - body2, err := getImagesJson(srv, nil, req2, nil) - if err != nil { + if err := getImagesJson(srv, r2, req2, nil); err != nil { t.Fatal(err) } images2 := []ApiImages{} - err = json.Unmarshal(body2, &images2) - if err != nil { + if err := json.Unmarshal(r2.Body.Bytes(), &images2); err != nil { t.Fatal(err) } @@ -172,20 +169,20 @@ func TestGetImagesJson(t *testing.T) { t.Errorf("Retrieved image Id differs, expected %s, received %s", GetTestImage(runtime).ShortId(), images2[0].Id) } + r3 := httptest.NewRecorder() + // filter=a req3, err := http.NewRequest("GET", "/images/json?filter=a", nil) if err != nil { t.Fatal(err) } - body3, err := getImagesJson(srv, nil, req3, nil) - if err != nil { + if err := getImagesJson(srv, r3, req3, nil); err != nil { t.Fatal(err) } images3 := []ApiImages{} - err = json.Unmarshal(body3, &images3) - if err != nil { + if err := json.Unmarshal(r3.Body.Bytes(), &images3); err != nil { t.Fatal(err) } @@ -204,9 +201,7 @@ func TestGetImagesViz(t *testing.T) { srv := &Server{runtime: runtime} r := httptest.NewRecorder() - - _, err = getImagesViz(srv, r, nil, nil) - if err != nil { + if err := getImagesViz(srv, r, nil, nil); err != nil { t.Fatal(err) } @@ -233,19 +228,19 @@ func TestGetImagesSearch(t *testing.T) { srv := &Server{runtime: runtime} + r := httptest.NewRecorder() + req, err := http.NewRequest("GET", "/images/search?term=redis", nil) if err != nil { t.Fatal(err) } - body, err := getImagesSearch(srv, nil, req, nil) - if err != nil { + if err := getImagesSearch(srv, r, req, nil); err != nil { t.Fatal(err) } results := []ApiSearch{} - err = json.Unmarshal(body, &results) - if err != nil { + if err := json.Unmarshal(r.Body.Bytes(), &results); err != nil { t.Fatal(err) } if len(results) < 2 { @@ -262,14 +257,14 @@ func TestGetImagesHistory(t *testing.T) { srv := &Server{runtime: runtime} - body, err := getImagesHistory(srv, nil, nil, map[string]string{"name": unitTestImageName}) - if err != nil { + r := httptest.NewRecorder() + + if err := getImagesHistory(srv, r, nil, map[string]string{"name": unitTestImageName}); err != nil { t.Fatal(err) } history := []ApiHistory{} - err = json.Unmarshal(body, &history) - if err != nil { + if err := json.Unmarshal(r.Body.Bytes(), &history); err != nil { t.Fatal(err) } if len(history) != 1 { @@ -286,15 +281,13 @@ func TestGetImagesByName(t *testing.T) { srv := &Server{runtime: runtime} - body, err := getImagesByName(srv, nil, nil, map[string]string{"name": unitTestImageName}) - if err != nil { + r := httptest.NewRecorder() + if err := getImagesByName(srv, r, nil, map[string]string{"name": unitTestImageName}); err != nil { t.Fatal(err) } img := &Image{} - - err = json.Unmarshal(body, img) - if err != nil { + if err := json.Unmarshal(r.Body.Bytes(), img); err != nil { t.Fatal(err) } if img.Id != GetTestImage(runtime).Id || img.Comment != "Imported from http://get.docker.io/images/busybox" { @@ -325,13 +318,12 @@ func TestGetContainersPs(t *testing.T) { t.Fatal(err) } - body, err := getContainersPs(srv, nil, req, nil) - if err != nil { + r := httptest.NewRecorder() + if err := getContainersPs(srv, r, req, nil); err != nil { t.Fatal(err) } containers := []ApiContainers{} - err = json.Unmarshal(body, &containers) - if err != nil { + if err := json.Unmarshal(r.Body.Bytes(), &containers); err != nil { t.Fatal(err) } if len(containers) != 1 { @@ -370,9 +362,7 @@ func TestGetContainersExport(t *testing.T) { } r := httptest.NewRecorder() - - _, err = getContainersExport(srv, r, nil, map[string]string{"name": container.Id}) - if err != nil { + if err = getContainersExport(srv, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } @@ -426,12 +416,12 @@ func TestGetContainersChanges(t *testing.T) { t.Fatal(err) } - body, err := getContainersChanges(srv, nil, nil, map[string]string{"name": container.Id}) - if err != nil { + r := httptest.NewRecorder() + if err := getContainersChanges(srv, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } changes := []Change{} - if err := json.Unmarshal(body, &changes); err != nil { + if err := json.Unmarshal(r.Body.Bytes(), &changes); err != nil { t.Fatal(err) } @@ -470,12 +460,12 @@ func TestGetContainersByName(t *testing.T) { } defer runtime.Destroy(container) - body, err := getContainersByName(srv, nil, nil, map[string]string{"name": container.Id}) - if err != nil { + r := httptest.NewRecorder() + if err := getContainersByName(srv, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } outContainer := &Container{} - if err := json.Unmarshal(body, outContainer); err != nil { + if err := json.Unmarshal(r.Body.Bytes(), outContainer); err != nil { t.Fatal(err) } if outContainer.Id != container.Id { @@ -498,14 +488,13 @@ func TestPostAuth(t *testing.T) { } runtime.authConfig = authConfigOrig - body, err := getAuth(srv, nil, nil, nil) - if err != nil { + r := httptest.NewRecorder() + if err := getAuth(srv, r, nil, nil); err != nil { t.Fatal(err) } authConfig := &auth.AuthConfig{} - err = json.Unmarshal(body, authConfig) - if err != nil { + if err := json.Unmarshal(r.Body.Bytes(), authConfig); err != nil { t.Fatal(err) } @@ -523,8 +512,6 @@ func TestPostCommit(t *testing.T) { srv := &Server{runtime: runtime} - r := httptest.NewRecorder() - builder := NewBuilder(runtime) // Create a container and remove a file @@ -548,8 +535,8 @@ func TestPostCommit(t *testing.T) { t.Fatal(err) } - body, err := postCommit(srv, r, req, nil) - if err != nil { + r := httptest.NewRecorder() + if err := postCommit(srv, r, req, nil); err != nil { t.Fatal(err) } if r.Code != http.StatusCreated { @@ -557,7 +544,7 @@ func TestPostCommit(t *testing.T) { } apiId := &ApiId{} - if err := json.Unmarshal(body, apiId); err != nil { + if err := json.Unmarshal(r.Body.Bytes(), apiId); err != nil { t.Fatal(err) } if _, err := runtime.graph.Get(apiId.Id); err != nil { @@ -579,20 +566,16 @@ func TestPostBuild(t *testing.T) { c1 := make(chan struct{}) go func() { + defer close(c1) r := &hijackTester{ ResponseRecorder: httptest.NewRecorder(), in: stdin, out: stdoutPipe, } - body, err := postBuild(srv, r, nil, nil) - close(c1) - if err != nil { + if err := postBuild(srv, r, nil, nil); err != nil { t.Fatal(err) } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } }() // Acknowledge hijack @@ -794,8 +777,6 @@ func TestPostContainersCreate(t *testing.T) { srv := &Server{runtime: runtime} - r := httptest.NewRecorder() - configJson, err := json.Marshal(&Config{ Image: GetTestImage(runtime).Id, Memory: 33554432, @@ -810,8 +791,8 @@ func TestPostContainersCreate(t *testing.T) { t.Fatal(err) } - body, err := postContainersCreate(srv, r, req, nil) - if err != nil { + r := httptest.NewRecorder() + if err := postContainersCreate(srv, r, req, nil); err != nil { t.Fatal(err) } if r.Code != http.StatusCreated { @@ -819,7 +800,7 @@ func TestPostContainersCreate(t *testing.T) { } apiRun := &ApiRun{} - if err := json.Unmarshal(body, apiRun); err != nil { + if err := json.Unmarshal(r.Body.Bytes(), apiRun); err != nil { t.Fatal(err) } @@ -874,14 +855,9 @@ func TestPostContainersKill(t *testing.T) { } r := httptest.NewRecorder() - - body, err := postContainersKill(srv, r, nil, map[string]string{"name": container.Id}) - if err != nil { + if err := postContainersKill(srv, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } if r.Code != http.StatusNoContent { t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code) } @@ -922,19 +898,14 @@ func TestPostContainersRestart(t *testing.T) { t.Errorf("Container should be running") } - r := httptest.NewRecorder() - req, err := http.NewRequest("POST", "/containers/"+container.Id+"/restart?t=1", bytes.NewReader([]byte{})) if err != nil { t.Fatal(err) } - body, err := postContainersRestart(srv, r, req, map[string]string{"name": container.Id}) - if err != nil { + r := httptest.NewRecorder() + if err := postContainersRestart(srv, r, req, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } if r.Code != http.StatusNoContent { t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code) } @@ -973,14 +944,9 @@ func TestPostContainersStart(t *testing.T) { defer runtime.Destroy(container) r := httptest.NewRecorder() - - body, err := postContainersStart(srv, r, nil, map[string]string{"name": container.Id}) - if err != nil { + if err := postContainersStart(srv, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } if r.Code != http.StatusNoContent { t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code) } @@ -992,7 +958,8 @@ func TestPostContainersStart(t *testing.T) { t.Errorf("Container should be running") } - if _, err = postContainersStart(srv, r, nil, map[string]string{"name": container.Id}); err == nil { + r = httptest.NewRecorder() + if err = postContainersStart(srv, r, nil, map[string]string{"name": container.Id}); err == nil { t.Fatalf("A running containter should be able to be started") } @@ -1033,20 +1000,15 @@ func TestPostContainersStop(t *testing.T) { t.Errorf("Container should be running") } - r := httptest.NewRecorder() - // Note: as it is a POST request, it requires a body. req, err := http.NewRequest("POST", "/containers/"+container.Id+"/stop?t=1", bytes.NewReader([]byte{})) if err != nil { t.Fatal(err) } - body, err := postContainersStop(srv, r, req, map[string]string{"name": container.Id}) - if err != nil { + r := httptest.NewRecorder() + if err := postContainersStop(srv, r, req, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } if r.Code != http.StatusNoContent { t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code) } @@ -1081,12 +1043,12 @@ func TestPostContainersWait(t *testing.T) { } setTimeout(t, "Wait timed out", 3*time.Second, func() { - body, err := postContainersWait(srv, nil, nil, map[string]string{"name": container.Id}) - if err != nil { + r := httptest.NewRecorder() + if err := postContainersWait(srv, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } apiWait := &ApiWait{} - if err := json.Unmarshal(body, apiWait); err != nil { + if err := json.Unmarshal(r.Body.Bytes(), apiWait); err != nil { t.Fatal(err) } if apiWait.StatusCode != 0 { @@ -1131,8 +1093,7 @@ func TestPostContainersAttach(t *testing.T) { // Attach to it c1 := make(chan struct{}) go func() { - // We're simulating a disconnect so the return value doesn't matter. What matters is the - // fact that CmdAttach returns. + defer close(c1) r := &hijackTester{ ResponseRecorder: httptest.NewRecorder(), @@ -1145,14 +1106,9 @@ func TestPostContainersAttach(t *testing.T) { t.Fatal(err) } - body, err := postContainersAttach(srv, r, req, map[string]string{"name": container.Id}) - close(c1) - if err != nil { + if err := postContainersAttach(srv, r, req, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } }() // Acknowledge hijack @@ -1215,20 +1171,14 @@ func TestDeleteContainers(t *testing.T) { t.Fatal(err) } - r := httptest.NewRecorder() - req, err := http.NewRequest("DELETE", "/containers/"+container.Id, nil) if err != nil { t.Fatal(err) } - - body, err := deleteContainers(srv, r, req, map[string]string{"name": container.Id}) - if err != nil { + r := httptest.NewRecorder() + if err := deleteContainers(srv, r, req, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } - if body != nil { - t.Fatalf("No body expected, received: %s\n", body) - } if r.Code != http.StatusNoContent { t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code) } @@ -1244,7 +1194,7 @@ func TestDeleteContainers(t *testing.T) { func TestDeleteImages(t *testing.T) { //FIXME: Implement this test - t.Log("Test not implemented") + t.Skip("Test not implemented") } // Mocked types for tests From 9416574569b3969f1844c83cf4e24bc50957aaf5 Mon Sep 17 00:00:00 2001 From: Paul Bowsher Date: Sat, 11 May 2013 18:34:26 +0100 Subject: [PATCH 11/15] Make examples bash-highlighted Remove DOCKER-VERSION, easier to maintain Add example of multiple FROM steps --- docs/sources/builder/basics.rst | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/sources/builder/basics.rst b/docs/sources/builder/basics.rst index 2e77822982..735b2e575f 100644 --- a/docs/sources/builder/basics.rst +++ b/docs/sources/builder/basics.rst @@ -126,12 +126,11 @@ curl was installed within the image. 3. Dockerfile Examples ====================== -:: +.. code-block:: bash # Nginx # # VERSION 0.0.1 - # DOCKER-VERSION 0.2 FROM ubuntu MAINTAINER Guillaume J. Charmes "guillaume@dotcloud.com" @@ -143,12 +142,11 @@ curl was installed within the image. RUN apt-get install -y inotify-tools nginx apache2 openssh-server INSERT https://raw.github.com/creack/docker-vps/master/nginx-wrapper.sh /usr/sbin/nginx-wrapper -:: +.. code-block:: bash # Firefox over VNC # # VERSION 0.3 - # DOCKER-VERSION 0.2 FROM ubuntu # make sure the package repository is up to date @@ -160,8 +158,25 @@ curl was installed within the image. RUN mkdir /.vnc # Setup a password RUN x11vnc -storepasswd 1234 ~/.vnc/passwd - # Autostart firefox (might not be the best way to do it, but it does the trick) + # Autostart firefox (might not be the best way, but it does the trick) RUN bash -c 'echo "firefox" >> /.bashrc' EXPOSE 5900 CMD ["x11vnc", "-forever", "-usepw", "-create"] + +.. code-block:: bash + + # Multiple images example + # + # VERSION 0.1 + + FROM ubuntu + RUN echo foo > bar + # Will output something like ===> 907ad6c2736f + + FROM ubuntu + RUN echo moo > oink + # Will output something like ===> 695d7793cbe4 + + # You'll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with + # /oink. \ No newline at end of file From a47d8799b190ba44d7bea2a39e05f98f6019f952 Mon Sep 17 00:00:00 2001 From: Jonas Pfenniger Date: Sat, 11 May 2013 23:50:06 +0100 Subject: [PATCH 12/15] Fixes the README build example to make it work --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b22c731691..1f69e4d833 100644 --- a/README.md +++ b/README.md @@ -77,14 +77,14 @@ commands, the *order* in which the commands are executed expresses *dependencies Here's a typical docker build process: ```bash -from ubuntu:12.10 -run apt-get update -run apt-get install python -run apt-get install python-pip -run pip install django -run apt-get install curl -run curl http://github.com/shykes/helloflask/helloflask/master.tar.gz | tar -zxv -run cd master && pip install -r requirements.txt +from ubuntu:12.10 +run apt-get update +run DEBIAN_FRONTEND=noninteractive apt-get install -q -y python +run DEBIAN_FRONTEND=noninteractive apt-get install -q -y python-pip +run pip install django +run DEBIAN_FRONTEND=noninteractive apt-get install -q -y curl +run curl -L https://github.com/shykes/helloflask/archive/master.tar.gz | tar -xzv +run cd helloflask-master && pip install -r requirements.txt ``` Note that Docker doesn't care *how* dependencies are built - as long as they can be built by running a unix command in a container. From 8b31d30601f487bca5e4985c6a14b89e47ac83be Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 13 May 2013 11:38:13 +0200 Subject: [PATCH 13/15] fix error message in export --- api.go | 2 +- commands.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/api.go b/api.go index 2198a0963a..162dc66160 100644 --- a/api.go +++ b/api.go @@ -117,7 +117,7 @@ func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, va if err := srv.ContainerExport(name, w); err != nil { Debugf("%s", err.Error()) - //return nil, err + return err } return nil } diff --git a/commands.go b/commands.go index dc3f8c4e87..a8363925b2 100644 --- a/commands.go +++ b/commands.go @@ -1196,6 +1196,14 @@ func stream(method, path string) error { return err } defer resp.Body.Close() + if resp.StatusCode < 200 || resp.StatusCode >= 400 { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + return fmt.Errorf("error: %s", body) + } + if _, err := io.Copy(os.Stdout, resp.Body); err != nil { return err } From 182842e3c3cb56e8b2012629d06822c8f395e826 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 13 May 2013 19:19:27 +0200 Subject: [PATCH 14/15] fix error push --- api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.go b/api.go index 2198a0963a..0a9f86a991 100644 --- a/api.go +++ b/api.go @@ -353,7 +353,7 @@ func postImagesPush(srv *Server, w http.ResponseWriter, r *http.Request, vars ma defer in.Close() fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") if err := srv.ImagePush(name, registry, out); err != nil { - fmt.Fprintln(out, "Error: %s\n", err) + fmt.Fprintf(out, "Error: %s\n", err) } return nil } From 824ad4274a6de5bacb67bce892faaeb0094977b2 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 13 May 2013 10:45:45 -0700 Subject: [PATCH 15/15] Change t.Skip to t.Log in tests for go1.0.3 compatibility --- api_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api_test.go b/api_test.go index 68e60adc21..2128f3ef35 100644 --- a/api_test.go +++ b/api_test.go @@ -1194,7 +1194,7 @@ func TestDeleteContainers(t *testing.T) { func TestDeleteImages(t *testing.T) { //FIXME: Implement this test - t.Skip("Test not implemented") + t.Log("Test not implemented") } // Mocked types for tests