Selaa lähdekoodia

Merge pull request #45923 from thaJeztah/client_header

client: remove custom "headers" type (use http.Header), and omit "version" header on API >= 1.30
Bjorn Neergaard 2 vuotta sitten
vanhempi
commit
ebcb230cff

+ 3 - 3
client/container_attach.go

@@ -2,6 +2,7 @@ package client // import "github.com/docker/docker/client"
 
 import (
 	"context"
+	"net/http"
 	"net/url"
 
 	"github.com/docker/docker/api/types"
@@ -52,8 +53,7 @@ func (cli *Client) ContainerAttach(ctx context.Context, container string, option
 		query.Set("logs", "1")
 	}
 
-	headers := map[string][]string{
+	return cli.postHijacked(ctx, "/containers/"+container+"/attach", query, nil, http.Header{
 		"Content-Type": {"text/plain"},
-	}
-	return cli.postHijacked(ctx, "/containers/"+container+"/attach", query, nil, headers)
+	})
 }

+ 3 - 3
client/container_exec.go

@@ -3,6 +3,7 @@ package client // import "github.com/docker/docker/client"
 import (
 	"context"
 	"encoding/json"
+	"net/http"
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/versions"
@@ -46,10 +47,9 @@ func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, confi
 	if versions.LessThan(cli.ClientVersion(), "1.42") {
 		config.ConsoleSize = nil
 	}
-	headers := map[string][]string{
+	return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, http.Header{
 		"Content-Type": {"application/json"},
-	}
-	return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, headers)
+	})
 }
 
 // ContainerExecInspect returns information about a specific exec process on the docker host.

+ 3 - 2
client/distribution_inspect.go

@@ -3,6 +3,7 @@ package client // import "github.com/docker/docker/client"
 import (
 	"context"
 	"encoding/json"
+	"net/http"
 	"net/url"
 
 	"github.com/docker/docker/api/types/registry"
@@ -19,10 +20,10 @@ func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegist
 	if err := cli.NewVersionError("1.30", "distribution inspect"); err != nil {
 		return distributionInspect, err
 	}
-	var headers map[string][]string
 
+	var headers http.Header
 	if encodedRegistryAuth != "" {
-		headers = map[string][]string{
+		headers = http.Header{
 			registry.AuthHeader: {encodedRegistryAuth},
 		}
 	}

+ 3 - 5
client/image_build.go

@@ -23,13 +23,13 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio
 		return types.ImageBuildResponse{}, err
 	}
 
-	headers := http.Header(make(map[string][]string))
 	buf, err := json.Marshal(options.AuthConfigs)
 	if err != nil {
 		return types.ImageBuildResponse{}, err
 	}
-	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
 
+	headers := http.Header{}
+	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
 	headers.Set("Content-Type", "application/x-tar")
 
 	serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers)
@@ -37,11 +37,9 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio
 		return types.ImageBuildResponse{}, err
 	}
 
-	osType := getDockerOS(serverResp.header.Get("Server"))
-
 	return types.ImageBuildResponse{
 		Body:   serverResp.body,
-		OSType: osType,
+		OSType: getDockerOS(serverResp.header.Get("Server")),
 	}, nil
 }
 

+ 4 - 2
client/image_create.go

@@ -3,6 +3,7 @@ package client // import "github.com/docker/docker/client"
 import (
 	"context"
 	"io"
+	"net/http"
 	"net/url"
 	"strings"
 
@@ -33,6 +34,7 @@ func (cli *Client) ImageCreate(ctx context.Context, parentReference string, opti
 }
 
 func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
-	return cli.post(ctx, "/images/create", query, nil, headers)
+	return cli.post(ctx, "/images/create", query, nil, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
 }

+ 4 - 2
client/image_load.go

@@ -3,6 +3,7 @@ package client // import "github.com/docker/docker/client"
 import (
 	"context"
 	"io"
+	"net/http"
 	"net/url"
 
 	"github.com/docker/docker/api/types"
@@ -17,8 +18,9 @@ func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (
 	if quiet {
 		v.Set("quiet", "1")
 	}
-	headers := map[string][]string{"Content-Type": {"application/x-tar"}}
-	resp, err := cli.postRaw(ctx, "/images/load", v, input, headers)
+	resp, err := cli.postRaw(ctx, "/images/load", v, input, http.Header{
+		"Content-Type": {"application/x-tar"},
+	})
 	if err != nil {
 		return types.ImageLoadResponse{}, err
 	}

+ 4 - 2
client/image_push.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"errors"
 	"io"
+	"net/http"
 	"net/url"
 
 	"github.com/docker/distribution/reference"
@@ -50,6 +51,7 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options types.Im
 }
 
 func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
-	return cli.post(ctx, "/images/"+imageID+"/push", query, nil, headers)
+	return cli.post(ctx, "/images/"+imageID+"/push", query, nil, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
 }

+ 4 - 2
client/image_search.go

@@ -3,6 +3,7 @@ package client // import "github.com/docker/docker/client"
 import (
 	"context"
 	"encoding/json"
+	"net/http"
 	"net/url"
 	"strconv"
 
@@ -48,6 +49,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
 }
 
 func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
-	return cli.get(ctx, "/images/search", query, headers)
+	return cli.get(ctx, "/images/search", query, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
 }

+ 7 - 4
client/plugin_install.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"io"
+	"net/http"
 	"net/url"
 
 	"github.com/docker/distribution/reference"
@@ -68,13 +69,15 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
 }
 
 func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
-	return cli.get(ctx, "/plugins/privileges", query, headers)
+	return cli.get(ctx, "/plugins/privileges", query, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
 }
 
 func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
-	return cli.post(ctx, "/plugins/pull", query, privileges, headers)
+	return cli.post(ctx, "/plugins/pull", query, privileges, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
 }
 
 func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options types.PluginInstallOptions) (types.PluginPrivileges, error) {

+ 4 - 2
client/plugin_push.go

@@ -3,14 +3,16 @@ package client // import "github.com/docker/docker/client"
 import (
 	"context"
 	"io"
+	"net/http"
 
 	"github.com/docker/docker/api/types/registry"
 )
 
 // PluginPush pushes a plugin to a registry
 func (cli *Client) PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error) {
-	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
-	resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, headers)
+	resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
 	if err != nil {
 		return nil, err
 	}

