Browse Source

Force API versioning in the client library.

Remove dependencies on docker's version packages.
Allow empty version as a fallback to latest version.

Signed-off-by: David Calavera <david.calavera@gmail.com>
David Calavera 9 years ago
parent
commit
b679eb9a82
3 changed files with 50 additions and 17 deletions
  1. 2 1
      api/client/cli.go
  2. 12 16
      api/client/lib/client.go
  3. 36 0
      api/client/lib/client_test.go

+ 2 - 1
api/client/cli.go

@@ -7,6 +7,7 @@ import (
 	"os"
 	"runtime"
 
+	"github.com/docker/docker/api"
 	"github.com/docker/docker/api/client/lib"
 	"github.com/docker/docker/cli"
 	"github.com/docker/docker/cliconfig"
@@ -102,7 +103,7 @@ 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, clientFlags.Common.TLSOptions, customHeaders)
+		client, err := lib.NewClient(host, string(api.Version), clientFlags.Common.TLSOptions, customHeaders)
 		if err != nil {
 			return err
 		}

+ 12 - 16
api/client/lib/client.go

@@ -7,10 +7,8 @@ import (
 	"net/url"
 	"strings"
 
-	"github.com/docker/docker/api"
 	"github.com/docker/docker/pkg/sockets"
 	"github.com/docker/docker/pkg/tlsconfig"
-	"github.com/docker/docker/pkg/version"
 )
 
 // Client is the API client that performs all operations
@@ -29,24 +27,16 @@ type Client struct {
 	// httpClient holds the client transport instance. Exported to keep the old code running.
 	httpClient *http.Client
 	// version of the server to talk to.
-	version version.Version
+	version string
 	// custom http headers configured by users
 	customHTTPHeaders map[string]string
 }
 
-// NewClient initializes a new API client
-// for the given host. It uses the tlsOptions
-// to decide whether to use a secure connection or not.
+// NewClient initializes a new API client for the given host and API version.
+// It won't send any version information if the version number is empty.
+// It uses the tlsOptions to decide whether to use a secure connection or not.
 // It also initializes the custom http headers to add to each request.
-func NewClient(host string, tlsOptions *tlsconfig.Options, httpHeaders map[string]string) (*Client, error) {
-	return NewClientWithVersion(host, api.Version, tlsOptions, httpHeaders)
-}
-
-// NewClientWithVersion initializes a new API client
-// for the given host and API version. It uses the tlsOptions
-// to decide whether to use a secure connection or not.
-// It also initializes the custom http headers to add to each request.
-func NewClientWithVersion(host string, version version.Version, tlsOptions *tlsconfig.Options, httpHeaders map[string]string) (*Client, error) {
+func NewClient(host string, version string, tlsOptions *tlsconfig.Options, httpHeaders map[string]string) (*Client, error) {
 	var (
 		basePath       string
 		tlsConfig      *tls.Config
@@ -94,7 +84,13 @@ func NewClientWithVersion(host string, version version.Version, tlsOptions *tlsc
 // getAPIPath returns the versioned request path to call the api.
 // It appends the query parameters to the path if they are not empty.
 func (cli *Client) getAPIPath(p string, query url.Values) string {
-	apiPath := fmt.Sprintf("%s/v%s%s", cli.basePath, cli.version, p)
+	var apiPath string
+	if cli.version != "" {
+		v := strings.TrimPrefix(cli.version, "v")
+		apiPath = fmt.Sprintf("%s/v%s%s", cli.basePath, v, p)
+	} else {
+		apiPath = fmt.Sprintf("%s%s", cli.basePath, p)
+	}
 	if len(query) > 0 {
 		apiPath += "?" + query.Encode()
 	}

+ 36 - 0
api/client/lib/client_test.go

@@ -0,0 +1,36 @@
+package lib
+
+import (
+	"net/url"
+	"testing"
+)
+
+func TestGetAPIPath(t *testing.T) {
+	cases := []struct {
+		v string
+		p string
+		q url.Values
+		e string
+	}{
+		{"", "/containers/json", nil, "/containers/json"},
+		{"", "/containers/json", url.Values{}, "/containers/json"},
+		{"", "/containers/json", url.Values{"s": []string{"c"}}, "/containers/json?s=c"},
+		{"1.22", "/containers/json", nil, "/v1.22/containers/json"},
+		{"1.22", "/containers/json", url.Values{}, "/v1.22/containers/json"},
+		{"1.22", "/containers/json", url.Values{"s": []string{"c"}}, "/v1.22/containers/json?s=c"},
+		{"v1.22", "/containers/json", nil, "/v1.22/containers/json"},
+		{"v1.22", "/containers/json", url.Values{}, "/v1.22/containers/json"},
+		{"v1.22", "/containers/json", url.Values{"s": []string{"c"}}, "/v1.22/containers/json?s=c"},
+	}
+
+	for _, cs := range cases {
+		c, err := NewClient("unix:///var/run/docker.sock", cs.v, nil, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		g := c.getAPIPath(cs.p, cs.q)
+		if g != cs.e {
+			t.Fatalf("Expected %s, got %s", cs.e, g)
+		}
+	}
+}