Browse Source

Merge pull request #3827 from vieux/mova_api_package

Move api into sub package
Michael Crosby 11 years ago
parent
commit
6a1ee89d2d
12 changed files with 209 additions and 217 deletions
  1. 130 86
      api/api.go
  2. 15 1
      api/api_unit_test.go
  3. 0 19
      api_unit_test.go
  4. 6 5
      commands.go
  5. 4 2
      docker/docker.go
  6. 33 54
      integration/api_test.go
  7. 9 8
      integration/runtime_test.go
  8. 1 1
      integration/server_test.go
  9. 6 8
      integration/sorter_test.go
  10. 1 1
      integration/utils_test.go
  11. 2 1
      opts.go
  12. 2 31
      server.go

+ 130 - 86
api.go → 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
+}

+ 15 - 1
http_test.go → 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)

+ 0 - 19
api_unit_test.go

@@ -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()
-	}
-}

+ 6 - 5
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
 	}

+ 4 - 2
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)
 		}

+ 33 - 54
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)

+ 9 - 8
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 {

+ 1 - 1
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

+ 6 - 8
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()

+ 1 - 1
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

+ 2 - 1
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
 	}

+ 2 - 31
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,