From 58d0cfe3cb836c1da0dad6eabd92b211128b2edf Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 24 Jan 2014 23:15:40 -0800 Subject: [PATCH 1/6] Remove api_params.go Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) Upstream-commit: 217ad5e5e673aa09471e95f4726ddab2422fe5d1 Component: engine --- components/engine/api.go | 69 ++++++++-------- components/engine/api_params.go | 43 ---------- components/engine/commands.go | 95 +++++++++++++---------- components/engine/integration/api_test.go | 68 ++++++++-------- 4 files changed, 127 insertions(+), 148 deletions(-) delete mode 100644 components/engine/api_params.go diff --git a/components/engine/api.go b/components/engine/api.go index 0a7f7abea7..ba8646599d 100644 --- a/components/engine/api.go +++ b/components/engine/api.go @@ -89,18 +89,10 @@ func httpError(w http.ResponseWriter, err error) { } } -func writeJSON(w http.ResponseWriter, code int, v interface{}) error { - b, err := json.Marshal(v) - - if err != nil { - return err - } - +func writeJSON(w http.ResponseWriter, code int, v engine.Env) error { w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) - w.Write(b) - - return nil + return v.Encode(w) } func getBoolParam(value string) (bool, error) { @@ -352,12 +344,15 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req if err := parseForm(r); err != nil { return err } - config := &Config{} + var ( + config = &Config{} + env engine.Env + job = srv.Eng.Job("commit", r.Form.Get("container")) + ) if err := json.NewDecoder(r.Body).Decode(config); err != nil && err != io.EOF { utils.Errorf("%s", err) } - job := srv.Eng.Job("commit", r.Form.Get("container")) job.Setenv("repo", r.Form.Get("repo")) job.Setenv("tag", r.Form.Get("tag")) job.Setenv("author", r.Form.Get("author")) @@ -369,8 +364,8 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req if err := job.Run(); err != nil { return err } - - return writeJSON(w, http.StatusCreated, &APIID{id}) + env.Set("Id", id) + return writeJSON(w, http.StatusCreated, env) } // Creates an image from Pull or from Import @@ -555,15 +550,19 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r if err := parseForm(r); err != nil { return nil } - out := &APIRun{} - job := srv.Eng.Job("create", r.Form.Get("name")) + var ( + out engine.Env + job = srv.Eng.Job("create", r.Form.Get("name")) + outWarnings []string + outId string + warnings = bytes.NewBuffer(nil) + ) if err := job.DecodeEnv(r.Body); err != nil { return err } // Read container ID from the first line of stdout - job.Stdout.AddString(&out.ID) + job.Stdout.AddString(&outId) // Read warnings from stderr - warnings := &bytes.Buffer{} job.Stderr.Add(warnings) if err := job.Run(); err != nil { return err @@ -571,8 +570,10 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r // Parse warnings from stderr scanner := bufio.NewScanner(warnings) for scanner.Scan() { - out.Warnings = append(out.Warnings, scanner.Text()) + outWarnings = append(outWarnings, scanner.Text()) } + out.Set("Id", outId) + out.SetList("Warnings", outWarnings) return writeJSON(w, http.StatusCreated, out) } @@ -664,18 +665,22 @@ func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r * if vars == nil { return fmt.Errorf("Missing parameter") } - job := srv.Eng.Job("wait", vars["name"]) - var statusStr string - job.Stdout.AddString(&statusStr) + var ( + env engine.Env + status string + job = srv.Eng.Job("wait", vars["name"]) + ) + job.Stdout.AddString(&status) if err := job.Run(); err != nil { return err } // Parse a 16-bit encoded integer to map typical unix exit status. - status, err := strconv.ParseInt(statusStr, 10, 16) + _, err := strconv.ParseInt(status, 10, 16) if err != nil { return err } - return writeJSON(w, http.StatusOK, &APIWait{StatusCode: int(status)}) + env.Set("StatusCode", status) + return writeJSON(w, http.StatusOK, env) } func postContainersResize(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { @@ -874,24 +879,24 @@ func postContainersCopy(srv *Server, version float64, w http.ResponseWriter, r * return fmt.Errorf("Missing parameter") } - copyData := &APICopy{} - contentType := r.Header.Get("Content-Type") - if contentType == "application/json" { - if err := json.NewDecoder(r.Body).Decode(copyData); err != nil { + var copyData engine.Env + + if contentType := r.Header.Get("Content-Type"); contentType == "application/json" { + if err := copyData.Decode(r.Body); err != nil { return err } } else { return fmt.Errorf("Content-Type not supported: %s", contentType) } - if copyData.Resource == "" { + if copyData.Get("Resource") == "" { return fmt.Errorf("Path cannot be empty") } - if copyData.Resource[0] == '/' { - copyData.Resource = copyData.Resource[1:] + if copyData.Get("Resource")[0] == '/' { + copyData.Set("Resource", copyData.Get("Resource")[1:]) } - job := srv.Eng.Job("container_copy", vars["name"], copyData.Resource) + job := srv.Eng.Job("container_copy", vars["name"], copyData.Get("Resource")) job.Stdout.Add(w) if err := job.Run(); err != nil { utils.Errorf("%s", err.Error()) diff --git a/components/engine/api_params.go b/components/engine/api_params.go deleted file mode 100644 index fb5ad6f388..0000000000 --- a/components/engine/api_params.go +++ /dev/null @@ -1,43 +0,0 @@ -package docker - -type ( - APITop struct { - Titles []string - Processes [][]string - } - - APIRmi struct { - Deleted string `json:",omitempty"` - Untagged string `json:",omitempty"` - } - - APIID struct { - ID string `json:"Id"` - } - - APIRun struct { - ID string `json:"Id"` - Warnings []string `json:",omitempty"` - } - - APIPort struct { - PrivatePort int64 - PublicPort int64 - Type string - IP string - } - - APIWait struct { - StatusCode int - } - - APIImageConfig struct { - ID string `json:"Id"` - *Config - } - - APICopy struct { - Resource string - HostPath string - } -) diff --git a/components/engine/commands.go b/components/engine/commands.go index 083ca39bc5..5af02046a3 100644 --- a/components/engine/commands.go +++ b/components/engine/commands.go @@ -755,18 +755,21 @@ func (cli *DockerCli) CmdTop(args ...string) error { val.Set("ps_args", strings.Join(cmd.Args()[1:], " ")) } - body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, false)) + stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, false) if err != nil { return err } - procs := APITop{} - err = json.Unmarshal(body, &procs) - if err != nil { + var procs engine.Env + if err := procs.Decode(stream); err != nil { return err } w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) - fmt.Fprintln(w, strings.Join(procs.Titles, "\t")) - for _, proc := range procs.Processes { + fmt.Fprintln(w, strings.Join(procs.GetList("Titles"), "\t")) + processes := [][]string{} + if err := procs.GetJson("Processes", &processes); err != nil { + return err + } + for _, proc := range processes { fmt.Fprintln(w, strings.Join(proc, "\t")) } w.Flush() @@ -1451,25 +1454,25 @@ func (cli *DockerCli) CmdCommit(args ...string) error { v.Set("tag", tag) v.Set("comment", *flComment) v.Set("author", *flAuthor) - var config *Config + var ( + config *Config + env engine.Env + ) if *flConfig != "" { config = &Config{} if err := json.Unmarshal([]byte(*flConfig), config); err != nil { return err } } - body, _, err := readBody(cli.call("POST", "/commit?"+v.Encode(), config, false)) + stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, false) if err != nil { return err } - - apiID := &APIID{} - err = json.Unmarshal(body, apiID) - if err != nil { + if err := env.Decode(stream); err != nil { return err } - fmt.Fprintf(cli.out, "%s\n", apiID.ID) + fmt.Fprintf(cli.out, "%s\n", env.Get("ID")) return nil } @@ -1989,7 +1992,7 @@ func (cli *DockerCli) CmdRun(args ...string) error { } //create the container - body, statusCode, err := readBody(cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false)) + stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false) //if image not found try to pull it if statusCode == 404 { _, tag := utils.ParseRepositoryTag(config.Image) @@ -2026,30 +2029,30 @@ func (cli *DockerCli) CmdRun(args ...string) error { if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil { return err } - if body, _, err = readBody(cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false)); err != nil { + if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false); err != nil { return err } } else if err != nil { return err } - var runResult APIRun - if err := json.Unmarshal(body, &runResult); err != nil { + var runResult engine.Env + if err := runResult.Decode(stream); err != nil { return err } - for _, warning := range runResult.Warnings { + for _, warning := range runResult.GetList("Warnings") { fmt.Fprintf(cli.err, "WARNING: %s\n", warning) } if len(hostConfig.ContainerIDFile) > 0 { - if _, err = containerIDFile.Write([]byte(runResult.ID)); err != nil { + if _, err = containerIDFile.Write([]byte(runResult.Get("Id"))); err != nil { return fmt.Errorf("failed to write the container ID to the file: %s", err) } } if sigProxy { - sigc := cli.forwardAllSignals(runResult.ID) + sigc := cli.forwardAllSignals(runResult.Get("Id")) defer utils.StopCatch(sigc) } @@ -2063,7 +2066,7 @@ func (cli *DockerCli) CmdRun(args ...string) error { waitDisplayId = make(chan struct{}) go func() { defer close(waitDisplayId) - fmt.Fprintf(cli.out, "%s\n", runResult.ID) + fmt.Fprintf(cli.out, "%s\n", runResult.Get("Id")) }() } @@ -2105,7 +2108,7 @@ func (cli *DockerCli) CmdRun(args ...string) error { } errCh = utils.Go(func() error { - return cli.hijack("POST", "/containers/"+runResult.ID+"/attach?"+v.Encode(), config.Tty, in, out, stderr, hijacked) + return cli.hijack("POST", "/containers/"+runResult.Get("Id")+"/attach?"+v.Encode(), config.Tty, in, out, stderr, hijacked) }) } else { close(hijacked) @@ -2127,12 +2130,12 @@ func (cli *DockerCli) CmdRun(args ...string) error { } //start the container - if _, _, err = readBody(cli.call("POST", "/containers/"+runResult.ID+"/start", hostConfig, false)); err != nil { + if _, _, err = readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/start", hostConfig, false)); err != nil { return err } if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminal { - if err := cli.monitorTtySize(runResult.ID); err != nil { + if err := cli.monitorTtySize(runResult.Get("Id")); err != nil { utils.Errorf("Error monitoring TTY size: %s\n", err) } } @@ -2157,26 +2160,26 @@ func (cli *DockerCli) CmdRun(args ...string) error { if autoRemove { // Autoremove: wait for the container to finish, retrieve // the exit code and remove the container - if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.ID+"/wait", nil, false)); err != nil { + if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/wait", nil, false)); err != nil { return err } - if _, status, err = getExitCode(cli, runResult.ID); err != nil { + if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil { return err } - if _, _, err := readBody(cli.call("DELETE", "/containers/"+runResult.ID+"?v=1", nil, false)); err != nil { + if _, _, err := readBody(cli.call("DELETE", "/containers/"+runResult.Get("Id")+"?v=1", nil, false)); err != nil { return err } } else { if !config.Tty { // In non-tty mode, we can't dettach, so we know we need to wait. - if status, err = waitForExit(cli, runResult.ID); err != nil { + if status, err = waitForExit(cli, runResult.Get("Id")); err != nil { return err } } else { // In TTY mode, there is a race. If the process dies too slowly, the state can be update after the getExitCode call // and result in a wrong exit code. // No Autoremove: Simply retrieve the exit code - if _, status, err = getExitCode(cli, runResult.ID); err != nil { + if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil { return err } } @@ -2198,15 +2201,15 @@ func (cli *DockerCli) CmdCp(args ...string) error { return nil } - var copyData APICopy + var copyData engine.Env info := strings.Split(cmd.Arg(0), ":") if len(info) != 2 { return fmt.Errorf("Error: Path not specified") } - copyData.Resource = info[1] - copyData.HostPath = cmd.Arg(1) + copyData.Set("Resource", info[1]) + copyData.Set("HostPath", cmd.Arg(1)) stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData, false) if stream != nil { @@ -2217,7 +2220,7 @@ func (cli *DockerCli) CmdCp(args ...string) error { } if statusCode == 200 { - if err := archive.Untar(stream, copyData.HostPath, nil); err != nil { + if err := archive.Untar(stream, copyData.Get("HostPath"), nil); err != nil { return err } } @@ -2260,13 +2263,21 @@ func (cli *DockerCli) CmdLoad(args ...string) error { } func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo bool) (io.ReadCloser, int, error) { - var params io.Reader + params := bytes.NewBuffer(nil) if data != nil { - buf, err := json.Marshal(data) - if err != nil { - return nil, -1, err + if env, ok := data.(engine.Env); ok { + if err := env.Encode(params); err != nil { + return nil, -1, err + } + } else { + buf, err := json.Marshal(data) + if err != nil { + return nil, -1, err + } + if _, err := params.Write(buf); err != nil { + return nil, -1, err + } } - params = bytes.NewBuffer(buf) } // fixme: refactor client to support redirect re := regexp.MustCompile("/+") @@ -2569,16 +2580,16 @@ func (cli *DockerCli) LoadConfigFile() (err error) { } func waitForExit(cli *DockerCli, containerId string) (int, error) { - body, _, err := readBody(cli.call("POST", "/containers/"+containerId+"/wait", nil, false)) + stream, _, err := cli.call("POST", "/containers/"+containerId+"/wait", nil, false) if err != nil { return -1, err } - var out APIWait - if err := json.Unmarshal(body, &out); err != nil { + var out engine.Env + if err := out.Decode(stream); err != nil { return -1, err } - return out.StatusCode, nil + return out.GetInt("StatusCode"), nil } // getExitCode perform an inspect on the container. It returns diff --git a/components/engine/integration/api_test.go b/components/engine/integration/api_test.go index 95cae47e15..b9ff079cb1 100644 --- a/components/engine/integration/api_test.go +++ b/components/engine/integration/api_test.go @@ -485,26 +485,29 @@ func TestGetContainersTop(t *testing.T) { t.Fatal(err) } assertHttpNotError(r, t) - procs := docker.APITop{} - if err := json.Unmarshal(r.Body.Bytes(), &procs); err != nil { + var procs engine.Env + if err := procs.Decode(r.Body); err != nil { t.Fatal(err) } - if len(procs.Titles) != 11 { - t.Fatalf("Expected 11 titles, found %d.", len(procs.Titles)) + if len(procs.GetList("Titles")) != 11 { + t.Fatalf("Expected 11 titles, found %d.", len(procs.GetList("Titles"))) } - if procs.Titles[0] != "USER" || procs.Titles[10] != "COMMAND" { - t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.Titles[0], procs.Titles[10]) + if procs.GetList("Titles")[0] != "USER" || procs.GetList("Titles")[10] != "COMMAND" { + t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.GetList("Titles")[0], procs.GetList("Titles")[10]) } - - if len(procs.Processes) != 2 { - t.Fatalf("Expected 2 processes, found %d.", len(procs.Processes)) + processes := [][]string{} + if err := procs.GetJson("Processes", &processes); err != nil { + t.Fatal(err) } - if procs.Processes[0][10] != "/bin/sh -c cat" { - t.Fatalf("Expected `/bin/sh -c cat`, found %s.", procs.Processes[0][10]) + if len(processes) != 2 { + t.Fatalf("Expected 2 processes, found %d.", len(processes)) } - if procs.Processes[1][10] != "/bin/sh -c cat" { - t.Fatalf("Expected `/bin/sh -c cat`, found %s.", procs.Processes[1][10]) + if processes[0][10] != "/bin/sh -c cat" { + t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[0][10]) + } + if processes[1][10] != "/bin/sh -c cat" { + t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[1][10]) } } @@ -570,11 +573,11 @@ func TestPostCommit(t *testing.T) { t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code) } - apiID := &docker.APIID{} - if err := json.Unmarshal(r.Body.Bytes(), apiID); err != nil { + var env engine.Env + if err := env.Decode(r.Body); err != nil { t.Fatal(err) } - if _, err := srv.ImageInspect(apiID.ID); err != nil { + if _, err := srv.ImageInspect(env.Get("Id")); err != nil { t.Fatalf("The image has not been committed") } } @@ -607,11 +610,11 @@ func TestPostContainersCreate(t *testing.T) { t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code) } - apiRun := &docker.APIRun{} - if err := json.Unmarshal(r.Body.Bytes(), apiRun); err != nil { + var apiRun engine.Env + if err := apiRun.Decode(r.Body); err != nil { t.Fatal(err) } - containerID := apiRun.ID + containerID := apiRun.Get("Id") containerAssertExists(eng, containerID, t) containerRun(eng, containerID, t) @@ -863,12 +866,12 @@ func TestPostContainersWait(t *testing.T) { t.Fatal(err) } assertHttpNotError(r, t) - apiWait := &docker.APIWait{} - if err := json.Unmarshal(r.Body.Bytes(), apiWait); err != nil { + var apiWait engine.Env + if err := apiWait.Decode(r.Body); err != nil { t.Fatal(err) } - if apiWait.StatusCode != 0 { - t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.StatusCode) + if apiWait.GetInt("StatusCode") != 0 { + t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode")) } }) @@ -1160,12 +1163,12 @@ func TestDeleteImages(t *testing.T) { t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code) } - var outs []docker.APIRmi - if err := json.Unmarshal(r2.Body.Bytes(), &outs); err != nil { + outs := engine.NewTable("Created", 0) + if _, err := outs.ReadListFrom(r2.Body.Bytes()); err != nil { t.Fatal(err) } - if len(outs) != 1 { - t.Fatalf("Expected %d event (untagged), got %d", 1, len(outs)) + if len(outs.Data) != 1 { + t.Fatalf("Expected %d event (untagged), got %d", 1, len(outs.Data)) } images = getImages(eng, t, false, "") @@ -1190,14 +1193,17 @@ func TestPostContainersCopy(t *testing.T) { containerRun(eng, containerID, t) r := httptest.NewRecorder() - copyData := docker.APICopy{HostPath: ".", Resource: "/test.txt"} - jsonData, err := json.Marshal(copyData) - if err != nil { + var copyData engine.Env + copyData.Set("Resource", "/test.txt") + copyData.Set("HostPath", ".") + + jsonData := bytes.NewBuffer(nil) + if err := copyData.Encode(jsonData); err != nil { t.Fatal(err) } - req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", bytes.NewReader(jsonData)) + req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", jsonData) if err != nil { t.Fatal(err) } From edaa89a4ad510d2ecaae5dc7d9f1456d5d9df002 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Tue, 28 Jan 2014 00:27:02 +0000 Subject: [PATCH 2/6] job.error\* now return engine.StatusErr Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) Upstream-commit: 55d7aa1b49a49a27d77cd4011d921e340ec99f9f Component: engine --- components/engine/engine/job.go | 10 +- components/engine/server.go | 452 +++++++++++--------------------- 2 files changed, 156 insertions(+), 306 deletions(-) diff --git a/components/engine/engine/job.go b/components/engine/engine/job.go index 179b2ebdda..34393fcab5 100644 --- a/components/engine/engine/job.go +++ b/components/engine/engine/job.go @@ -188,10 +188,12 @@ func (job *Job) Printf(format string, args ...interface{}) (n int, err error) { return fmt.Fprintf(job.Stdout, format, args...) } -func (job *Job) Errorf(format string, args ...interface{}) (n int, err error) { - return fmt.Fprintf(job.Stderr, format, args...) +func (job *Job) Errorf(format string, args ...interface{}) Status { + fmt.Fprintf(job.Stderr, format, args...) + return StatusErr } -func (job *Job) Error(err error) (int, error) { - return fmt.Fprintf(job.Stderr, "%s", err) +func (job *Job) Error(err error) Status { + fmt.Fprintf(job.Stderr, "%s", err) + return StatusErr } diff --git a/components/engine/server.go b/components/engine/server.go index a6731842cc..a6f869f977 100644 --- a/components/engine/server.go +++ b/components/engine/server.go @@ -45,8 +45,7 @@ func jobInitApi(job *engine.Job) engine.Status { // FIXME: ImportEnv deprecates ConfigFromJob srv, err := NewServer(job.Eng, ConfigFromJob(job)) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if srv.runtime.config.Pidfile != "" { job.Logf("Creating pidfile") @@ -107,8 +106,7 @@ func jobInitApi(job *engine.Job) engine.Status { "auth": srv.Auth, } { if err := job.Eng.Register(name, handler); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } return engine.StatusOK @@ -131,8 +129,7 @@ func (srv *Server) ListenAndServe(job *engine.Job) engine.Status { for i := 0; i < len(protoAddrs); i += 1 { err := <-chErrors if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } @@ -200,8 +197,7 @@ func (srv *Server) ContainerKill(job *engine.Job) engine.Status { } if n := len(job.Args); n < 1 || n > 2 { - job.Errorf("Usage: %s CONTAINER [SIGNAL]", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s CONTAINER [SIGNAL]", job.Name) } name := job.Args[0] var sig uint64 @@ -212,8 +208,7 @@ func (srv *Server) ContainerKill(job *engine.Job) engine.Status { // The largest legal signal is 31, so let's parse on 5 bits sig, err = strconv.ParseUint(job.Args[1], 10, 5) if err != nil { - job.Errorf("Invalid signal: %s", job.Args[1]) - return engine.StatusErr + return job.Errorf("Invalid signal: %s", job.Args[1]) } } } @@ -221,21 +216,18 @@ func (srv *Server) ContainerKill(job *engine.Job) engine.Status { // If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait()) if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL { if err := container.Kill(); err != nil { - job.Errorf("Cannot kill container %s: %s", name, err) - return engine.StatusErr + return job.Errorf("Cannot kill container %s: %s", name, err) } srv.LogEvent("kill", container.ID, srv.runtime.repositories.ImageName(container.Image)) } else { // Otherwise, just send the requested signal if err := container.kill(int(sig)); err != nil { - job.Errorf("Cannot kill container %s: %s", name, err) - return engine.StatusErr + return job.Errorf("Cannot kill container %s: %s", name, err) } // FIXME: Add event for signals } } else { - job.Errorf("No such container: %s", name) - return engine.StatusErr + return job.Errorf("No such container: %s", name) } return engine.StatusOK } @@ -245,8 +237,7 @@ func (srv *Server) Auth(job *engine.Job) engine.Status { job.GetenvJson("authConfig", authConfig) status, err := auth.Login(authConfig, srv.HTTPRequestFactory(nil)) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } job.Printf("%s\n", status) return engine.StatusOK @@ -254,8 +245,7 @@ func (srv *Server) Auth(job *engine.Job) engine.Status { func (srv *Server) Events(job *engine.Job) engine.Status { if len(job.Args) != 1 { - job.Errorf("Usage: %s FROM", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s FROM", job.Name) } var ( @@ -305,8 +295,7 @@ func (srv *Server) Events(job *engine.Job) engine.Status { continue } if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } return engine.StatusOK @@ -314,28 +303,24 @@ func (srv *Server) Events(job *engine.Job) engine.Status { func (srv *Server) ContainerExport(job *engine.Job) engine.Status { if len(job.Args) != 1 { - job.Errorf("Usage: %s container_id", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s container_id", job.Name) } name := job.Args[0] if container := srv.runtime.Get(name); container != nil { data, err := container.Export() if err != nil { - job.Errorf("%s: %s", name, err) - return engine.StatusErr + return job.Errorf("%s: %s", name, err) } // Stream the entire contents of the container (basically a volatile snapshot) if _, err := io.Copy(job.Stdout, data); err != nil { - job.Errorf("%s: %s", name, err) - return engine.StatusErr + return job.Errorf("%s: %s", name, err) } // FIXME: factor job-specific LogEvent to engine.Job.Run() srv.LogEvent("export", container.ID, srv.runtime.repositories.ImageName(container.Image)) return engine.StatusOK } - job.Errorf("No such container: %s", name) - return engine.StatusErr + return job.Errorf("No such container: %s", name) } // ImageExport exports all images with the given tag. All versions @@ -345,15 +330,13 @@ func (srv *Server) ContainerExport(job *engine.Job) engine.Status { // out is the writer where the images are written to. func (srv *Server) ImageExport(job *engine.Job) engine.Status { if len(job.Args) != 1 { - job.Errorf("Usage: %s CONTAINER\n", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s CONTAINER\n", job.Name) } name := job.Args[0] // get image json tempdir, err := ioutil.TempDir("", "docker-export-") if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } defer os.RemoveAll(tempdir) @@ -361,20 +344,17 @@ func (srv *Server) ImageExport(job *engine.Job) engine.Status { rootRepo, err := srv.runtime.repositories.Get(name) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if rootRepo != nil { for _, id := range rootRepo { image, err := srv.ImageInspect(id) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if err := srv.exportImage(image, tempdir); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } @@ -384,30 +364,25 @@ func (srv *Server) ImageExport(job *engine.Job) engine.Status { rootRepoJson, _ := json.Marshal(rootRepoMap) if err := ioutil.WriteFile(path.Join(tempdir, "repositories"), rootRepoJson, os.ModeAppend); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } else { image, err := srv.ImageInspect(name) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if err := srv.exportImage(image, tempdir); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } fs, err := archive.Tar(tempdir, archive.Uncompressed) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if _, err := io.Copy(job.Stdout, fs); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } @@ -469,8 +444,7 @@ func (srv *Server) exportImage(image *Image, tempdir string) error { func (srv *Server) Build(job *engine.Job) engine.Status { if len(job.Args) != 0 { - job.Errorf("Usage: %s\n", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s\n", job.Name) } var ( remoteURL = job.Getenv("remote") @@ -495,38 +469,32 @@ func (srv *Server) Build(job *engine.Job) engine.Status { } root, err := ioutil.TempDir("", "docker-build-git") if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } defer os.RemoveAll(root) if output, err := exec.Command("git", "clone", remoteURL, root).CombinedOutput(); err != nil { - job.Errorf("Error trying to use git: %s (%s)", err, output) - return engine.StatusErr + return job.Errorf("Error trying to use git: %s (%s)", err, output) } c, err := archive.Tar(root, archive.Uncompressed) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } context = c } else if utils.IsURL(remoteURL) { f, err := utils.Download(remoteURL) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } defer f.Body.Close() dockerFile, err := ioutil.ReadAll(f.Body) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } c, err := MkBuildContext(string(dockerFile), nil) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } context = c } @@ -544,8 +512,7 @@ func (srv *Server) Build(job *engine.Job) engine.Status { !suppressOutput, !noCache, rm, job.Stdout, sf, authConfig, configFile) id, err := b.Build(context) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if repoName != "" { srv.runtime.repositories.Set(repoName, tag, id, false) @@ -558,8 +525,7 @@ func (srv *Server) Build(job *engine.Job) engine.Status { func (srv *Server) ImageLoad(job *engine.Job) engine.Status { tmpImageDir, err := ioutil.TempDir("", "docker-import-") if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } defer os.RemoveAll(tmpImageDir) @@ -570,40 +536,33 @@ func (srv *Server) ImageLoad(job *engine.Job) engine.Status { tarFile, err := os.Create(repoTarFile) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if _, err := io.Copy(tarFile, job.Stdin); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } tarFile.Close() repoFile, err := os.Open(repoTarFile) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if err := os.Mkdir(repoDir, os.ModeDir); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if err := archive.Untar(repoFile, repoDir, nil); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } dirs, err := ioutil.ReadDir(repoDir) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } for _, d := range dirs { if d.IsDir() { if err := srv.recursiveLoad(d.Name(), tmpImageDir); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } } @@ -612,21 +571,18 @@ func (srv *Server) ImageLoad(job *engine.Job) engine.Status { if err == nil { repositories := map[string]Repository{} if err := json.Unmarshal(repositoriesJson, &repositories); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } for imageName, tagMap := range repositories { for tag, address := range tagMap { if err := srv.runtime.repositories.Set(imageName, tag, address, true); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } } } else if !os.IsNotExist(err) { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK @@ -670,8 +626,7 @@ func (srv *Server) recursiveLoad(address, tmpImageDir string) error { func (srv *Server) ImagesSearch(job *engine.Job) engine.Status { if n := len(job.Args); n != 1 { - job.Errorf("Usage: %s TERM", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s TERM", job.Name) } var ( term = job.Args[0] @@ -683,13 +638,11 @@ func (srv *Server) ImagesSearch(job *engine.Job) engine.Status { r, err := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), auth.IndexServerAddress()) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } results, err := r.SearchRepositories(term) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } outs := engine.NewTable("star_count", 0) for _, result := range results.Results { @@ -699,16 +652,14 @@ func (srv *Server) ImagesSearch(job *engine.Job) engine.Status { } outs.ReverseSort() if _, err := outs.WriteListTo(job.Stdout); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } func (srv *Server) ImageInsert(job *engine.Job) engine.Status { if len(job.Args) != 3 { - job.Errorf("Usage: %s IMAGE URL PATH\n", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s IMAGE URL PATH\n", job.Name) } var ( @@ -722,32 +673,27 @@ func (srv *Server) ImageInsert(job *engine.Job) engine.Status { out := utils.NewWriteFlusher(job.Stdout) img, err := srv.runtime.repositories.LookupImage(name) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } file, err := utils.Download(url) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } defer file.Body.Close() config, _, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.sysInfo) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } c, _, err := srv.runtime.Create(config, "") if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf, false, utils.TruncateID(img.ID), "Downloading"), path); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } // FIXME: Handle custom repo, tag comment, author img, err = srv.runtime.Commit(c, "", "", img.Comment, img.Author, nil) @@ -773,8 +719,7 @@ func (srv *Server) ImagesViz(job *engine.Job) engine.Status { for _, image := range images { parentImage, err = image.GetParent() if err != nil { - job.Errorf("Error while getting parent image: %v", err) - return engine.StatusErr + return job.Errorf("Error while getting parent image: %v", err) } if parentImage != nil { job.Stdout.Write([]byte(" \"" + parentImage.ID + "\" -> \"" + image.ID + "\"\n")) @@ -809,8 +754,7 @@ func (srv *Server) Images(job *engine.Job) engine.Status { allImages, err = srv.runtime.graph.Heads() } if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } lookup := make(map[string]*engine.Env) for name, repository := range srv.runtime.repositories.Repositories { @@ -864,8 +808,7 @@ func (srv *Server) Images(job *engine.Job) engine.Status { outs.ReverseSort() if _, err := outs.WriteListTo(job.Stdout); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } @@ -908,22 +851,19 @@ func (srv *Server) DockerInfo(job *engine.Job) engine.Status { v.Set("InitSha1", utils.INITSHA1) v.Set("InitPath", initPath) if _, err := v.WriteTo(job.Stdout); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } func (srv *Server) ImageHistory(job *engine.Job) engine.Status { if n := len(job.Args); n != 1 { - job.Errorf("Usage: %s IMAGE", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s IMAGE", job.Name) } name := job.Args[0] image, err := srv.runtime.repositories.LookupImage(name) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } lookupMap := make(map[string][]string) @@ -950,16 +890,14 @@ func (srv *Server) ImageHistory(job *engine.Job) engine.Status { }) outs.ReverseSort() if _, err := outs.WriteListTo(job.Stdout); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } func (srv *Server) ContainerTop(job *engine.Job) engine.Status { if len(job.Args) != 1 && len(job.Args) != 2 { - job.Errorf("Not enough arguments. Usage: %s CONTAINER [PS_ARGS]\n", job.Name) - return engine.StatusErr + return job.Errorf("Not enough arguments. Usage: %s CONTAINER [PS_ARGS]\n", job.Name) } var ( name = job.Args[0] @@ -972,18 +910,15 @@ func (srv *Server) ContainerTop(job *engine.Job) engine.Status { if container := srv.runtime.Get(name); container != nil { if !container.State.IsRunning() { - job.Errorf("Container %s is not running", name) - return engine.StatusErr + return job.Errorf("Container %s is not running", name) } pids, err := srv.runtime.execDriver.GetPidsForContainer(container.ID) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } output, err := exec.Command("ps", psArgs).Output() if err != nil { - job.Errorf("Error running ps: %s", err) - return engine.StatusErr + return job.Errorf("Error running ps: %s", err) } lines := strings.Split(string(output), "\n") @@ -998,8 +933,7 @@ func (srv *Server) ContainerTop(job *engine.Job) engine.Status { } } if pidIndex == -1 { - job.Errorf("Couldn't find PID field in ps output") - return engine.StatusErr + return job.Errorf("Couldn't find PID field in ps output") } processes := [][]string{} @@ -1010,8 +944,7 @@ func (srv *Server) ContainerTop(job *engine.Job) engine.Status { fields := strings.Fields(line) p, err := strconv.Atoi(fields[pidIndex]) if err != nil { - job.Errorf("Unexpected pid '%s': %s", fields[pidIndex], err) - return engine.StatusErr + return job.Errorf("Unexpected pid '%s': %s", fields[pidIndex], err) } for _, pid := range pids { @@ -1029,38 +962,32 @@ func (srv *Server) ContainerTop(job *engine.Job) engine.Status { return engine.StatusOK } - job.Errorf("No such container: %s", name) - return engine.StatusErr + return job.Errorf("No such container: %s", name) } func (srv *Server) ContainerChanges(job *engine.Job) engine.Status { if n := len(job.Args); n != 1 { - job.Errorf("Usage: %s CONTAINER", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s CONTAINER", job.Name) } name := job.Args[0] if container := srv.runtime.Get(name); container != nil { outs := engine.NewTable("", 0) changes, err := container.Changes() if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } for _, change := range changes { out := &engine.Env{} if err := out.Import(change); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } outs.Add(out) } if _, err := outs.WriteListTo(job.Stdout); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } else { - job.Errorf("No such container: %s", name) - return engine.StatusErr + return job.Errorf("No such container: %s", name) } return engine.StatusOK } @@ -1109,8 +1036,7 @@ func (srv *Server) Containers(job *engine.Job) engine.Status { out.Set("Status", container.State.String()) str, err := container.NetworkSettings.PortMappingAPI().ToListString() if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } out.Set("Ports", str) if size { @@ -1122,34 +1048,29 @@ func (srv *Server) Containers(job *engine.Job) engine.Status { } outs.ReverseSort() if _, err := outs.WriteListTo(job.Stdout); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } func (srv *Server) ContainerCommit(job *engine.Job) engine.Status { if len(job.Args) != 1 { - job.Errorf("Not enough arguments. Usage: %s CONTAINER\n", job.Name) - return engine.StatusErr + return job.Errorf("Not enough arguments. Usage: %s CONTAINER\n", job.Name) } name := job.Args[0] container := srv.runtime.Get(name) if container == nil { - job.Errorf("No such container: %s", name) - return engine.StatusErr + return job.Errorf("No such container: %s", name) } var config Config if err := job.GetenvJson("config", &config); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } img, err := srv.runtime.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), &config) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } job.Printf("%s\n", img.ID) return engine.StatusOK @@ -1157,16 +1078,14 @@ func (srv *Server) ContainerCommit(job *engine.Job) engine.Status { func (srv *Server) ImageTag(job *engine.Job) engine.Status { if len(job.Args) != 2 && len(job.Args) != 3 { - job.Errorf("Usage: %s IMAGE REPOSITORY [TAG]\n", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s IMAGE REPOSITORY [TAG]\n", job.Name) } var tag string if len(job.Args) == 3 { tag = job.Args[2] } if err := srv.runtime.repositories.Set(job.Args[1], tag, job.Args[0], job.GetenvBool("force")); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } @@ -1403,8 +1322,7 @@ func (srv *Server) poolRemove(kind, key string) error { func (srv *Server) ImagePull(job *engine.Job) engine.Status { if n := len(job.Args); n != 1 && n != 2 { - job.Errorf("Usage: %s IMAGE [TAG]", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s IMAGE [TAG]", job.Name) } var ( localName = job.Args[0] @@ -1428,22 +1346,19 @@ func (srv *Server) ImagePull(job *engine.Job) engine.Status { <-c return engine.StatusOK } - job.Error(err) - return engine.StatusErr + return job.Error(err) } defer srv.poolRemove("pull", localName+":"+tag) // Resolve the Repository name from fqn to endpoint + name endpoint, remoteName, err := registry.ResolveRepositoryName(localName) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } r, err := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), endpoint) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if endpoint == auth.IndexServerAddress() { @@ -1452,8 +1367,7 @@ func (srv *Server) ImagePull(job *engine.Job) engine.Status { } if err = srv.pullRepository(r, job.Stdout, localName, remoteName, tag, sf, job.GetenvBool("parallel")); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK @@ -1622,8 +1536,7 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgID, // FIXME: Allow to interrupt current push when new push of same image is done. func (srv *Server) ImagePush(job *engine.Job) engine.Status { if n := len(job.Args); n != 1 { - job.Errorf("Usage: %s IMAGE", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s IMAGE", job.Name) } var ( localName = job.Args[0] @@ -1635,23 +1548,20 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status { job.GetenvJson("authConfig", authConfig) job.GetenvJson("metaHeaders", metaHeaders) if _, err := srv.poolAdd("push", localName); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } defer srv.poolRemove("push", localName) // Resolve the Repository name from fqn to endpoint + name endpoint, remoteName, err := registry.ResolveRepositoryName(localName) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } img, err := srv.runtime.graph.Get(localName) r, err2 := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), endpoint) if err2 != nil { - job.Error(err2) - return engine.StatusErr + return job.Error(err2) } if err != nil { @@ -1660,28 +1570,24 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status { // If it fails, try to get the repository if localRepo, exists := srv.runtime.repositories.Repositories[localName]; exists { if err := srv.pushRepository(r, job.Stdout, localName, remoteName, localRepo, sf); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } - job.Error(err) - return engine.StatusErr + return job.Error(err) } var token []string job.Stdout.Write(sf.FormatStatus("", "The push refers to an image: [%s]", localName)) if _, err := srv.pushImage(r, job.Stdout, remoteName, img.ID, endpoint, token, sf); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } func (srv *Server) ImageImport(job *engine.Job) engine.Status { if n := len(job.Args); n != 2 && n != 3 { - job.Errorf("Usage: %s SRC REPO [TAG]", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s SRC REPO [TAG]", job.Name) } var ( src = job.Args[0] @@ -1700,8 +1606,7 @@ func (srv *Server) ImageImport(job *engine.Job) engine.Status { } else { u, err := url.Parse(src) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if u.Scheme == "" { u.Scheme = "http" @@ -1713,21 +1618,18 @@ func (srv *Server) ImageImport(job *engine.Job) engine.Status { // If curl is not available, fallback to http.Get() resp, err = utils.Download(u.String()) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), job.Stdout, sf, true, "", "Importing") } img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } // Optionally register the image at REPO/TAG if repo != "" { if err := srv.runtime.repositories.Set(repo, tag, img.ID, true); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } } job.Stdout.Write(sf.FormatStatus("", img.ID)) @@ -1739,17 +1641,14 @@ func (srv *Server) ContainerCreate(job *engine.Job) engine.Status { if len(job.Args) == 1 { name = job.Args[0] } else if len(job.Args) > 1 { - job.Printf("Usage: %s", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s", job.Name) } var config Config if err := job.ExportEnv(&config); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if config.Memory != 0 && config.Memory < 524288 { - job.Errorf("Minimum memory limit allowed is 512k") - return engine.StatusErr + return job.Errorf("Minimum memory limit allowed is 512k") } if config.Memory > 0 && !srv.runtime.sysInfo.MemoryLimit { job.Errorf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n") @@ -1776,11 +1675,9 @@ func (srv *Server) ContainerCreate(job *engine.Job) engine.Status { if tag == "" { tag = DEFAULTTAG } - job.Errorf("No such image: %s (tag: %s)", config.Image, tag) - return engine.StatusErr + return job.Errorf("No such image: %s (tag: %s)", config.Image, tag) } - job.Error(err) - return engine.StatusErr + return job.Error(err) } if !container.Config.NetworkDisabled && srv.runtime.sysInfo.IPv4ForwardingDisabled { job.Errorf("WARNING: IPv4 forwarding is disabled.\n") @@ -1793,15 +1690,14 @@ func (srv *Server) ContainerCreate(job *engine.Job) engine.Status { job.Printf("%s\n", container.ID) } for _, warning := range buildWarnings { - job.Errorf("%s\n", warning) + return job.Errorf("%s\n", warning) } return engine.StatusOK } func (srv *Server) ContainerRestart(job *engine.Job) engine.Status { if len(job.Args) != 1 { - job.Errorf("Usage: %s CONTAINER\n", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s CONTAINER\n", job.Name) } name := job.Args[0] t := job.GetenvInt("t") @@ -1810,22 +1706,18 @@ func (srv *Server) ContainerRestart(job *engine.Job) engine.Status { } if container := srv.runtime.Get(name); container != nil { if err := container.Restart(int(t)); err != nil { - job.Errorf("Cannot restart container %s: %s\n", name, err) - return engine.StatusErr + return job.Errorf("Cannot restart container %s: %s\n", name, err) } srv.LogEvent("restart", container.ID, srv.runtime.repositories.ImageName(container.Image)) } else { - job.Errorf("No such container: %s\n", name) - return engine.StatusErr + return job.Errorf("No such container: %s\n", name) } return engine.StatusOK - } func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status { if len(job.Args) != 1 { - job.Errorf("Not enough arguments. Usage: %s CONTAINER\n", job.Name) - return engine.StatusErr + return job.Errorf("Not enough arguments. Usage: %s CONTAINER\n", job.Name) } name := job.Args[0] removeVolume := job.GetenvBool("removeVolume") @@ -1835,23 +1727,19 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status { if removeLink { if container == nil { - job.Errorf("No such link: %s", name) - return engine.StatusErr + return job.Errorf("No such link: %s", name) } name, err := getFullName(name) if err != nil { job.Error(err) - return engine.StatusErr } parent, n := path.Split(name) if parent == "/" { - job.Errorf("Conflict, cannot remove the default name of the container") - return engine.StatusErr + return job.Errorf("Conflict, cannot remove the default name of the container") } pe := srv.runtime.containerGraph.Get(parent) if pe == nil { - job.Errorf("Cannot get parent %s for name %s", parent, name) - return engine.StatusErr + return job.Errorf("Cannot get parent %s for name %s", parent, name) } parentContainer := srv.runtime.Get(pe.ID()) @@ -1864,16 +1752,14 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status { } if err := srv.runtime.containerGraph.Delete(name); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } if container != nil { if container.State.IsRunning() { - job.Errorf("Impossible to remove a running container, please stop it first") - return engine.StatusErr + return job.Errorf("Impossible to remove a running container, please stop it first") } volumes := make(map[string]struct{}) @@ -1898,8 +1784,7 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status { volumes[volumeId] = struct{}{} } if err := srv.runtime.Destroy(container); err != nil { - job.Errorf("Cannot destroy container %s: %s", name, err) - return engine.StatusErr + return job.Errorf("Cannot destroy container %s: %s", name, err) } srv.LogEvent("destroy", container.ID, srv.runtime.repositories.ImageName(container.Image)) @@ -1919,14 +1804,12 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status { continue } if err := srv.runtime.volumes.Delete(volumeId); err != nil { - job.Errorf("Error calling volumes.Delete(%q): %v", volumeId, err) - return engine.StatusErr + return job.Errorf("Error calling volumes.Delete(%q): %v", volumeId, err) } } } } else { - job.Errorf("No such container: %s", name) - return engine.StatusErr + return job.Errorf("No such container: %s", name) } return engine.StatusOK } @@ -2078,22 +1961,18 @@ func (srv *Server) DeleteImage(name string, autoPrune bool) (*engine.Table, erro func (srv *Server) ImageDelete(job *engine.Job) engine.Status { if n := len(job.Args); n != 1 { - job.Errorf("Usage: %s IMAGE", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s IMAGE", job.Name) } imgs, err := srv.DeleteImage(job.Args[0], job.GetenvBool("autoPrune")) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if len(imgs.Data) == 0 { - job.Errorf("Conflict, %s wasn't deleted", job.Args[0]) - return engine.StatusErr + return job.Errorf("Conflict, %s wasn't deleted", job.Args[0]) } if _, err := imgs.WriteListTo(job.Stdout); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } @@ -2183,23 +2062,20 @@ func (srv *Server) RegisterLinks(container *Container, hostConfig *HostConfig) e func (srv *Server) ContainerStart(job *engine.Job) engine.Status { if len(job.Args) < 1 { - job.Errorf("Usage: %s container_id", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s container_id", job.Name) } name := job.Args[0] runtime := srv.runtime container := runtime.Get(name) if container == nil { - job.Errorf("No such container: %s", name) - return engine.StatusErr + return job.Errorf("No such container: %s", name) } // If no environment was set, then no hostconfig was passed. if len(job.Environ()) > 0 { var hostConfig HostConfig if err := job.ExportEnv(&hostConfig); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } // Validate the HostConfig binds. Make sure that: // 1) the source of a bind mount isn't / @@ -2212,8 +2088,7 @@ func (srv *Server) ContainerStart(job *engine.Job) engine.Status { // refuse to bind mount "/" to the container if source == "/" { - job.Errorf("Invalid bind mount '%s' : source can't be '/'", bind) - return engine.StatusErr + return job.Errorf("Invalid bind mount '%s' : source can't be '/'", bind) } // ensure the source exists on the host @@ -2221,22 +2096,19 @@ func (srv *Server) ContainerStart(job *engine.Job) engine.Status { if err != nil && os.IsNotExist(err) { err = os.MkdirAll(source, 0755) if err != nil { - job.Errorf("Could not create local directory '%s' for bind mount: %s!", source, err.Error()) - return engine.StatusErr + return job.Errorf("Could not create local directory '%s' for bind mount: %s!", source, err.Error()) } } } // Register any links from the host config before starting the container if err := srv.RegisterLinks(container, &hostConfig); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } container.hostConfig = &hostConfig container.ToDisk() } if err := container.Start(); err != nil { - job.Errorf("Cannot start container %s: %s", name, err) - return engine.StatusErr + return job.Errorf("Cannot start container %s: %s", name, err) } srv.LogEvent("start", container.ID, runtime.repositories.ImageName(container.Image)) @@ -2245,8 +2117,7 @@ func (srv *Server) ContainerStart(job *engine.Job) engine.Status { func (srv *Server) ContainerStop(job *engine.Job) engine.Status { if len(job.Args) != 1 { - job.Errorf("Usage: %s CONTAINER\n", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s CONTAINER\n", job.Name) } name := job.Args[0] t := job.GetenvInt("t") @@ -2255,21 +2126,18 @@ func (srv *Server) ContainerStop(job *engine.Job) engine.Status { } if container := srv.runtime.Get(name); container != nil { if err := container.Stop(int(t)); err != nil { - job.Errorf("Cannot stop container %s: %s\n", name, err) - return engine.StatusErr + return job.Errorf("Cannot stop container %s: %s\n", name, err) } srv.LogEvent("stop", container.ID, srv.runtime.repositories.ImageName(container.Image)) } else { - job.Errorf("No such container: %s\n", name) - return engine.StatusErr + return job.Errorf("No such container: %s\n", name) } return engine.StatusOK } func (srv *Server) ContainerWait(job *engine.Job) engine.Status { if len(job.Args) != 1 { - job.Errorf("Usage: %s", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s", job.Name) } name := job.Args[0] if container := srv.runtime.Get(name); container != nil { @@ -2277,41 +2145,34 @@ func (srv *Server) ContainerWait(job *engine.Job) engine.Status { job.Printf("%d\n", status) return engine.StatusOK } - job.Errorf("%s: no such container: %s", job.Name, name) - return engine.StatusErr + return job.Errorf("%s: no such container: %s", job.Name, name) } func (srv *Server) ContainerResize(job *engine.Job) engine.Status { if len(job.Args) != 3 { - job.Errorf("Not enough arguments. Usage: %s CONTAINER HEIGHT WIDTH\n", job.Name) - return engine.StatusErr + return job.Errorf("Not enough arguments. Usage: %s CONTAINER HEIGHT WIDTH\n", job.Name) } name := job.Args[0] height, err := strconv.Atoi(job.Args[1]) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } width, err := strconv.Atoi(job.Args[2]) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if container := srv.runtime.Get(name); container != nil { if err := container.Resize(height, width); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } - job.Errorf("No such container: %s", name) - return engine.StatusErr + return job.Errorf("No such container: %s", name) } func (srv *Server) ContainerAttach(job *engine.Job) engine.Status { if len(job.Args) != 1 { - job.Errorf("Usage: %s CONTAINER\n", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s CONTAINER\n", job.Name) } var ( @@ -2325,8 +2186,7 @@ func (srv *Server) ContainerAttach(job *engine.Job) engine.Status { container := srv.runtime.Get(name) if container == nil { - job.Errorf("No such container: %s", name) - return engine.StatusErr + return job.Errorf("No such container: %s", name) } //logs @@ -2377,8 +2237,7 @@ func (srv *Server) ContainerAttach(job *engine.Job) engine.Status { //stream if stream { if container.State.IsGhost() { - job.Errorf("Impossible to attach to a ghost container") - return engine.StatusErr + return job.Errorf("Impossible to attach to a ghost container") } var ( @@ -2432,8 +2291,7 @@ func (srv *Server) ImageInspect(name string) (*Image, error) { func (srv *Server) JobInspect(job *engine.Job) engine.Status { // TODO: deprecate KIND/conflict if n := len(job.Args); n != 2 { - job.Errorf("Usage: %s CONTAINER|IMAGE KIND", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s CONTAINER|IMAGE KIND", job.Name) } var ( name = job.Args[0] @@ -2445,35 +2303,30 @@ func (srv *Server) JobInspect(job *engine.Job) engine.Status { ) if conflict && image != nil && container != nil { - job.Errorf("Conflict between containers and images") - return engine.StatusErr + return job.Errorf("Conflict between containers and images") } switch kind { case "image": if errImage != nil { - job.Error(errImage) - return engine.StatusErr + return job.Error(errImage) } object = image case "container": if errContainer != nil { - job.Error(errContainer) - return engine.StatusErr + return job.Error(errContainer) } object = &struct { *Container HostConfig *HostConfig }{container, container.hostConfig} default: - job.Errorf("Unknown kind: %s", kind) - return engine.StatusErr + return job.Errorf("Unknown kind: %s", kind) } b, err := json.Marshal(object) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } job.Stdout.Write(b) return engine.StatusOK @@ -2481,8 +2334,7 @@ func (srv *Server) JobInspect(job *engine.Job) engine.Status { func (srv *Server) ContainerCopy(job *engine.Job) engine.Status { if len(job.Args) != 2 { - job.Errorf("Usage: %s CONTAINER RESOURCE\n", job.Name) - return engine.StatusErr + return job.Errorf("Usage: %s CONTAINER RESOURCE\n", job.Name) } var ( @@ -2494,19 +2346,15 @@ func (srv *Server) ContainerCopy(job *engine.Job) engine.Status { data, err := container.Copy(resource) if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if _, err := io.Copy(job.Stdout, data); err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } return engine.StatusOK } - job.Errorf("No such container: %s", name) - return engine.StatusErr - + return job.Errorf("No such container: %s", name) } func NewServer(eng *engine.Engine, config *DaemonConfig) (*Server, error) { From 3f744f45d9f881f68a00e8e86101fa871790d9b2 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Tue, 28 Jan 2014 03:26:24 +0000 Subject: [PATCH 3/6] add setSubEnv and getSubEnv Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) Upstream-commit: 7b7f7e443637d8303f03316ee437012b71936c12 Component: engine --- components/engine/api.go | 18 +++++++----------- components/engine/engine/env.go | 22 ++++++++++++++++++++++ components/engine/engine/job.go | 8 ++++++++ components/engine/server.go | 3 +-- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/components/engine/api.go b/components/engine/api.go index ba8646599d..4d294667ac 100644 --- a/components/engine/api.go +++ b/components/engine/api.go @@ -345,11 +345,11 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req return err } var ( - config = &Config{} + config engine.Env env engine.Env job = srv.Eng.Job("commit", r.Form.Get("container")) ) - if err := json.NewDecoder(r.Body).Decode(config); err != nil && err != io.EOF { + if err := config.Import(r.Body); err != nil { utils.Errorf("%s", err) } @@ -357,7 +357,7 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req job.Setenv("tag", r.Form.Get("tag")) job.Setenv("author", r.Form.Get("author")) job.Setenv("comment", r.Form.Get("comment")) - job.SetenvJson("config", config) + job.SetenvSubEnv("config", &config) var id string job.Stdout.AddString(&id) @@ -704,18 +704,14 @@ func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r return fmt.Errorf("Missing parameter") } - // TODO: replace the buffer by job.AddEnv() var ( job = srv.Eng.Job("inspect", vars["name"], "container") - buffer = bytes.NewBuffer(nil) - c Container + c, err = job.Stdout.AddEnv() ) - job.Stdout.Add(buffer) - if err := job.Run(); err != nil { + if err != nil { return err } - - if err := json.Unmarshal(buffer.Bytes(), &c); err != nil { + if err = job.Run(); err != nil { return err } @@ -742,7 +738,7 @@ func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") - if !c.Config.Tty && version >= 1.6 { + if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version >= 1.6 { errStream = utils.NewStdWriter(outStream, utils.Stderr) outStream = utils.NewStdWriter(outStream, utils.Stdout) } else { diff --git a/components/engine/engine/env.go b/components/engine/engine/env.go index f93555a40b..f30e135555 100644 --- a/components/engine/engine/env.go +++ b/components/engine/engine/env.go @@ -86,6 +86,28 @@ func (env *Env) GetList(key string) []string { return l } +func (env *Env) GetSubEnv(key string) *Env { + sval := env.Get(key) + if sval == "" { + return nil + } + buf := bytes.NewBufferString(sval) + var sub Env + if err := sub.Decode(buf); err != nil { + return nil + } + return &sub +} + +func (env *Env) SetSubEnv(key string, sub *Env) error { + var buf bytes.Buffer + if err := sub.Encode(&buf); err != nil { + return err + } + env.Set(key, string(buf.Bytes())) + return nil +} + func (env *Env) GetJson(key string, iface interface{}) error { sval := env.Get(key) if sval == "" { diff --git a/components/engine/engine/job.go b/components/engine/engine/job.go index 34393fcab5..5447441beb 100644 --- a/components/engine/engine/job.go +++ b/components/engine/engine/job.go @@ -114,6 +114,14 @@ func (job *Job) SetenvBool(key string, value bool) { job.env.SetBool(key, value) } +func (job *Job) GetenvSubEnv(key string) *Env { + return job.env.GetSubEnv(key) +} + +func (job *Job) SetenvSubEnv(key string, value *Env) error { + return job.env.SetSubEnv(key, value) +} + func (job *Job) GetenvInt64(key string) int64 { return job.env.GetInt64(key) } diff --git a/components/engine/server.go b/components/engine/server.go index a6f869f977..2df7a8abc6 100644 --- a/components/engine/server.go +++ b/components/engine/server.go @@ -1660,8 +1660,7 @@ func (srv *Server) ContainerCreate(job *engine.Job) engine.Status { } resolvConf, err := utils.GetResolvConf() if err != nil { - job.Error(err) - return engine.StatusErr + return job.Error(err) } if !config.NetworkDisabled && len(config.Dns) == 0 && len(srv.runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) { job.Errorf("WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v\n", defaultDns) From 3fc86028ff88cc40ffd56636052871ebd3189538 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 29 Jan 2014 19:26:54 +0000 Subject: [PATCH 4/6] move api to it's own package Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) Upstream-commit: f556cd4186dfdb5e96b2e58b5caf9edbe7e2d7df Component: engine --- components/engine/{ => api}/api.go | 185 ++++++++++-------- .../{http_test.go => api/api_unit_test.go} | 16 +- components/engine/api_unit_test.go | 19 -- components/engine/commands.go | 11 +- components/engine/docker/docker.go | 3 +- components/engine/integration/api_test.go | 87 ++++---- components/engine/opts.go | 3 +- components/engine/server.go | 3 +- 8 files changed, 159 insertions(+), 168 deletions(-) rename components/engine/{ => api}/api.go (78%) rename components/engine/{http_test.go => api/api_unit_test.go} (82%) delete mode 100644 components/engine/api_unit_test.go diff --git a/components/engine/api.go b/components/engine/api/api.go similarity index 78% rename from components/engine/api.go rename to components/engine/api/api.go index 4d294667ac..61069445fc 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,7 @@ 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 hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) { conn, _, err := w.(http.Hijacker).Hijack() @@ -106,7 +106,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 +127,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 +150,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 +174,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 +186,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 +194,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 +232,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 +273,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 +294,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 +336,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 +344,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 +353,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 +382,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 +412,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 +434,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 +458,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 +466,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 +477,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 +491,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 +525,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 +541,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 +590,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 +606,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 +623,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 +658,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 +674,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 +696,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 +718,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 +758,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 +774,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 +782,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 +806,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 +835,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 +883,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 +905,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 +913,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 +923,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 +934,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 +951,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 +984,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 +1045,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 +1063,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 +1106,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 } 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 5af02046a3..981ae3d0b8 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..2da9c1fa26 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) } diff --git a/components/engine/integration/api_test.go b/components/engine/integration/api_test.go index b9ff079cb1..ad631f97e2 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/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 2df7a8abc6..ce6024d919 100644 --- a/components/engine/server.go +++ b/components/engine/server.go @@ -4,6 +4,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" @@ -122,7 +123,7 @@ func (srv *Server) ListenAndServe(job *engine.Job) engine.Status { 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")) + chErrors <- api.ListenAndServe(protoAddrParts[0], protoAddrParts[1], srv.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), VERSION) }() } From bef9a1a530435a5b310941313bc18fb7e3c66f56 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 29 Jan 2014 20:16:47 +0000 Subject: [PATCH 5/6] remove some mkServerFromEngine Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) Upstream-commit: fc2f998822699c0c7e22e4fc791d10c3b1ea1e53 Component: engine --- components/engine/integration/runtime_test.go | 7 ++++--- components/engine/integration/sorter_test.go | 14 ++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/components/engine/integration/runtime_test.go b/components/engine/integration/runtime_test.go index e08643b36d..4fc3c56868 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 @@ -132,10 +132,11 @@ func setupBaseImage() { 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)) 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() From 140db53b4e70a8ee18907dd9b320f9bdea00bf4a Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 31 Jan 2014 19:30:43 +0000 Subject: [PATCH 6/6] Move serveapi to api/api.go Remove api import from server.go Rename initapi to init server Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) Upstream-commit: 9eea7f28f0c64d43ef2a9987999a29774fa1476b Component: engine --- components/engine/api/api.go | 31 +++++++++++++++++ components/engine/docker/docker.go | 3 +- components/engine/integration/runtime_test.go | 10 +++--- components/engine/integration/server_test.go | 2 +- components/engine/integration/utils_test.go | 2 +- components/engine/server.go | 34 ++----------------- 6 files changed, 42 insertions(+), 40 deletions(-) diff --git a/components/engine/api/api.go b/components/engine/api/api.go index 61069445fc..b722eb5c60 100644 --- a/components/engine/api/api.go +++ b/components/engine/api/api.go @@ -36,6 +36,10 @@ const ( 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() if err != nil { @@ -1160,3 +1164,30 @@ func ListenAndServe(proto, addr string, eng *engine.Engine, logging, enableCors 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/docker/docker.go b/components/engine/docker/docker.go index 2da9c1fa26..ba7764050b 100644 --- a/components/engine/docker/docker.go +++ b/components/engine/docker/docker.go @@ -83,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) @@ -103,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/runtime_test.go b/components/engine/integration/runtime_test.go index 9afc10f5af..da95967a30 100644 --- a/components/engine/integration/runtime_test.go +++ b/components/engine/integration/runtime_test.go @@ -125,7 +125,7 @@ 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) @@ -573,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 { @@ -605,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 { @@ -615,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 { @@ -665,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/utils_test.go b/components/engine/integration/utils_test.go index d7a2814472..67f31a312a 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/server.go b/components/engine/server.go index 3561e76abd..f4d2f3722f 100644 --- a/components/engine/server.go +++ b/components/engine/server.go @@ -4,12 +4,10 @@ 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" "github.com/dotcloud/docker/pkg/graphdb" - "github.com/dotcloud/docker/pkg/systemd" "github.com/dotcloud/docker/registry" "github.com/dotcloud/docker/utils" "io" @@ -35,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 { @@ -77,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, @@ -112,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 <- api.ListenAndServe(protoAddrParts[0], protoAddrParts[1], srv.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), 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 -} - // simpleVersionInfo is a simple implementation of // the interface VersionInfo, which is used // to provide version information for some product,