Browse Source

Error out if client API version is too old

Signed-off-by: Antonio Murdaca <runcom@linux.com>
Antonio Murdaca 10 years ago
parent
commit
910322a893
6 changed files with 52 additions and 11 deletions
  1. 1 1
      api/client/hijack.go
  2. 1 1
      api/client/utils.go
  3. 1 1
      api/client/version.go
  4. 8 2
      api/common.go
  5. 8 4
      api/server/server.go
  6. 33 2
      integration-cli/docker_api_test.go

+ 1 - 1
api/client/hijack.go

@@ -138,7 +138,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
 	if err != nil {
 		return err
 	}
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), params)
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.Version, path), params)
 	if err != nil {
 		return err
 	}

+ 1 - 1
api/client/utils.go

@@ -53,7 +53,7 @@ func (cli *DockerCli) clientRequest(method, path string, in io.Reader, headers m
 	if expectedPayload && in == nil {
 		in = bytes.NewReader([]byte{})
 	}
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), in)
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.Version, path), in)
 	if err != nil {
 		return nil, nil, -1, err
 	}

+ 1 - 1
api/client/version.go

@@ -26,7 +26,7 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
 	if dockerversion.VERSION != "" {
 		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
 	}
-	fmt.Fprintf(cli.out, "Client API version: %s\n", api.APIVERSION)
+	fmt.Fprintf(cli.out, "Client API version: %s\n", api.Version)
 	fmt.Fprintf(cli.out, "Go version (client): %s\n", runtime.Version())
 	if dockerversion.GITCOMMIT != "" {
 		fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)

+ 8 - 2
api/common.go

@@ -16,8 +16,14 @@ import (
 
 // Common constants for daemon and client.
 const (
-	APIVERSION            version.Version = "1.20"       // Current REST API version
-	DefaultDockerfileName string          = "Dockerfile" // Default filename with Docker commands, read by docker build
+	// Current REST API version
+	Version version.Version = "1.20"
+
+	// Minimun REST API version supported
+	MinVersion version.Version = "1.12"
+
+	// Default filename with Docker commands, read by docker build
+	DefaultDockerfileName string = "Dockerfile"
 )
 
 type ByPrivatePort []types.Port

+ 8 - 4
api/server/server.go

@@ -244,7 +244,7 @@ func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *htt
 func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	v := &types.Version{
 		Version:    dockerversion.VERSION,
-		ApiVersion: api.APIVERSION,
+		ApiVersion: api.Version,
 		GitCommit:  dockerversion.GITCOMMIT,
 		GoVersion:  runtime.Version(),
 		Os:         runtime.GOOS,
@@ -1477,14 +1477,18 @@ func makeHttpHandler(logging bool, localMethod string, localRoute string, handle
 		}
 		version := version.Version(mux.Vars(r)["version"])
 		if version == "" {
-			version = api.APIVERSION
+			version = api.Version
 		}
 		if corsHeaders != "" {
 			writeCorsHeaders(w, r, corsHeaders)
 		}
 
-		if version.GreaterThan(api.APIVERSION) {
-			http.Error(w, fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", version, api.APIVERSION).Error(), http.StatusBadRequest)
+		if version.GreaterThan(api.Version) {
+			http.Error(w, fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", version, api.Version).Error(), http.StatusBadRequest)
+			return
+		}
+		if version.LessThan(api.MinVersion) {
+			http.Error(w, fmt.Errorf("client is too old, minimum supported API version is %s, please upgrade your client to a newer version", api.MinVersion).Error(), http.StatusBadRequest)
 			return
 		}
 

+ 33 - 2
integration-cli/docker_api_test.go

@@ -3,15 +3,18 @@ package main
 import (
 	"net/http"
 	"net/http/httputil"
+	"strconv"
+	"strings"
 	"time"
 
+	"github.com/docker/docker/api"
 	"github.com/go-check/check"
 )
 
 func (s *DockerSuite) TestApiOptionsRoute(c *check.C) {
 	status, _, err := sockRequest("OPTIONS", "/", nil)
-	c.Assert(status, check.Equals, http.StatusOK)
 	c.Assert(err, check.IsNil)
+	c.Assert(status, check.Equals, http.StatusOK)
 }
 
 func (s *DockerSuite) TestApiGetEnabledCors(c *check.C) {
@@ -26,7 +29,7 @@ func (s *DockerSuite) TestApiGetEnabledCors(c *check.C) {
 	//c.Assert(res.Header.Get("Access-Control-Allow-Headers"), check.Equals, "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
 }
 
-func (s *DockerSuite) TestVersionStatusCode(c *check.C) {
+func (s *DockerSuite) TestApiVersionStatusCode(c *check.C) {
 	conn, err := sockConn(time.Duration(10 * time.Second))
 	c.Assert(err, check.IsNil)
 
@@ -40,3 +43,31 @@ func (s *DockerSuite) TestVersionStatusCode(c *check.C) {
 	res, err := client.Do(req)
 	c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest)
 }
+
+func (s *DockerSuite) TestApiClientVersionNewerThanServer(c *check.C) {
+	v := strings.Split(string(api.Version), ".")
+	vMinInt, err := strconv.Atoi(v[1])
+	c.Assert(err, check.IsNil)
+	vMinInt++
+	v[1] = strconv.Itoa(vMinInt)
+	version := strings.Join(v, ".")
+
+	status, body, err := sockRequest("GET", "/v"+version+"/version", nil)
+	c.Assert(err, check.IsNil)
+	c.Assert(status, check.Equals, http.StatusBadRequest)
+	c.Assert(len(string(body)), check.Not(check.Equals), 0) // Expected not empty body
+}
+
+func (s *DockerSuite) TestApiClientVersionOldNotSupported(c *check.C) {
+	v := strings.Split(string(api.MinVersion), ".")
+	vMinInt, err := strconv.Atoi(v[1])
+	c.Assert(err, check.IsNil)
+	vMinInt--
+	v[1] = strconv.Itoa(vMinInt)
+	version := strings.Join(v, ".")
+
+	status, body, err := sockRequest("GET", "/v"+version+"/version", nil)
+	c.Assert(err, check.IsNil)
+	c.Assert(status, check.Equals, http.StatusBadRequest)
+	c.Assert(len(string(body)), check.Not(check.Equals), 0) // Expected not empty body
+}