diff --git a/api/client/cli.go b/api/client/cli.go index 7f600d3489..b073c3abc8 100644 --- a/api/client/cli.go +++ b/api/client/cli.go @@ -103,7 +103,12 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF } customHeaders["User-Agent"] = "Docker-Client/" + dockerversion.Version + " (" + runtime.GOOS + ")" - client, err := lib.NewClient(host, string(api.Version), clientFlags.Common.TLSOptions, customHeaders) + verStr := string(api.DefaultVersion) + if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" { + verStr = tmpStr + } + + client, err := lib.NewClient(host, verStr, clientFlags.Common.TLSOptions, customHeaders) if err != nil { return err } diff --git a/api/client/client.go b/api/client/client.go index f452ad6187..edb75e8627 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -17,6 +17,7 @@ import ( // apiClient is an interface that clients that talk with a docker server must implement. type apiClient interface { + ClientVersion() string ContainerAttach(options types.ContainerAttachOptions) (types.HijackedResponse, error) ContainerCommit(options types.ContainerCommitOptions) (types.ContainerCommitResponse, error) ContainerCreate(config *runconfig.ContainerConfigWrapper, containerName string) (types.ContainerCreateResponse, error) diff --git a/api/client/lib/client.go b/api/client/lib/client.go index f0ad922fa1..2bae2d101e 100644 --- a/api/client/lib/client.go +++ b/api/client/lib/client.go @@ -96,3 +96,10 @@ func (cli *Client) getAPIPath(p string, query url.Values) string { } return apiPath } + +// ClientVersion returns the version string associated with this +// instance of the Client. Note that this value can be changed +// via the DOCKER_API_VERSION env var. +func (cli *Client) ClientVersion() string { + return cli.version +} diff --git a/api/client/version.go b/api/client/version.go index 61125cecbc..c4abbf0949 100644 --- a/api/client/version.go +++ b/api/client/version.go @@ -5,11 +5,11 @@ import ( "text/template" "time" - "github.com/docker/docker/api" "github.com/docker/docker/api/types" Cli "github.com/docker/docker/cli" "github.com/docker/docker/dockerversion" flag "github.com/docker/docker/pkg/mflag" + "github.com/docker/docker/pkg/version" "github.com/docker/docker/utils" ) @@ -57,7 +57,7 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) { vd := types.VersionResponse{ Client: &types.Version{ Version: dockerversion.Version, - APIVersion: api.Version, + APIVersion: version.Version(cli.client.ClientVersion()), GoVersion: runtime.Version(), GitCommit: dockerversion.GitCommit, BuildTime: dockerversion.BuildTime, diff --git a/api/common.go b/api/common.go index 3f9f81d801..b72070b965 100644 --- a/api/common.go +++ b/api/common.go @@ -18,7 +18,7 @@ import ( // Common constants for daemon and client. const ( // Version of Current REST API - Version version.Version = "1.22" + DefaultVersion version.Version = "1.22" // MinVersion represents Minimum REST API version supported MinVersion version.Version = "1.12" diff --git a/api/server/middleware.go b/api/server/middleware.go index 3bb6419275..548d0c2911 100644 --- a/api/server/middleware.go +++ b/api/server/middleware.go @@ -121,14 +121,14 @@ func versionMiddleware(handler httputils.APIFunc) httputils.APIFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { apiVersion := version.Version(vars["version"]) if apiVersion == "" { - apiVersion = api.Version + apiVersion = api.DefaultVersion } - if apiVersion.GreaterThan(api.Version) { - return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, api.Version) + if apiVersion.GreaterThan(api.DefaultVersion) { + return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, api.DefaultVersion) } if apiVersion.LessThan(api.MinVersion) { - return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.Version) + return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.DefaultVersion) } w.Header().Set("Server", "Docker/"+dockerversion.Version+" ("+runtime.GOOS+")") diff --git a/api/server/router/system/system_routes.go b/api/server/router/system/system_routes.go index e93d0c0d38..4ab59f2011 100644 --- a/api/server/router/system/system_routes.go +++ b/api/server/router/system/system_routes.go @@ -38,7 +38,7 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { info := s.backend.SystemVersion() - info.APIVersion = api.Version + info.APIVersion = api.DefaultVersion return httputils.WriteJSON(w, http.StatusOK, info) } diff --git a/docs/reference/commandline/cli.md b/docs/reference/commandline/cli.md index 4d1a0c7961..6a9a1d85fb 100644 --- a/docs/reference/commandline/cli.md +++ b/docs/reference/commandline/cli.md @@ -38,6 +38,7 @@ the [installation](../../installation/index.md) instructions for your operating For easy reference, the following list of environment variables are supported by the `docker` command line: +* `DOCKER_API_VERSION` The API version to use (e.g. `1.19`) * `DOCKER_CONFIG` The location of your client configuration files. * `DOCKER_CERT_PATH` The location of your authentication keys. * `DOCKER_DRIVER` The graph driver to use. diff --git a/integration-cli/docker_api_test.go b/integration-cli/docker_api_test.go index 087737853c..a5fc57c297 100644 --- a/integration-cli/docker_api_test.go +++ b/integration-cli/docker_api_test.go @@ -2,7 +2,10 @@ package main import ( "net/http" + "net/http/httptest" "net/http/httputil" + "os" + "os/exec" "strconv" "strings" "time" @@ -46,7 +49,7 @@ func (s *DockerSuite) TestApiVersionStatusCode(c *check.C) { } func (s *DockerSuite) TestApiClientVersionNewerThanServer(c *check.C) { - v := strings.Split(string(api.Version), ".") + v := strings.Split(string(api.DefaultVersion), ".") vMinInt, err := strconv.Atoi(v[1]) c.Assert(err, checker.IsNil) vMinInt++ @@ -72,3 +75,25 @@ func (s *DockerSuite) TestApiClientVersionOldNotSupported(c *check.C) { c.Assert(status, checker.Equals, http.StatusBadRequest) c.Assert(len(string(body)), checker.Not(check.Equals), 0) // Expected not empty body } + +func (s *DockerSuite) TestApiDockerApiVersion(c *check.C) { + var svrVersion string + + server := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + url := r.URL.Path + svrVersion = url + })) + defer server.Close() + + // Test using the env var first + cmd := exec.Command(dockerBinary, "-H="+server.URL[7:], "version") + cmd.Env = append([]string{"DOCKER_API_VERSION=xxx"}, os.Environ()...) + out, _, _ := runCommandWithOutput(cmd) + + c.Assert(svrVersion, check.Equals, "/vxxx/version") + + if !strings.Contains(out, "API version: xxx") { + c.Fatalf("Out didn't have 'xxx' for the API version, had:\n%s", out) + } +}