client: improve GoDoc, and minor touch-ups
- Improve documentation of various functions to better describe their behavior. - Rename some variables to be more descriptive (as this is client code, used by external consumers, it's nice to be a bit more explicit). - Remove a redundant check in `WithVersionFromEnv()`, as `WithVersion()` already checks for empty values. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
eb9e42a09e
commit
c2c7e9d449
4 changed files with 96 additions and 55 deletions
109
client/client.go
109
client/client.go
|
@ -43,7 +43,6 @@ package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -93,15 +92,18 @@ type Client struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckRedirect specifies the policy for dealing with redirect responses:
|
// CheckRedirect specifies the policy for dealing with redirect responses:
|
||||||
// If the request is non-GET return `ErrRedirect`. Otherwise use the last response.
|
// If the request is non-GET return ErrRedirect, otherwise use the last response.
|
||||||
//
|
//
|
||||||
// Go 1.8 changes behavior for HTTP redirects (specifically 301, 307, and 308) in the client .
|
// Go 1.8 changes behavior for HTTP redirects (specifically 301, 307, and 308)
|
||||||
// The Docker client (and by extension docker API client) can be made to send a request
|
// in the client. The Docker client (and by extension docker API client) can be
|
||||||
// like POST /containers//start where what would normally be in the name section of the URL is empty.
|
// made to send a request like POST /containers//start where what would normally
|
||||||
// This triggers an HTTP 301 from the daemon.
|
// be in the name section of the URL is empty. This triggers an HTTP 301 from
|
||||||
// In go 1.8 this 301 will be converted to a GET request, and ends up getting a 404 from the daemon.
|
// the daemon.
|
||||||
// This behavior change manifests in the client in that before the 301 was not followed and
|
//
|
||||||
// the client did not generate an error, but now results in a message like Error response from daemon: page not found.
|
// In go 1.8 this 301 will be converted to a GET request, and ends up getting
|
||||||
|
// a 404 from the daemon. This behavior change manifests in the client in that
|
||||||
|
// before, the 301 was not followed and the client did not generate an error,
|
||||||
|
// but now results in a message like Error response from daemon: page not found.
|
||||||
func CheckRedirect(req *http.Request, via []*http.Request) error {
|
func CheckRedirect(req *http.Request, via []*http.Request) error {
|
||||||
if via[0].Method == http.MethodGet {
|
if via[0].Method == http.MethodGet {
|
||||||
return http.ErrUseLastResponse
|
return http.ErrUseLastResponse
|
||||||
|
@ -109,13 +111,22 @@ func CheckRedirect(req *http.Request, via []*http.Request) error {
|
||||||
return ErrRedirect
|
return ErrRedirect
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClientWithOpts initializes a new API client with default values. It takes functors
|
// NewClientWithOpts initializes a new API client with a default HTTPClient, and
|
||||||
// to modify values when creating it, like `NewClientWithOpts(WithVersion(…))`
|
// default API host and version. It also initializes the custom HTTP headers to
|
||||||
// It also initializes the custom http headers to add to each request.
|
// add to each request.
|
||||||
|
//
|
||||||
|
// It takes an optional list of Opt functional arguments, which are applied in
|
||||||
|
// the order they're provided, which allows modifying the defaults when creating
|
||||||
|
// the client. For example, the following initializes a client that configures
|
||||||
|
// itself with values from environment variables (client.FromEnv), and has
|
||||||
|
// automatic API version negotiation enabled (client.WithAPIVersionNegotiation()).
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// cli, err := client.NewClientWithOpts(
|
||||||
|
// client.FromEnv,
|
||||||
|
// client.WithAPIVersionNegotiation(),
|
||||||
|
// )
|
||||||
//
|
//
|
||||||
// It won't send any version information if the version number is empty. It is
|
|
||||||
// highly recommended that you set a version or your client may break if the
|
|
||||||
// server is upgraded.
|
|
||||||
func NewClientWithOpts(ops ...Opt) (*Client, error) {
|
func NewClientWithOpts(ops ...Opt) (*Client, error) {
|
||||||
client, err := defaultHTTPClient(DefaultDockerHost)
|
client, err := defaultHTTPClient(DefaultDockerHost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -153,12 +164,12 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultHTTPClient(host string) (*http.Client, error) {
|
func defaultHTTPClient(host string) (*http.Client, error) {
|
||||||
url, err := ParseHostURL(host)
|
hostURL, err := ParseHostURL(host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
transport := new(http.Transport)
|
transport := &http.Transport{}
|
||||||
sockets.ConfigureTransport(transport, url.Scheme, url.Host)
|
_ = sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host)
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
CheckRedirect: CheckRedirect,
|
CheckRedirect: CheckRedirect,
|
||||||
|
@ -194,11 +205,21 @@ func (cli *Client) ClientVersion() string {
|
||||||
return cli.version
|
return cli.version
|
||||||
}
|
}
|
||||||
|
|
||||||
// NegotiateAPIVersion queries the API and updates the version to match the
|
// NegotiateAPIVersion queries the API and updates the version to match the API
|
||||||
// API version. Any errors are silently ignored. If a manual override is in place,
|
// version. NegotiateAPIVersion downgrades the client's API version to match the
|
||||||
// either through the `DOCKER_API_VERSION` environment variable, or if the client
|
// APIVersion if the ping version is lower than the default version. If the API
|
||||||
// was initialized with a fixed version (`opts.WithVersion(xx)`), no negotiation
|
// version reported by the server is higher than the maximum version supported
|
||||||
// will be performed.
|
// by the client, it uses the client's maximum version.
|
||||||
|
//
|
||||||
|
// If a manual override is in place, either through the "DOCKER_API_VERSION"
|
||||||
|
// environment variable, or if the client is initialized
|
||||||
|
// with a fixed version (WithVersion(xx)), no negotiation is performed.
|
||||||
|
//
|
||||||
|
// If the API server's ping response does not contain an API version, or if the
|
||||||
|
// client did not get a successful ping response, it assumes it is connected with
|
||||||
|
// an old daemon that does not support API version negotiation, in which case it
|
||||||
|
// downgrades to the latest version of the API before version negotiation was
|
||||||
|
// added (1.24).
|
||||||
func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
|
func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
|
||||||
if !cli.manualOverride {
|
if !cli.manualOverride {
|
||||||
ping, _ := cli.Ping(ctx)
|
ping, _ := cli.Ping(ctx)
|
||||||
|
@ -206,23 +227,31 @@ func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NegotiateAPIVersionPing updates the client version to match the Ping.APIVersion
|
// NegotiateAPIVersionPing downgrades the client's API version to match the
|
||||||
// if the ping version is less than the default version. If a manual override is
|
// APIVersion in the ping response. If the API version in pingResponse is higher
|
||||||
// in place, either through the `DOCKER_API_VERSION` environment variable, or if
|
// than the maximum version supported by the client, it uses the client's maximum
|
||||||
// the client was initialized with a fixed version (`opts.WithVersion(xx)`), no
|
// version.
|
||||||
// negotiation is performed.
|
//
|
||||||
func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
|
// If a manual override is in place, either through the "DOCKER_API_VERSION"
|
||||||
|
// environment variable, or if the client is initialized
|
||||||
|
// with a fixed version (WithVersion(xx)), no negotiation is performed.
|
||||||
|
//
|
||||||
|
// If the API server's ping response does not contain an API version, we assume
|
||||||
|
// we are connected with an old daemon without API version negotiation support,
|
||||||
|
// and downgrade to the latest version of the API before version negotiation was
|
||||||
|
// added (1.24).
|
||||||
|
func (cli *Client) NegotiateAPIVersionPing(pingResponse types.Ping) {
|
||||||
if !cli.manualOverride {
|
if !cli.manualOverride {
|
||||||
cli.negotiateAPIVersionPing(p)
|
cli.negotiateAPIVersionPing(pingResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// negotiateAPIVersionPing queries the API and updates the version to match the
|
// negotiateAPIVersionPing queries the API and updates the version to match the
|
||||||
// API version. Any errors are silently ignored.
|
// API version from the ping response.
|
||||||
func (cli *Client) negotiateAPIVersionPing(p types.Ping) {
|
func (cli *Client) negotiateAPIVersionPing(pingResponse types.Ping) {
|
||||||
// try the latest version before versioning headers existed
|
// default to the latest version before versioning headers existed
|
||||||
if p.APIVersion == "" {
|
if pingResponse.APIVersion == "" {
|
||||||
p.APIVersion = "1.24"
|
pingResponse.APIVersion = "1.24"
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the client is not initialized with a version, start with the latest supported version
|
// if the client is not initialized with a version, start with the latest supported version
|
||||||
|
@ -231,8 +260,8 @@ func (cli *Client) negotiateAPIVersionPing(p types.Ping) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if server version is lower than the client version, downgrade
|
// if server version is lower than the client version, downgrade
|
||||||
if versions.LessThan(p.APIVersion, cli.version) {
|
if versions.LessThan(pingResponse.APIVersion, cli.version) {
|
||||||
cli.version = p.APIVersion
|
cli.version = pingResponse.APIVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the results, so that automatic API version negotiation (if enabled)
|
// Store the results, so that automatic API version negotiation (if enabled)
|
||||||
|
@ -258,7 +287,7 @@ func (cli *Client) HTTPClient() *http.Client {
|
||||||
func ParseHostURL(host string) (*url.URL, error) {
|
func ParseHostURL(host string) (*url.URL, error) {
|
||||||
protoAddrParts := strings.SplitN(host, "://", 2)
|
protoAddrParts := strings.SplitN(host, "://", 2)
|
||||||
if len(protoAddrParts) == 1 {
|
if len(protoAddrParts) == 1 {
|
||||||
return nil, fmt.Errorf("unable to parse docker host `%s`", host)
|
return nil, errors.Errorf("unable to parse docker host `%s`", host)
|
||||||
}
|
}
|
||||||
|
|
||||||
var basePath string
|
var basePath string
|
||||||
|
@ -278,7 +307,9 @@ func ParseHostURL(host string) (*url.URL, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dialer returns a dialer for a raw stream connection, with HTTP/1.1 header, that can be used for proxying the daemon connection.
|
// Dialer returns a dialer for a raw stream connection, with an HTTP/1.1 header,
|
||||||
|
// that can be used for proxying the daemon connection.
|
||||||
|
//
|
||||||
// Used by `docker dial-stdio` (docker/cli#889).
|
// Used by `docker dial-stdio` (docker/cli#889).
|
||||||
func (cli *Client) Dialer() func(context.Context) (net.Conn, error) {
|
func (cli *Client) Dialer() func(context.Context) (net.Conn, error) {
|
||||||
return func(ctx context.Context) (net.Conn, error) {
|
return func(ctx context.Context) (net.Conn, error) {
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
// DefaultDockerHost defines os specific default if DOCKER_HOST is unset
|
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
|
||||||
|
// environment variable is unset or empty.
|
||||||
const DefaultDockerHost = "unix:///var/run/docker.sock"
|
const DefaultDockerHost = "unix:///var/run/docker.sock"
|
||||||
|
|
||||||
const defaultProto = "unix"
|
const defaultProto = "unix"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
// DefaultDockerHost defines os specific default if DOCKER_HOST is unset
|
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
|
||||||
|
// environment variable is unset or empty.
|
||||||
const DefaultDockerHost = "npipe:////./pipe/docker_engine"
|
const DefaultDockerHost = "npipe:////./pipe/docker_engine"
|
||||||
|
|
||||||
const defaultProto = "npipe"
|
const defaultProto = "npipe"
|
||||||
|
|
|
@ -18,11 +18,18 @@ type Opt func(*Client) error
|
||||||
|
|
||||||
// FromEnv configures the client with values from environment variables.
|
// FromEnv configures the client with values from environment variables.
|
||||||
//
|
//
|
||||||
// Supported environment variables:
|
// FromEnv uses the following environment variables:
|
||||||
// DOCKER_HOST to set the url to the docker server.
|
//
|
||||||
// DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
|
// DOCKER_HOST to set the URL to the docker server.
|
||||||
// DOCKER_CERT_PATH to load the TLS certificates from.
|
//
|
||||||
// DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
|
// DOCKER_API_VERSION to set the version of the API to
|
||||||
|
// use, leave empty for latest.
|
||||||
|
//
|
||||||
|
// DOCKER_CERT_PATH to specify the directory from which to
|
||||||
|
// load the TLS certificates (ca.pem, cert.pem, key.pem).
|
||||||
|
//
|
||||||
|
// DOCKER_TLS_VERIFY to enable or disable TLS verification (off by
|
||||||
|
// default).
|
||||||
func FromEnv(c *Client) error {
|
func FromEnv(c *Client) error {
|
||||||
ops := []Opt{
|
ops := []Opt{
|
||||||
WithTLSClientConfigFromEnv(),
|
WithTLSClientConfigFromEnv(),
|
||||||
|
@ -75,8 +82,8 @@ func WithHost(host string) Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithHostFromEnv overrides the client host with the host specified in the
|
// WithHostFromEnv overrides the client host with the host specified in the
|
||||||
// DOCKER_HOST environment variable. If DOCKER_HOST is not set, the host is
|
// DOCKER_HOST environment variable. If DOCKER_HOST is not set,
|
||||||
// not modified.
|
// or set to an empty value, the host is not modified.
|
||||||
func WithHostFromEnv() Opt {
|
func WithHostFromEnv() Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if host := os.Getenv("DOCKER_HOST"); host != "" {
|
if host := os.Getenv("DOCKER_HOST"); host != "" {
|
||||||
|
@ -145,9 +152,13 @@ func WithTLSClientConfig(cacertPath, certPath, keyPath string) Opt {
|
||||||
// settings in the DOCKER_CERT_PATH and DOCKER_TLS_VERIFY environment variables.
|
// settings in the DOCKER_CERT_PATH and DOCKER_TLS_VERIFY environment variables.
|
||||||
// If DOCKER_CERT_PATH is not set or empty, TLS configuration is not modified.
|
// If DOCKER_CERT_PATH is not set or empty, TLS configuration is not modified.
|
||||||
//
|
//
|
||||||
// Supported environment variables:
|
// WithTLSClientConfigFromEnv uses the following environment variables:
|
||||||
// DOCKER_CERT_PATH directory to load the TLS certificates (ca.pem, cert.pem, key.pem) from.
|
//
|
||||||
// DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
|
// DOCKER_CERT_PATH to specify the directory from which to
|
||||||
|
// load the TLS certificates (ca.pem, cert.pem, key.pem).
|
||||||
|
//
|
||||||
|
// DOCKER_TLS_VERIFY to enable or disable TLS verification (off by
|
||||||
|
// default).
|
||||||
func WithTLSClientConfigFromEnv() Opt {
|
func WithTLSClientConfigFromEnv() Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
dockerCertPath := os.Getenv("DOCKER_CERT_PATH")
|
dockerCertPath := os.Getenv("DOCKER_CERT_PATH")
|
||||||
|
@ -190,10 +201,7 @@ func WithVersion(version string) Opt {
|
||||||
// the version is not modified.
|
// the version is not modified.
|
||||||
func WithVersionFromEnv() Opt {
|
func WithVersionFromEnv() Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if version := os.Getenv("DOCKER_API_VERSION"); version != "" {
|
return WithVersion(os.Getenv("DOCKER_API_VERSION"))(c)
|
||||||
return WithVersion(version)(c)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue