Переглянути джерело

Merge pull request #3119 from shykes/engine-version

Port 'docker version' to the engine API
Victor Vieux 11 роки тому
батько
коміт
09d2c2351c
7 змінених файлів з 105 додано та 54 видалено
  1. 2 1
      api.go
  2. 0 6
      api_params.go
  3. 12 13
      commands.go
  4. 40 0
      engine/http.go
  5. 11 4
      integration/api_test.go
  6. 7 30
      server.go
  7. 33 0
      version.go

+ 2 - 1
api.go

@@ -140,7 +140,8 @@ func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Reque
 }
 
 func getVersion(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	return writeJSON(w, http.StatusOK, srv.DockerVersion())
+	srv.Eng.ServeHTTP(w, r)
+	return nil
 }
 
 func postContainersKill(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {

+ 0 - 6
api_params.go

@@ -95,12 +95,6 @@ type (
 		IP          string
 	}
 
-	APIVersion struct {
-		Version   string
-		GitCommit string `json:",omitempty"`
-		GoVersion string `json:",omitempty"`
-	}
-
 	APIWait struct {
 		StatusCode int
 	}

+ 12 - 13
commands.go

@@ -11,6 +11,7 @@ import (
 	"fmt"
 	"github.com/dotcloud/docker/archive"
 	"github.com/dotcloud/docker/auth"
+	"github.com/dotcloud/docker/engine"
 	"github.com/dotcloud/docker/registry"
 	"github.com/dotcloud/docker/term"
 	"github.com/dotcloud/docker/utils"
@@ -391,26 +392,24 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
 		return err
 	}
 
-	var out APIVersion
-	err = json.Unmarshal(body, &out)
+	out := engine.NewOutput()
+	remoteVersion, err := out.AddEnv()
 	if err != nil {
-		utils.Errorf("Error unmarshal: body: %s, err: %s\n", body, err)
+		utils.Errorf("Error reading remote version: %s\n", err)
 		return err
 	}
-	if out.Version != "" {
-		fmt.Fprintf(cli.out, "Server version: %s\n", out.Version)
-	}
-	if out.GitCommit != "" {
-		fmt.Fprintf(cli.out, "Git commit (server): %s\n", out.GitCommit)
-	}
-	if out.GoVersion != "" {
-		fmt.Fprintf(cli.out, "Go version (server): %s\n", out.GoVersion)
+	if _, err := out.Write(body); err != nil {
+		utils.Errorf("Error reading remote version: %s\n", err)
+		return err
 	}
-
+	out.Close()
+	fmt.Fprintf(cli.out, "Server version: %s\n", remoteVersion.Get("Version"))
+	fmt.Fprintf(cli.out, "Git commit (server): %s\n", remoteVersion.Get("GitCommit"))
+	fmt.Fprintf(cli.out, "Go version (server): %s\n", remoteVersion.Get("GoVersion"))
 	release := utils.GetReleaseVersion()
 	if release != "" {
 		fmt.Fprintf(cli.out, "Last stable version: %s", release)
-		if (VERSION != "" || out.Version != "") && (strings.Trim(VERSION, "-dev") != release || strings.Trim(out.Version, "-dev") != release) {
+		if (VERSION != "" || remoteVersion.Exists("Version")) && (strings.Trim(VERSION, "-dev") != release || strings.Trim(remoteVersion.Get("Version"), "-dev") != release) {
 			fmt.Fprintf(cli.out, ", please update docker")
 		}
 		fmt.Fprintf(cli.out, "\n")

+ 40 - 0
engine/http.go

@@ -0,0 +1,40 @@
+package engine
+
+import (
+	"path"
+	"net/http"
+)
+
+// ServeHTTP executes a job as specified by the http request `r`, and sends the
+// result as an http response.
+// This method allows an Engine instance to be passed as a standard http.Handler interface.
+//
+// Note that the protocol used in this methid is a convenience wrapper and is not the canonical
+// implementation of remote job execution. This is because HTTP/1 does not handle stream multiplexing,
+// and so cannot differentiate stdout from stderr. Additionally, headers cannot be added to a response
+// once data has been written to the body, which makes it inconvenient to return metadata such
+// as the exit status.
+//
+func (eng *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	jobName := path.Base(r.URL.Path)
+	jobArgs, exists := r.URL.Query()["a"]
+	if !exists {
+		jobArgs = []string{}
+	}
+	w.Header().Set("Job-Name", jobName)
+	for _, arg := range(jobArgs) {
+		w.Header().Add("Job-Args", arg)
+	}
+	job := eng.Job(jobName, jobArgs...)
+	job.Stdout.Add(w)
+	job.Stderr.Add(w)
+	// FIXME: distinguish job status from engine error in Run()
+	// The former should be passed as a special header, the former
+	// should cause a 500 status
+	w.WriteHeader(http.StatusOK)
+	// The exit status cannot be sent reliably with HTTP1, because headers
+	// can only be sent before the body.
+	// (we could possibly use http footers via chunked encoding, but I couldn't find
+	// how to use them in net/http)
+	job.Run()
+}

+ 11 - 4
integration/api_test.go

@@ -7,6 +7,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"github.com/dotcloud/docker"
+	"github.com/dotcloud/docker/engine"
 	"github.com/dotcloud/docker/utils"
 	"io"
 	"net"
@@ -35,12 +36,18 @@ func TestGetVersion(t *testing.T) {
 	}
 	assertHttpNotError(r, t)
 
-	v := &docker.APIVersion{}
-	if err = json.Unmarshal(r.Body.Bytes(), v); err != nil {
+	out := engine.NewOutput()
+	v, err := out.AddEnv()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if _, err := io.Copy(out, r.Body); err != nil {
 		t.Fatal(err)
 	}
-	if v.Version != docker.VERSION {
-		t.Errorf("Expected version %s, %s found", docker.VERSION, v.Version)
+	out.Close()
+	expected := docker.VERSION
+	if result := v.Get("Version"); result != expected {
+		t.Errorf("Expected version %s, %s found", expected, result)
 	}
 }
 

+ 7 - 30
server.go

@@ -122,14 +122,6 @@ func (srv *Server) ListenAndServe(job *engine.Job) engine.Status {
 	return engine.StatusOK
 }
 
-func (srv *Server) DockerVersion() APIVersion {
-	return APIVersion{
-		Version:   VERSION,
-		GitCommit: GITCOMMIT,
-		GoVersion: runtime.Version(),
-	}
-}
-
 // simpleVersionInfo is a simple implementation of
 // the interface VersionInfo, which is used
 // to provide version information for some product,
@@ -148,27 +140,6 @@ func (v *simpleVersionInfo) Version() string {
 	return v.version
 }
 
-// versionCheckers() returns version informations of:
-// docker, go, git-commit (of the docker) and the host's kernel.
-//
-// Such information will be used on call to NewRegistry().
-func (srv *Server) versionInfos() []utils.VersionInfo {
-	v := srv.DockerVersion()
-	ret := append(make([]utils.VersionInfo, 0, 4), &simpleVersionInfo{"docker", v.Version})
-
-	if len(v.GoVersion) > 0 {
-		ret = append(ret, &simpleVersionInfo{"go", v.GoVersion})
-	}
-	if len(v.GitCommit) > 0 {
-		ret = append(ret, &simpleVersionInfo{"git-commit", v.GitCommit})
-	}
-	if kernelVersion, err := utils.GetKernelVersion(); err == nil {
-		ret = append(ret, &simpleVersionInfo{"kernel", kernelVersion.String()})
-	}
-
-	return ret
-}
-
 // ContainerKill send signal to the container
 // If no signal is given (sig 0), then Kill with SIGKILL and wait
 // for the container to exit.
@@ -1886,7 +1857,13 @@ func NewServer(eng *engine.Engine, config *DaemonConfig) (*Server, error) {
 func (srv *Server) HTTPRequestFactory(metaHeaders map[string][]string) *utils.HTTPRequestFactory {
 	srv.Lock()
 	defer srv.Unlock()
-	ud := utils.NewHTTPUserAgentDecorator(srv.versionInfos()...)
+	v := dockerVersion()
+	httpVersion := make([]utils.VersionInfo, 0, 4)
+	httpVersion = append(httpVersion, &simpleVersionInfo{"docker", v.Get("Version")})
+	httpVersion = append(httpVersion, &simpleVersionInfo{"go", v.Get("GoVersion")})
+	httpVersion = append(httpVersion, &simpleVersionInfo{"git-commit", v.Get("GitCommit")})
+	httpVersion = append(httpVersion, &simpleVersionInfo{"kernel", v.Get("KernelVersion")})
+	ud := utils.NewHTTPUserAgentDecorator(httpVersion...)
 	md := &utils.HTTPMetaHeadersDecorator{
 		Headers: metaHeaders,
 	}

+ 33 - 0
version.go

@@ -0,0 +1,33 @@
+package docker
+
+import (
+	"github.com/dotcloud/docker/engine"
+	"github.com/dotcloud/docker/utils"
+	"runtime"
+)
+
+func init() {
+	engine.Register("version", jobVersion)
+}
+
+func jobVersion(job *engine.Job) engine.Status {
+	if _, err := dockerVersion().WriteTo(job.Stdout); err != nil {
+		job.Errorf("%s", err)
+		return engine.StatusErr
+	}
+	return engine.StatusOK
+}
+
+// dockerVersion returns detailed version information in the form of a queriable
+// environment.
+func dockerVersion() *engine.Env {
+	v := &engine.Env{}
+	v.Set("Version", VERSION)
+	v.Set("GitCommit", GITCOMMIT)
+	v.Set("GoVersion", runtime.Version())
+	// FIXME:utils.GetKernelVersion should only be needed here
+	if kernelVersion, err := utils.GetKernelVersion(); err == nil {
+		v.Set("KernelVersion", kernelVersion.String())
+	}
+	return v
+}