+ 4 - 2
client/plugin_upgrade.go

@@ -3,6 +3,7 @@ package client // import "github.com/docker/docker/client"
 import (
 	"context"
 	"io"
+	"net/http"
 	"net/url"
 
 	"github.com/docker/distribution/reference"
@@ -35,6 +36,7 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options types
 }
 
 func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
-	return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, headers)
+	return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
 }

+ 16 - 18
client/request.go

@@ -28,17 +28,17 @@ type serverResponse struct {
 }
 
 // head sends an http request to the docker API using the method HEAD.
-func (cli *Client) head(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) {
+func (cli *Client) head(ctx context.Context, path string, query url.Values, headers http.Header) (serverResponse, error) {
 	return cli.sendRequest(ctx, http.MethodHead, path, query, nil, headers)
 }
 
 // get sends an http request to the docker API using the method GET with a specific Go context.
-func (cli *Client) get(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) {
+func (cli *Client) get(ctx context.Context, path string, query url.Values, headers http.Header) (serverResponse, error) {
 	return cli.sendRequest(ctx, http.MethodGet, path, query, nil, headers)
 }
 
 // post sends an http request to the docker API using the method POST with a specific Go context.
-func (cli *Client) post(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
+func (cli *Client) post(ctx context.Context, path string, query url.Values, obj interface{}, headers http.Header) (serverResponse, error) {
 	body, headers, err := encodeBody(obj, headers)
 	if err != nil {
 		return serverResponse{}, err
@@ -46,11 +46,11 @@ func (cli *Client) post(ctx context.Context, path string, query url.Values, obj
 	return cli.sendRequest(ctx, http.MethodPost, path, query, body, headers)
 }
 
-func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
+func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers http.Header) (serverResponse, error) {
 	return cli.sendRequest(ctx, http.MethodPost, path, query, body, headers)
 }
 
-func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers map[string][]string) (serverResponse, error) {
+func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers http.Header) (serverResponse, error) {
 	body, headers, err := encodeBody(obj, headers)
 	if err != nil {
 		return serverResponse{}, err
@@ -59,7 +59,7 @@ func (cli *Client) put(ctx context.Context, path string, query url.Values, obj i
 }
 
 // putRaw sends an http request to the docker API using the method PUT.
-func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (serverResponse, error) {
+func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers http.Header) (serverResponse, error) {
 	// PUT requests are expected to always have a body (apparently)
 	// so explicitly pass an empty body to sendRequest to signal that
 	// it should set the Content-Type header if not already present.
@@ -70,13 +70,11 @@ func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, bo
 }
 
 // delete sends an http request to the docker API using the method DELETE.
-func (cli *Client) delete(ctx context.Context, path string, query url.Values, headers map[string][]string) (serverResponse, error) {
+func (cli *Client) delete(ctx context.Context, path string, query url.Values, headers http.Header) (serverResponse, error) {
 	return cli.sendRequest(ctx, http.MethodDelete, path, query, nil, headers)
 }
 
-type headers map[string][]string
-
-func encodeBody(obj interface{}, headers headers) (io.Reader, headers, error) {
+func encodeBody(obj interface{}, headers http.Header) (io.Reader, http.Header, error) {
 	if obj == nil {
 		return nil, headers, nil
 	}
@@ -98,7 +96,7 @@ func encodeBody(obj interface{}, headers headers) (io.Reader, headers, error) {
 	return body, headers, nil
 }
 
-func (cli *Client) buildRequest(method, path string, body io.Reader, headers headers) (*http.Request, error) {
+func (cli *Client) buildRequest(method, path string, body io.Reader, headers http.Header) (*http.Request, error) {
 	req, err := http.NewRequest(method, path, body)
 	if err != nil {
 		return nil, err
@@ -123,7 +121,7 @@ func (cli *Client) buildRequest(method, path string, body io.Reader, headers hea
 	return req, nil
 }
 
-func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers headers) (serverResponse, error) {
+func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers http.Header) (serverResponse, error) {
 	req, err := cli.buildRequest(method, cli.getAPIPath(ctx, path, query), body, headers)
 	if err != nil {
 		return serverResponse{}, err
@@ -161,19 +159,19 @@ func (cli *Client) doRequest(ctx context.Context, req *http.Request) (serverResp
 			return serverResp, err
 		}
 
-		if nErr, ok := err.(*url.Error); ok {
-			if nErr, ok := nErr.Err.(*net.OpError); ok {
+		if uErr, ok := err.(*url.Error); ok {
+			if nErr, ok := uErr.Err.(*net.OpError); ok {
 				if os.IsPermission(nErr.Err) {
 					return serverResp, errors.Wrapf(err, "permission denied while trying to connect to the Docker daemon socket at %v", cli.host)
 				}
 			}
 		}
 
-		if err, ok := err.(net.Error); ok {
-			if err.Timeout() {
+		if nErr, ok := err.(net.Error); ok {
+			if nErr.Timeout() {
 				return serverResp, ErrorConnectionFailed(cli.host)
 			}
-			if strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") {
+			if strings.Contains(nErr.Error(), "connection refused") || strings.Contains(nErr.Error(), "dial unix") {
 				return serverResp, ErrorConnectionFailed(cli.host)
 			}
 		}
@@ -253,7 +251,7 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error {
 	return errors.Wrap(errors.New(errorMessage), "Error response from daemon")
 }
 
-func (cli *Client) addHeaders(req *http.Request, headers headers) *http.Request {
+func (cli *Client) addHeaders(req *http.Request, headers http.Header) *http.Request {
 	// Add CLI Config's HTTP Headers BEFORE we set the Docker headers
 	// then the user can't change OUR headers
 	for k, v := range cli.customHTTPHeaders {

+ 12 - 7
client/service_create.go

@@ -4,12 +4,14 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"net/http"
 	"strings"
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/api/types/versions"
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 )
@@ -17,13 +19,6 @@ import (
 // ServiceCreate creates a new service.
 func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options types.ServiceCreateOptions) (types.ServiceCreateResponse, error) {
 	var response types.ServiceCreateResponse
-	headers := map[string][]string{
-		"version": {cli.version},
-	}
-
-	if options.EncodedRegistryAuth != "" {
-		headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
-	}
 
 	// Make sure containerSpec is not nil when no runtime is set or the runtime is set to container
 	if service.TaskTemplate.ContainerSpec == nil && (service.TaskTemplate.Runtime == "" || service.TaskTemplate.Runtime == swarm.RuntimeContainer) {
@@ -53,6 +48,16 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
 		}
 	}
 
+	headers := http.Header{}
+	if versions.LessThan(cli.version, "1.30") {
+		// the custom "version" header was used by engine API before 20.10
+		// (API 1.30) to switch between client- and server-side lookup of
+		// image digests.
+		headers["version"] = []string{cli.version}
+	}
+	if options.EncodedRegistryAuth != "" {
+		headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
+	}
 	resp, err := cli.post(ctx, "/services/create", nil, service, headers)
 	defer ensureReaderClosed(resp)
 	if err != nil {

+ 12 - 8
client/service_update.go

@@ -3,11 +3,13 @@ package client // import "github.com/docker/docker/client"
 import (
 	"context"
 	"encoding/json"
+	"net/http"
 	"net/url"
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/api/types/versions"
 )
 
 // ServiceUpdate updates a Service. The version number is required to avoid conflicting writes.
@@ -19,14 +21,6 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
 		response = types.ServiceUpdateResponse{}
 	)
 
-	headers := map[string][]string{
-		"version": {cli.version},
-	}
-
-	if options.EncodedRegistryAuth != "" {
-		headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
-	}
-
 	if options.RegistryAuthFrom != "" {
 		query.Set("registryAuthFrom", options.RegistryAuthFrom)
 	}
@@ -60,6 +54,16 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
 		}
 	}
 
+	headers := http.Header{}
+	if versions.LessThan(cli.version, "1.30") {
+		// the custom "version" header was used by engine API before 20.10
+		// (API 1.30) to switch between client- and server-side lookup of
+		// image digests.
+		headers["version"] = []string{cli.version}
+	}
+	if options.EncodedRegistryAuth != "" {
+		headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
+	}
 	resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers)
 	defer ensureReaderClosed(resp)
 	if err != nil {