diff --git a/components/engine/api.go b/components/engine/api/api.go similarity index 76% rename from components/engine/api.go rename to components/engine/api/api.go index 4d294667ac..b722eb5c60 100644 --- a/components/engine/api.go +++ b/components/engine/api/api.go @@ -1,4 +1,4 @@ -package docker +package api import ( "bufio" @@ -34,7 +34,11 @@ const ( DEFAULTUNIXSOCKET = "/var/run/docker.sock" ) -type HttpApiFunc func(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error +type HttpApiFunc func(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error + +func init() { + engine.Register("serveapi", ServeApi) +} func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) { conn, _, err := w.(http.Hijacker).Hijack() @@ -106,7 +110,20 @@ func getBoolParam(value string) (bool, error) { return ret, nil } -func matchesContentType(contentType, expectedType string) bool { +//TODO remove, used on < 1.5 in getContainersJSON +func displayablePorts(ports *engine.Table) string { + result := []string{} + for _, port := range ports.Data { + if port.Get("IP") == "" { + result = append(result, fmt.Sprintf("%d/%s", port.GetInt("PublicPort"), port.Get("Type"))) + } else { + result = append(result, fmt.Sprintf("%s:%d->%d/%s", port.Get("IP"), port.GetInt("PublicPort"), port.GetInt("PrivatePort"), port.Get("Type"))) + } + } + return strings.Join(result, ", ") +} + +func MatchesContentType(contentType, expectedType string) bool { mimetype, _, err := mime.ParseMediaType(contentType) if err != nil { utils.Errorf("Error parsing media type: %s error: %s", contentType, err.Error()) @@ -114,10 +131,10 @@ func matchesContentType(contentType, expectedType string) bool { return err == nil && mimetype == expectedType } -func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postAuth(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var ( authConfig, err = ioutil.ReadAll(r.Body) - job = srv.Eng.Job("auth") + job = eng.Job("auth") status string ) if err != nil { @@ -137,20 +154,20 @@ func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Reque return nil } -func getVersion(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getVersion(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { w.Header().Set("Content-Type", "application/json") - srv.Eng.ServeHTTP(w, r) + eng.ServeHTTP(w, r) return nil } -func postContainersKill(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersKill(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } if err := parseForm(r); err != nil { return err } - job := srv.Eng.Job("kill", vars["name"]) + job := eng.Job("kill", vars["name"]) if sig := r.Form.Get("signal"); sig != "" { job.Args = append(job.Args, sig) } @@ -161,11 +178,11 @@ func postContainersKill(srv *Server, version float64, w http.ResponseWriter, r * return nil } -func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getContainersExport(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } - job := srv.Eng.Job("export", vars["name"]) + job := eng.Job("export", vars["name"]) job.Stdout.Add(w) if err := job.Run(); err != nil { return err @@ -173,7 +190,7 @@ func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r return nil } -func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesJSON(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -181,7 +198,7 @@ func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http. var ( err error outs *engine.Table - job = srv.Eng.Job("images") + job = eng.Job("images") ) job.Setenv("filter", r.Form.Get("filter")) @@ -219,39 +236,39 @@ func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http. return nil } -func getImagesViz(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesViz(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if version > 1.6 { w.WriteHeader(http.StatusNotFound) return fmt.Errorf("This is now implemented in the client.") } - srv.Eng.ServeHTTP(w, r) + eng.ServeHTTP(w, r) return nil } -func getInfo(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getInfo(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { w.Header().Set("Content-Type", "application/json") - srv.Eng.ServeHTTP(w, r) + eng.ServeHTTP(w, r) return nil } -func getEvents(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getEvents(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } w.Header().Set("Content-Type", "application/json") - var job = srv.Eng.Job("events", r.RemoteAddr) + var job = eng.Job("events", r.RemoteAddr) job.Stdout.Add(utils.NewWriteFlusher(w)) job.Setenv("since", r.Form.Get("since")) return job.Run() } -func getImagesHistory(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesHistory(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } - var job = srv.Eng.Job("history", vars["name"]) + var job = eng.Job("history", vars["name"]) job.Stdout.Add(w) if err := job.Run(); err != nil { @@ -260,17 +277,17 @@ func getImagesHistory(srv *Server, version float64, w http.ResponseWriter, r *ht return nil } -func getContainersChanges(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getContainersChanges(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } - var job = srv.Eng.Job("changes", vars["name"]) + var job = eng.Job("changes", vars["name"]) job.Stdout.Add(w) return job.Run() } -func getContainersTop(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getContainersTop(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if version < 1.4 { return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.") } @@ -281,19 +298,19 @@ func getContainersTop(srv *Server, version float64, w http.ResponseWriter, r *ht return err } - job := srv.Eng.Job("top", vars["name"], r.Form.Get("ps_args")) + job := eng.Job("top", vars["name"], r.Form.Get("ps_args")) job.Stdout.Add(w) return job.Run() } -func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getContainersJSON(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } var ( err error outs *engine.Table - job = srv.Eng.Job("containers") + job = eng.Job("containers") ) job.Setenv("all", r.Form.Get("all")) @@ -323,7 +340,7 @@ func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *h return nil } -func postImagesTag(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postImagesTag(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -331,7 +348,7 @@ func postImagesTag(srv *Server, version float64, w http.ResponseWriter, r *http. return fmt.Errorf("Missing parameter") } - job := srv.Eng.Job("tag", vars["name"], r.Form.Get("repo"), r.Form.Get("tag")) + job := eng.Job("tag", vars["name"], r.Form.Get("repo"), r.Form.Get("tag")) job.Setenv("force", r.Form.Get("force")) if err := job.Run(); err != nil { return err @@ -340,14 +357,14 @@ func postImagesTag(srv *Server, version float64, w http.ResponseWriter, r *http. return nil } -func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postCommit(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } var ( config engine.Env env engine.Env - job = srv.Eng.Job("commit", r.Form.Get("container")) + job = eng.Job("commit", r.Form.Get("container")) ) if err := config.Import(r.Body); err != nil { utils.Errorf("%s", err) @@ -369,7 +386,7 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req } // Creates an image from Pull or from Import -func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postImagesCreate(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -399,12 +416,12 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht metaHeaders[k] = v } } - job = srv.Eng.Job("pull", r.Form.Get("fromImage"), tag) + job = eng.Job("pull", r.Form.Get("fromImage"), tag) job.SetenvBool("parallel", version > 1.3) job.SetenvJson("metaHeaders", metaHeaders) job.SetenvJson("authConfig", authConfig) } else { //import - job = srv.Eng.Job("import", r.Form.Get("fromSrc"), r.Form.Get("repo"), tag) + job = eng.Job("import", r.Form.Get("fromSrc"), r.Form.Get("repo"), tag) job.Stdin.Add(r.Body) } @@ -421,7 +438,7 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht return nil } -func getImagesSearch(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesSearch(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -445,7 +462,7 @@ func getImagesSearch(srv *Server, version float64, w http.ResponseWriter, r *htt } } - var job = srv.Eng.Job("search", r.Form.Get("term")) + var job = eng.Job("search", r.Form.Get("term")) job.SetenvJson("metaHeaders", metaHeaders) job.SetenvJson("authConfig", authConfig) job.Stdout.Add(w) @@ -453,7 +470,7 @@ func getImagesSearch(srv *Server, version float64, w http.ResponseWriter, r *htt return job.Run() } -func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postImagesInsert(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -464,7 +481,7 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht w.Header().Set("Content-Type", "application/json") } - job := srv.Eng.Job("insert", vars["name"], r.Form.Get("url"), r.Form.Get("path")) + job := eng.Job("insert", vars["name"], r.Form.Get("url"), r.Form.Get("path")) job.SetenvBool("json", version > 1.0) job.Stdout.Add(w) if err := job.Run(); err != nil { @@ -478,7 +495,7 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht return nil } -func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postImagesPush(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -512,7 +529,7 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http if version > 1.0 { w.Header().Set("Content-Type", "application/json") } - job := srv.Eng.Job("push", vars["name"]) + job := eng.Job("push", vars["name"]) job.SetenvJson("metaHeaders", metaHeaders) job.SetenvJson("authConfig", authConfig) job.SetenvBool("json", version > 1.0) @@ -528,31 +545,31 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http return nil } -func getImagesGet(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesGet(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } if version > 1.0 { w.Header().Set("Content-Type", "application/x-tar") } - job := srv.Eng.Job("image_export", vars["name"]) + job := eng.Job("image_export", vars["name"]) job.Stdout.Add(w) return job.Run() } -func postImagesLoad(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - job := srv.Eng.Job("load") +func postImagesLoad(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + job := eng.Job("load") job.Stdin.Add(r.Body) return job.Run() } -func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersCreate(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return nil } var ( out engine.Env - job = srv.Eng.Job("create", r.Form.Get("name")) + job = eng.Job("create", r.Form.Get("name")) outWarnings []string outId string warnings = bytes.NewBuffer(nil) @@ -577,14 +594,14 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r return writeJSON(w, http.StatusCreated, out) } -func postContainersRestart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersRestart(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } - job := srv.Eng.Job("restart", vars["name"]) + job := eng.Job("restart", vars["name"]) job.Setenv("t", r.Form.Get("t")) if err := job.Run(); err != nil { return err @@ -593,14 +610,14 @@ func postContainersRestart(srv *Server, version float64, w http.ResponseWriter, return nil } -func deleteContainers(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func deleteContainers(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } - job := srv.Eng.Job("container_delete", vars["name"]) + job := eng.Job("container_delete", vars["name"]) job.Setenv("removeVolume", r.Form.Get("v")) job.Setenv("removeLink", r.Form.Get("link")) if err := job.Run(); err != nil { @@ -610,29 +627,29 @@ func deleteContainers(srv *Server, version float64, w http.ResponseWriter, r *ht return nil } -func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func deleteImages(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } - var job = srv.Eng.Job("image_delete", vars["name"]) + var job = eng.Job("image_delete", vars["name"]) job.Stdout.Add(w) job.SetenvBool("autoPrune", version > 1.1) return job.Run() } -func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersStart(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } name := vars["name"] - job := srv.Eng.Job("start", name) + job := eng.Job("start", name) // allow a nil body for backwards compatibility if r.Body != nil { - if matchesContentType(r.Header.Get("Content-Type"), "application/json") { + if MatchesContentType(r.Header.Get("Content-Type"), "application/json") { if err := job.DecodeEnv(r.Body); err != nil { return err } @@ -645,14 +662,14 @@ func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r return nil } -func postContainersStop(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersStop(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } - job := srv.Eng.Job("stop", vars["name"]) + job := eng.Job("stop", vars["name"]) job.Setenv("t", r.Form.Get("t")) if err := job.Run(); err != nil { return err @@ -661,14 +678,14 @@ func postContainersStop(srv *Server, version float64, w http.ResponseWriter, r * return nil } -func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersWait(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } var ( env engine.Env status string - job = srv.Eng.Job("wait", vars["name"]) + job = eng.Job("wait", vars["name"]) ) job.Stdout.AddString(&status) if err := job.Run(); err != nil { @@ -683,20 +700,20 @@ func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r * return writeJSON(w, http.StatusOK, env) } -func postContainersResize(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersResize(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } - if err := srv.Eng.Job("resize", vars["name"], r.Form.Get("h"), r.Form.Get("w")).Run(); err != nil { + if err := eng.Job("resize", vars["name"], r.Form.Get("h"), r.Form.Get("w")).Run(); err != nil { return err } return nil } -func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersAttach(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -705,7 +722,7 @@ func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r } var ( - job = srv.Eng.Job("inspect", vars["name"], "container") + job = eng.Job("inspect", vars["name"], "container") c, err = job.Stdout.AddEnv() ) if err != nil { @@ -745,7 +762,7 @@ func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r errStream = outStream } - job = srv.Eng.Job("attach", vars["name"]) + job = eng.Job("attach", vars["name"]) job.Setenv("logs", r.Form.Get("logs")) job.Setenv("stream", r.Form.Get("stream")) job.Setenv("stdin", r.Form.Get("stdin")) @@ -761,7 +778,7 @@ func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r return nil } -func wsContainersAttach(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func wsContainersAttach(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -769,13 +786,13 @@ func wsContainersAttach(srv *Server, version float64, w http.ResponseWriter, r * return fmt.Errorf("Missing parameter") } - if err := srv.Eng.Job("inspect", vars["name"], "container").Run(); err != nil { + if err := eng.Job("inspect", vars["name"], "container").Run(); err != nil { return err } h := websocket.Handler(func(ws *websocket.Conn) { defer ws.Close() - job := srv.Eng.Job("attach", vars["name"]) + job := eng.Job("attach", vars["name"]) job.Setenv("logs", r.Form.Get("logs")) job.Setenv("stream", r.Form.Get("stream")) job.Setenv("stdin", r.Form.Get("stdin")) @@ -793,27 +810,27 @@ func wsContainersAttach(srv *Server, version float64, w http.ResponseWriter, r * return nil } -func getContainersByName(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getContainersByName(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } - var job = srv.Eng.Job("inspect", vars["name"], "container") + var job = eng.Job("inspect", vars["name"], "container") job.Stdout.Add(w) job.SetenvBool("conflict", true) //conflict=true to detect conflict between containers and images in the job return job.Run() } -func getImagesByName(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesByName(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } - var job = srv.Eng.Job("inspect", vars["name"], "image") + var job = eng.Job("inspect", vars["name"], "image") job.Stdout.Add(w) job.SetenvBool("conflict", true) //conflict=true to detect conflict between containers and images in the job return job.Run() } -func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postBuild(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if version < 1.3 { return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.") } @@ -822,7 +839,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ authConfig = &auth.AuthConfig{} configFileEncoded = r.Header.Get("X-Registry-Config") configFile = &auth.ConfigFile{} - job = srv.Eng.Job("build") + job = eng.Job("build") ) // This block can be removed when API versions prior to 1.9 are deprecated. @@ -870,7 +887,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ return nil } -func postContainersCopy(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersCopy(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -892,7 +909,7 @@ func postContainersCopy(srv *Server, version float64, w http.ResponseWriter, r * copyData.Set("Resource", copyData.Get("Resource")[1:]) } - job := srv.Eng.Job("container_copy", vars["name"], copyData.Get("Resource")) + job := eng.Job("container_copy", vars["name"], copyData.Get("Resource")) job.Stdout.Add(w) if err := job.Run(); err != nil { utils.Errorf("%s", err.Error()) @@ -900,7 +917,7 @@ func postContainersCopy(srv *Server, version float64, w http.ResponseWriter, r * return nil } -func optionsHandler(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func optionsHandler(eng *engine.Engine, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { w.WriteHeader(http.StatusOK) return nil } @@ -910,7 +927,7 @@ func writeCorsHeaders(w http.ResponseWriter, r *http.Request) { w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS") } -func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool) http.HandlerFunc { +func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // log the request utils.Debugf("Calling %s %s", localMethod, localRoute) @@ -921,8 +938,8 @@ func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute s if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") { userAgent := strings.Split(r.Header.Get("User-Agent"), "/") - if len(userAgent) == 2 && userAgent[1] != VERSION { - utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], VERSION) + if len(userAgent) == 2 && userAgent[1] != dockerVersion { + utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion) } } version, err := strconv.ParseFloat(mux.Vars(r)["version"], 64) @@ -938,7 +955,7 @@ func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute s return } - if err := handlerFunc(srv, version, w, r, mux.Vars(r)); err != nil { + if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil { utils.Errorf("Error: %s", err) httpError(w, err) } @@ -971,7 +988,7 @@ func AttachProfiler(router *mux.Router) { router.HandleFunc("/debug/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP) } -func createRouter(srv *Server, logging, enableCors bool) (*mux.Router, error) { +func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion string) (*mux.Router, error) { r := mux.NewRouter() if os.Getenv("DEBUG") != "" { AttachProfiler(r) @@ -1032,7 +1049,7 @@ func createRouter(srv *Server, logging, enableCors bool) (*mux.Router, error) { localMethod := method // build the handler function - f := makeHttpHandler(srv, logging, localMethod, localRoute, localFct, enableCors) + f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, enableCors, dockerVersion) // add the new route if localRoute == "" { @@ -1050,8 +1067,8 @@ func createRouter(srv *Server, logging, enableCors bool) (*mux.Router, error) { // ServeRequest processes a single http request to the docker remote api. // FIXME: refactor this to be part of Server and not require re-creating a new // router each time. This requires first moving ListenAndServe into Server. -func ServeRequest(srv *Server, apiversion float64, w http.ResponseWriter, req *http.Request) error { - router, err := createRouter(srv, false, true) +func ServeRequest(eng *engine.Engine, apiversion float64, w http.ResponseWriter, req *http.Request) error { + router, err := createRouter(eng, false, true, "") if err != nil { return err } @@ -1093,8 +1110,8 @@ func ServeFd(addr string, handle http.Handler) error { // ListenAndServe sets up the required http.Server and gets it listening for // each addr passed in and does protocol specific checking. -func ListenAndServe(proto, addr string, srv *Server, logging, enableCors bool) error { - r, err := createRouter(srv, logging, enableCors) +func ListenAndServe(proto, addr string, eng *engine.Engine, logging, enableCors bool, dockerVersion string) error { + r, err := createRouter(eng, logging, enableCors, dockerVersion) if err != nil { return err } @@ -1147,3 +1164,30 @@ func ListenAndServe(proto, addr string, srv *Server, logging, enableCors bool) e httpSrv := http.Server{Addr: addr, Handler: r} return httpSrv.Serve(l) } + +// ServeApi loops through all of the protocols sent in to docker and spawns +// off a go routine to setup a serving http.Server for each. +func ServeApi(job *engine.Job) engine.Status { + protoAddrs := job.Args + chErrors := make(chan error, len(protoAddrs)) + + for _, protoAddr := range protoAddrs { + protoAddrParts := strings.SplitN(protoAddr, "://", 2) + go func() { + log.Printf("Listening for HTTP on %s (%s)\n", protoAddrParts[0], protoAddrParts[1]) + chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) + }() + } + + for i := 0; i < len(protoAddrs); i += 1 { + err := <-chErrors + if err != nil { + return job.Error(err) + } + } + + // Tell the init daemon we are accepting requests + go systemd.SdNotify("READY=1") + + return engine.StatusOK +} diff --git a/components/engine/http_test.go b/components/engine/api/api_unit_test.go similarity index 82% rename from components/engine/http_test.go rename to components/engine/api/api_unit_test.go index b9ecd6a203..2b3e76e75c 100644 --- a/components/engine/http_test.go +++ b/components/engine/api/api_unit_test.go @@ -1,4 +1,4 @@ -package docker +package api import ( "fmt" @@ -7,6 +7,20 @@ import ( "testing" ) +func TestJsonContentType(t *testing.T) { + if !MatchesContentType("application/json", "application/json") { + t.Fail() + } + + if !MatchesContentType("application/json; charset=utf-8", "application/json") { + t.Fail() + } + + if MatchesContentType("dockerapplication/json", "application/json") { + t.Fail() + } +} + func TestGetBoolParam(t *testing.T) { if ret, err := getBoolParam("true"); err != nil || !ret { t.Fatalf("true -> true, nil | got %t %s", ret, err) diff --git a/components/engine/api_unit_test.go b/components/engine/api_unit_test.go deleted file mode 100644 index 82095bd8b5..0000000000 --- a/components/engine/api_unit_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package docker - -import ( - "testing" -) - -func TestJsonContentType(t *testing.T) { - if !matchesContentType("application/json", "application/json") { - t.Fail() - } - - if !matchesContentType("application/json; charset=utf-8", "application/json") { - t.Fail() - } - - if matchesContentType("dockerapplication/json", "application/json") { - t.Fail() - } -} diff --git a/components/engine/commands.go b/components/engine/commands.go index 94624b96f1..bebab65481 100644 --- a/components/engine/commands.go +++ b/components/engine/commands.go @@ -8,6 +8,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/dotcloud/docker/api" "github.com/dotcloud/docker/archive" "github.com/dotcloud/docker/auth" "github.com/dotcloud/docker/engine" @@ -79,7 +80,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error { return nil } } - help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=[unix://%s]: tcp://host:port to bind/connect to or unix://path/to/socket to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", DEFAULTUNIXSOCKET) + help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=[unix://%s]: tcp://host:port to bind/connect to or unix://path/to/socket to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", api.DEFAULTUNIXSOCKET) for _, command := range [][]string{ {"attach", "Attach to a running container"}, {"build", "Build a container from a Dockerfile"}, @@ -2283,7 +2284,7 @@ func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo b re := regexp.MustCompile("/+") path = re.ReplaceAllString(path, "/") - req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), params) + req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", api.APIVERSION, path), params) if err != nil { return nil, -1, err } @@ -2360,7 +2361,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h re := regexp.MustCompile("/+") path = re.ReplaceAllString(path, "/") - req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), in) + req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", api.APIVERSION, path), in) if err != nil { return err } @@ -2405,7 +2406,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h return fmt.Errorf("Error: %s", bytes.TrimSpace(body)) } - if matchesContentType(resp.Header.Get("Content-Type"), "application/json") { + if api.MatchesContentType(resp.Header.Get("Content-Type"), "application/json") { return utils.DisplayJSONMessagesStream(resp.Body, out, cli.terminalFd, cli.isTerminal) } if _, err := io.Copy(out, resp.Body); err != nil { @@ -2424,7 +2425,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea re := regexp.MustCompile("/+") path = re.ReplaceAllString(path, "/") - req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), nil) + req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", api.APIVERSION, path), nil) if err != nil { return err } diff --git a/components/engine/docker/docker.go b/components/engine/docker/docker.go index e6c8076f36..ba7764050b 100644 --- a/components/engine/docker/docker.go +++ b/components/engine/docker/docker.go @@ -3,6 +3,7 @@ package main import ( "fmt" "github.com/dotcloud/docker" + "github.com/dotcloud/docker/api" "github.com/dotcloud/docker/engine" flag "github.com/dotcloud/docker/pkg/mflag" "github.com/dotcloud/docker/sysinit" @@ -57,7 +58,7 @@ func main() { if defaultHost == "" || *flDaemon { // If we do not have a host, default to unix socket - defaultHost = fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET) + defaultHost = fmt.Sprintf("unix://%s", api.DEFAULTUNIXSOCKET) } flHosts.Set(defaultHost) } @@ -82,7 +83,7 @@ func main() { log.Fatal(err) } // Load plugin: httpapi - job := eng.Job("initapi") + job := eng.Job("initserver") job.Setenv("Pidfile", *pidfile) job.Setenv("Root", *flRoot) job.SetenvBool("AutoRestart", *flAutoRestart) @@ -102,6 +103,7 @@ func main() { job = eng.Job("serveapi", flHosts.GetAll()...) job.SetenvBool("Logging", true) job.SetenvBool("EnableCors", *flEnableCors) + job.Setenv("Version", VERSION) if err := job.Run(); err != nil { log.Fatal(err) } diff --git a/components/engine/integration/api_test.go b/components/engine/integration/api_test.go index d376305264..82de56a8ba 100644 --- a/components/engine/integration/api_test.go +++ b/components/engine/integration/api_test.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "github.com/dotcloud/docker" + "github.com/dotcloud/docker/api" "github.com/dotcloud/docker/engine" "github.com/dotcloud/docker/utils" "io" @@ -21,7 +22,6 @@ import ( func TestGetVersion(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) var err error r := httptest.NewRecorder() @@ -31,7 +31,7 @@ func TestGetVersion(t *testing.T) { t.Fatal(err) } // FIXME getting the version should require an actual running Server - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -58,7 +58,6 @@ func TestGetVersion(t *testing.T) { func TestGetInfo(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) job := eng.Job("images") initialImages, err := job.Stdout.AddListTable() @@ -74,7 +73,7 @@ func TestGetInfo(t *testing.T) { } r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -122,7 +121,7 @@ func TestGetEvents(t *testing.T) { r := httptest.NewRecorder() setTimeout(t, "", 500*time.Millisecond, func() { - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -146,7 +145,6 @@ func TestGetEvents(t *testing.T) { func TestGetImagesJSON(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) job := eng.Job("images") initialImages, err := job.Stdout.AddListTable() @@ -164,7 +162,7 @@ func TestGetImagesJSON(t *testing.T) { r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -199,7 +197,7 @@ func TestGetImagesJSON(t *testing.T) { if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r2, req2); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r2, req2); err != nil { t.Fatal(err) } assertHttpNotError(r2, t) @@ -232,7 +230,7 @@ func TestGetImagesJSON(t *testing.T) { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r3, req3); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r3, req3); err != nil { t.Fatal(err) } assertHttpNotError(r3, t) @@ -250,7 +248,6 @@ func TestGetImagesJSON(t *testing.T) { func TestGetImagesHistory(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) r := httptest.NewRecorder() @@ -258,7 +255,7 @@ func TestGetImagesHistory(t *testing.T) { if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -275,7 +272,6 @@ func TestGetImagesHistory(t *testing.T) { func TestGetImagesByName(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) req, err := http.NewRequest("GET", "/images/"+unitTestImageName+"/json", nil) if err != nil { @@ -283,7 +279,7 @@ func TestGetImagesByName(t *testing.T) { } r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -300,7 +296,6 @@ func TestGetImagesByName(t *testing.T) { func TestGetContainersJSON(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) job := eng.Job("containers") job.SetenvBool("all", true) @@ -328,7 +323,7 @@ func TestGetContainersJSON(t *testing.T) { } r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -347,7 +342,6 @@ func TestGetContainersJSON(t *testing.T) { func TestGetContainersExport(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) // Create a container and remove a file containerID := createTestContainer(eng, @@ -365,7 +359,7 @@ func TestGetContainersExport(t *testing.T) { if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -396,7 +390,6 @@ func TestGetContainersExport(t *testing.T) { func TestGetContainersChanges(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) // Create a container and remove a file containerID := createTestContainer(eng, @@ -413,7 +406,7 @@ func TestGetContainersChanges(t *testing.T) { if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -437,7 +430,6 @@ func TestGetContainersChanges(t *testing.T) { func TestGetContainersTop(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer(eng, &docker.Config{ @@ -481,7 +473,7 @@ func TestGetContainersTop(t *testing.T) { if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -514,7 +506,6 @@ func TestGetContainersTop(t *testing.T) { func TestGetContainersByName(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) // Create a container and remove a file containerID := createTestContainer(eng, @@ -530,7 +521,7 @@ func TestGetContainersByName(t *testing.T) { if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -565,7 +556,7 @@ func TestPostCommit(t *testing.T) { } r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -585,7 +576,6 @@ func TestPostCommit(t *testing.T) { func TestPostContainersCreate(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) configJSON, err := json.Marshal(&docker.Config{ Image: unitTestImageID, @@ -602,7 +592,7 @@ func TestPostContainersCreate(t *testing.T) { } r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -627,7 +617,6 @@ func TestPostContainersCreate(t *testing.T) { func TestPostContainersKill(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer(eng, &docker.Config{ @@ -652,7 +641,7 @@ func TestPostContainersKill(t *testing.T) { if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -667,7 +656,6 @@ func TestPostContainersKill(t *testing.T) { func TestPostContainersRestart(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer(eng, &docker.Config{ @@ -692,7 +680,7 @@ func TestPostContainersRestart(t *testing.T) { t.Fatal(err) } r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -713,7 +701,6 @@ func TestPostContainersRestart(t *testing.T) { func TestPostContainersStart(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer( eng, @@ -735,7 +722,7 @@ func TestPostContainersStart(t *testing.T) { req.Header.Set("Content-Type", "application/json") r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -752,7 +739,7 @@ func TestPostContainersStart(t *testing.T) { } r = httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } // Starting an already started container should return an error @@ -767,7 +754,6 @@ func TestPostContainersStart(t *testing.T) { func TestRunErrorBindMountRootSource(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer( eng, @@ -791,7 +777,7 @@ func TestRunErrorBindMountRootSource(t *testing.T) { req.Header.Set("Content-Type", "application/json") r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } if r.Code != http.StatusInternalServerError { @@ -803,7 +789,6 @@ func TestRunErrorBindMountRootSource(t *testing.T) { func TestPostContainersStop(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer(eng, &docker.Config{ @@ -829,7 +814,7 @@ func TestPostContainersStop(t *testing.T) { t.Fatal(err) } r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -844,7 +829,6 @@ func TestPostContainersStop(t *testing.T) { func TestPostContainersWait(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer(eng, &docker.Config{ @@ -862,7 +846,7 @@ func TestPostContainersWait(t *testing.T) { if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -883,7 +867,6 @@ func TestPostContainersWait(t *testing.T) { func TestPostContainersAttach(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer(eng, &docker.Config{ @@ -921,7 +904,7 @@ func TestPostContainersAttach(t *testing.T) { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r.ResponseRecorder, t) @@ -962,7 +945,6 @@ func TestPostContainersAttach(t *testing.T) { func TestPostContainersAttachStderr(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer(eng, &docker.Config{ @@ -1000,7 +982,7 @@ func TestPostContainersAttachStderr(t *testing.T) { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r.ResponseRecorder, t) @@ -1044,7 +1026,6 @@ func TestPostContainersAttachStderr(t *testing.T) { func TestDeleteContainers(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) containerID := createTestContainer(eng, &docker.Config{ @@ -1058,7 +1039,7 @@ func TestDeleteContainers(t *testing.T) { t.Fatal(err) } r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -1071,13 +1052,13 @@ func TestDeleteContainers(t *testing.T) { func TestOptionsRoute(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) + r := httptest.NewRecorder() req, err := http.NewRequest("OPTIONS", "/", nil) if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -1089,14 +1070,14 @@ func TestOptionsRoute(t *testing.T) { func TestGetEnabledCors(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) + r := httptest.NewRecorder() req, err := http.NewRequest("GET", "/version", nil) if err != nil { t.Fatal(err) } - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) @@ -1122,7 +1103,6 @@ func TestGetEnabledCors(t *testing.T) { func TestDeleteImages(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) initialImages := getImages(eng, t, true, "") @@ -1142,7 +1122,7 @@ func TestDeleteImages(t *testing.T) { } r := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } if r.Code != http.StatusConflict { @@ -1155,7 +1135,7 @@ func TestDeleteImages(t *testing.T) { } r2 := httptest.NewRecorder() - if err := docker.ServeRequest(srv, docker.APIVERSION, r2, req2); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r2, req2); err != nil { t.Fatal(err) } assertHttpNotError(r2, t) @@ -1180,7 +1160,6 @@ func TestDeleteImages(t *testing.T) { func TestPostContainersCopy(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) // Create a container and remove a file containerID := createTestContainer(eng, @@ -1208,7 +1187,7 @@ func TestPostContainersCopy(t *testing.T) { t.Fatal(err) } req.Header.Add("Content-Type", "application/json") - if err := docker.ServeRequest(srv, docker.APIVERSION, r, req); err != nil { + if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil { t.Fatal(err) } assertHttpNotError(r, t) diff --git a/components/engine/integration/runtime_test.go b/components/engine/integration/runtime_test.go index e6b4aab804..da95967a30 100644 --- a/components/engine/integration/runtime_test.go +++ b/components/engine/integration/runtime_test.go @@ -61,7 +61,7 @@ func cleanup(eng *engine.Engine, t *testing.T) error { } for _, image := range images.Data { if image.Get("Id") != unitTestImageID { - mkServerFromEngine(eng, t).DeleteImage(image.Get("Id"), false) + eng.Job("image_delete", image.Get("Id")).Run() } } return nil @@ -125,17 +125,18 @@ func setupBaseImage() { if err != nil { log.Fatalf("Can't initialize engine at %s: %s", unitTestStoreBase, err) } - job := eng.Job("initapi") + job := eng.Job("initserver") job.Setenv("Root", unitTestStoreBase) job.SetenvBool("Autorestart", false) job.Setenv("BridgeIface", unitTestNetworkBridge) if err := job.Run(); err != nil { log.Fatalf("Unable to create a runtime for tests: %s", err) } - srv := mkServerFromEngine(eng, log.New(os.Stderr, "", 0)) + job = eng.Job("inspect", unitTestImageName, "image") + img, _ := job.Stdout.AddEnv() // If the unit test is not found, try to download it. - if img, err := srv.ImageInspect(unitTestImageName); err != nil || img.ID != unitTestImageID { + if err := job.Run(); err != nil || img.Get("id") != unitTestImageID { // Retrieve the Image job = eng.Job("pull", unitTestImageName) job.Stdout.Add(utils.NopWriteCloser(os.Stdout)) @@ -572,7 +573,7 @@ func TestRestore(t *testing.T) { if err != nil { t.Fatal(err) } - job := eng.Job("initapi") + job := eng.Job("initserver") job.Setenv("Root", eng.Root()) job.SetenvBool("Autorestart", false) if err := job.Run(); err != nil { @@ -604,7 +605,7 @@ func TestRestore(t *testing.T) { } func TestReloadContainerLinks(t *testing.T) { - // FIXME: here we don't use NewTestEngine because it calls initapi with Autorestart=false, + // FIXME: here we don't use NewTestEngine because it calls initserver with Autorestart=false, // and we want to set it to true. root, err := newTestDirectory(unitTestStoreBase) if err != nil { @@ -614,7 +615,7 @@ func TestReloadContainerLinks(t *testing.T) { if err != nil { t.Fatal(err) } - job := eng.Job("initapi") + job := eng.Job("initserver") job.Setenv("Root", eng.Root()) job.SetenvBool("Autorestart", true) if err := job.Run(); err != nil { @@ -664,7 +665,7 @@ func TestReloadContainerLinks(t *testing.T) { if err != nil { t.Fatal(err) } - job = eng.Job("initapi") + job = eng.Job("initserver") job.Setenv("Root", eng.Root()) job.SetenvBool("Autorestart", false) if err := job.Run(); err != nil { diff --git a/components/engine/integration/server_test.go b/components/engine/integration/server_test.go index c3371ce8bf..45d4930ad7 100644 --- a/components/engine/integration/server_test.go +++ b/components/engine/integration/server_test.go @@ -262,7 +262,7 @@ func TestRestartKillWait(t *testing.T) { t.Fatal(err) } - job = eng.Job("initapi") + job = eng.Job("initserver") job.Setenv("Root", eng.Root()) job.SetenvBool("AutoRestart", false) // TestGetEnabledCors and TestOptionsRoute require EnableCors=true diff --git a/components/engine/integration/sorter_test.go b/components/engine/integration/sorter_test.go index d193fca1f0..3ce1225ca4 100644 --- a/components/engine/integration/sorter_test.go +++ b/components/engine/integration/sorter_test.go @@ -1,7 +1,7 @@ package docker import ( - "github.com/dotcloud/docker" + "github.com/dotcloud/docker/engine" "testing" "time" ) @@ -9,9 +9,8 @@ import ( func TestServerListOrderedImagesByCreationDate(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) - if err := generateImage("", srv); err != nil { + if err := generateImage("", eng); err != nil { t.Fatal(err) } @@ -25,16 +24,15 @@ func TestServerListOrderedImagesByCreationDate(t *testing.T) { func TestServerListOrderedImagesByCreationDateAndTag(t *testing.T) { eng := NewTestEngine(t) defer mkRuntimeFromEngine(eng, t).Nuke() - srv := mkServerFromEngine(eng, t) - err := generateImage("bar", srv) + err := generateImage("bar", eng) if err != nil { t.Fatal(err) } time.Sleep(time.Second) - err = generateImage("zed", srv) + err = generateImage("zed", eng) if err != nil { t.Fatal(err) } @@ -46,12 +44,12 @@ func TestServerListOrderedImagesByCreationDateAndTag(t *testing.T) { } } -func generateImage(name string, srv *docker.Server) error { +func generateImage(name string, eng *engine.Engine) error { archive, err := fakeTar() if err != nil { return err } - job := srv.Eng.Job("import", "-", "repo", name) + job := eng.Job("import", "-", "repo", name) job.Stdin.Add(archive) job.SetenvBool("json", true) return job.Run() diff --git a/components/engine/integration/utils_test.go b/components/engine/integration/utils_test.go index 2eff13c81d..a1add3cb48 100644 --- a/components/engine/integration/utils_test.go +++ b/components/engine/integration/utils_test.go @@ -188,7 +188,7 @@ func NewTestEngine(t utils.Fataler) *engine.Engine { } // Load default plugins // (This is manually copied and modified from main() until we have a more generic plugin system) - job := eng.Job("initapi") + job := eng.Job("initserver") job.Setenv("Root", root) job.SetenvBool("AutoRestart", false) // TestGetEnabledCors and TestOptionsRoute require EnableCors=true diff --git a/components/engine/opts.go b/components/engine/opts.go index 3119f9dd10..b1d71c491d 100644 --- a/components/engine/opts.go +++ b/components/engine/opts.go @@ -2,6 +2,7 @@ package docker import ( "fmt" + "github.com/dotcloud/docker/api" "github.com/dotcloud/docker/utils" "os" "path/filepath" @@ -129,7 +130,7 @@ func ValidateEnv(val string) (string, error) { } func ValidateHost(val string) (string, error) { - host, err := utils.ParseHost(DEFAULTHTTPHOST, DEFAULTHTTPPORT, DEFAULTUNIXSOCKET, val) + host, err := utils.ParseHost(api.DEFAULTHTTPHOST, api.DEFAULTHTTPPORT, api.DEFAULTUNIXSOCKET, val) if err != nil { return val, err } diff --git a/components/engine/server.go b/components/engine/server.go index d037212ce3..f4d2f3722f 100644 --- a/components/engine/server.go +++ b/components/engine/server.go @@ -8,7 +8,6 @@ import ( "github.com/dotcloud/docker/auth" "github.com/dotcloud/docker/engine" "github.com/dotcloud/docker/pkg/graphdb" - "github.com/dotcloud/docker/pkg/systemd" "github.com/dotcloud/docker/registry" "github.com/dotcloud/docker/utils" "io" @@ -34,13 +33,13 @@ func (srv *Server) Close() error { } func init() { - engine.Register("initapi", jobInitApi) + engine.Register("initserver", jobInitServer) } // jobInitApi runs the remote api server `srv` as a daemon, // Only one api server can run at the same time - this is enforced by a pidfile. // The signals SIGINT, SIGQUIT and SIGTERM are intercepted for cleanup. -func jobInitApi(job *engine.Job) engine.Status { +func jobInitServer(job *engine.Job) engine.Status { job.Logf("Creating server") srv, err := NewServer(job.Eng, DaemonConfigFromJob(job)) if err != nil { @@ -76,7 +75,6 @@ func jobInitApi(job *engine.Job) engine.Status { "restart": srv.ContainerRestart, "start": srv.ContainerStart, "kill": srv.ContainerKill, - "serveapi": srv.ListenAndServe, "wait": srv.ContainerWait, "tag": srv.ImageTag, "resize": srv.ContainerResize, @@ -111,33 +109,6 @@ func jobInitApi(job *engine.Job) engine.Status { return engine.StatusOK } -// ListenAndServe loops through all of the protocols sent in to docker and spawns -// off a go routine to setup a serving http.Server for each. -func (srv *Server) ListenAndServe(job *engine.Job) engine.Status { - protoAddrs := job.Args - chErrors := make(chan error, len(protoAddrs)) - - for _, protoAddr := range protoAddrs { - protoAddrParts := strings.SplitN(protoAddr, "://", 2) - go func() { - log.Printf("Listening for HTTP on %s (%s)\n", protoAddrParts[0], protoAddrParts[1]) - chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], srv, job.GetenvBool("Logging"), job.GetenvBool("EnableCors")) - }() - } - - for i := 0; i < len(protoAddrs); i += 1 { - err := <-chErrors - if err != nil { - return job.Error(err) - } - } - - // Tell the init daemon we are accepting requests - go systemd.SdNotify("READY=1") - - return engine.StatusOK -} - // simpleVersionInfo is a simple implementation of // the interface VersionInfo, which is used // to provide version information for some product,