mirror of
https://github.com/moby/moby.git
synced 2026-01-11 10:41:43 +00:00
client: enable API-version negotiation by default
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
@@ -27,7 +27,7 @@ func main() {
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -8,10 +8,8 @@ https://docs.docker.com/reference/api/engine/
|
||||
|
||||
You use the library by constructing a client object using [New]
|
||||
and calling methods on it. The client can be configured from environment
|
||||
variables by passing the [FromEnv] option, and the [WithAPIVersionNegotiation]
|
||||
option to allow downgrading the API version used when connecting with an older
|
||||
daemon version. Other options can be configured manually by passing any of
|
||||
the available [Opt] options.
|
||||
variables by passing the [FromEnv] option. Other options can be configured
|
||||
manually by passing any of the available [Opt] options.
|
||||
|
||||
For example, to list running containers (the equivalent of "docker ps"):
|
||||
|
||||
@@ -30,7 +28,7 @@ For example, to list running containers (the equivalent of "docker ps"):
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -103,9 +101,9 @@ import (
|
||||
const DummyHost = "api.moby.localhost"
|
||||
|
||||
// MaxAPIVersion is the highest REST API version supported by the client.
|
||||
// If API-version negotiation is enabled (see [WithAPIVersionNegotiation],
|
||||
// the client may downgrade its API version. Similarly, the [WithAPIVersion]
|
||||
// and [WithAPIVersionFromEnv] options allow overriding the version.
|
||||
// If API-version negotiation is enabled, the client may downgrade its API version.
|
||||
// Similarly, the [WithAPIVersion] and [WithAPIVersionFromEnv] options allow
|
||||
// overriding the version and disable API-version negotiation.
|
||||
//
|
||||
// This version may be lower than the version of the api library module used.
|
||||
const MaxAPIVersion = "1.52"
|
||||
@@ -172,8 +170,13 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
|
||||
// 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 ([FromEnv]), and has automatic
|
||||
// API version negotiation enabled ([WithAPIVersionNegotiation]).
|
||||
// itself with values from environment variables ([FromEnv]).
|
||||
//
|
||||
// By default, the client automatically negotiates the API version to use when
|
||||
// making requests. API version negotiation is performed on the first request;
|
||||
// subsequent requests do not re-negotiate. Use [WithAPIVersion] or
|
||||
// [WithAPIVersionFromEnv] to configure the client with a fixed API version
|
||||
// and disable API version negotiation.
|
||||
//
|
||||
// cli, err := client.New(
|
||||
// client.FromEnv,
|
||||
@@ -282,7 +285,7 @@ func (cli *Client) Close() error {
|
||||
// be negotiated when making the actual requests, and for which cases
|
||||
// we cannot do the negotiation lazily.
|
||||
func (cli *Client) checkVersion(ctx context.Context) error {
|
||||
if cli.negotiated.Load() || !cli.negotiateVersion {
|
||||
if cli.negotiated.Load() {
|
||||
return nil
|
||||
}
|
||||
_, err := cli.Ping(ctx, PingOptions{
|
||||
|
||||
@@ -13,7 +13,7 @@ func ExampleNew() {
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -55,12 +55,6 @@ type clientConfig struct {
|
||||
// takes precedence. Either field disables API-version negotiation.
|
||||
envAPIVersion string
|
||||
|
||||
// negotiateVersion indicates if the client should automatically negotiate
|
||||
// the API version to use when making requests. API version negotiation is
|
||||
// performed on the first request, after which negotiated is set to "true"
|
||||
// so that subsequent requests do not re-negotiate.
|
||||
negotiateVersion bool
|
||||
|
||||
// traceOpts is a list of options to configure the tracing span.
|
||||
traceOpts []otelhttp.Option
|
||||
}
|
||||
@@ -325,9 +319,11 @@ func WithVersionFromEnv() Opt {
|
||||
// With this option enabled, the client automatically negotiates the API version
|
||||
// to use when making requests. API version negotiation is performed on the first
|
||||
// request; subsequent requests do not re-negotiate.
|
||||
//
|
||||
// Deprecated: API-version negotiation is now enabled by default. Use [WithAPIVersion]
|
||||
// or [WithAPIVersionFromEnv] to disable API version negotiation.
|
||||
func WithAPIVersionNegotiation() Opt {
|
||||
return func(c *clientConfig) error {
|
||||
c.negotiateVersion = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +257,6 @@ func TestNegotiateAPIVersionEmpty(t *testing.T) {
|
||||
const expected = MinAPIVersion
|
||||
|
||||
client, err := New(FromEnv,
|
||||
WithAPIVersionNegotiation(),
|
||||
WithBaseMockClient(mockPingResponse(http.StatusOK, PingResult{APIVersion: expected})),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
@@ -330,7 +329,6 @@ func TestNegotiateAPIVersion(t *testing.T) {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
opts := []Opt{
|
||||
FromEnv,
|
||||
WithAPIVersionNegotiation(),
|
||||
WithBaseMockClient(mockPingResponse(http.StatusOK, PingResult{APIVersion: tc.pingVersion})),
|
||||
}
|
||||
|
||||
@@ -396,7 +394,6 @@ func TestNegotiateAPIVersionAutomatic(t *testing.T) {
|
||||
WithBaseMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
return mockPingResponse(http.StatusOK, PingResult{APIVersion: pingVersion})(req)
|
||||
}),
|
||||
WithAPIVersionNegotiation(),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ func TestContainerCreateAutoRemove(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestContainerCreateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerCreate(t.Context(), ContainerCreateOptions{Config: &container.Config{Image: "test"}})
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestExecCreateError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestExecCreateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ExecCreate(t.Context(), "container_id", ExecCreateOptions{})
|
||||
|
||||
@@ -167,7 +167,7 @@ func TestContainerLogs(t *testing.T) {
|
||||
}
|
||||
|
||||
func ExampleClient_ContainerLogs_withTimeout() {
|
||||
client, err := New(FromEnv, WithAPIVersionNegotiation())
|
||||
client, err := New(FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestContainerRestartError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestContainerRestartConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerRestart(t.Context(), "nothing", ContainerRestartOptions{})
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestContainerStopError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestContainerStopConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerStop(t.Context(), "container_id", ContainerStopOptions{})
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestContainerWaitConnectionError(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
wait := client.ContainerWait(ctx, "nothing", ContainerWaitOptions{})
|
||||
|
||||
@@ -105,7 +105,7 @@ func TestTLSCloseWriter(t *testing.T) {
|
||||
|
||||
httpClient := ts.Client()
|
||||
defer httpClient.CloseIdleConnections()
|
||||
client, err := New(WithHost("tcp://"+serverURL.Host), WithHTTPClient(httpClient), WithAPIVersionNegotiation())
|
||||
client, err := New(WithHost("tcp://"+serverURL.Host), WithHTTPClient(httpClient))
|
||||
assert.NilError(t, err)
|
||||
|
||||
resp, err := client.postHijacked(ctx, "/asdf", url.Values{}, nil, map[string][]string{"Content-Type": {"text/plain"}})
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestImageListError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestImageListConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageList(t.Context(), ImageListOptions{})
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestNetworkCreateError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestNetworkCreateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkCreate(t.Context(), "mynetwork", NetworkCreateOptions{})
|
||||
|
||||
@@ -71,11 +71,12 @@ type SwarmStatus struct {
|
||||
// for other non-success status codes, failing to connect to the API, or failing
|
||||
// to parse the API response.
|
||||
func (cli *Client) Ping(ctx context.Context, options PingOptions) (PingResult, error) {
|
||||
if cli.negotiated.Load() && !options.ForceNegotiate {
|
||||
// API version was already negotiated or manually set.
|
||||
if !options.NegotiateAPIVersion {
|
||||
// No API version negotiation needed; just return ping response.
|
||||
return cli.ping(ctx)
|
||||
}
|
||||
if !options.NegotiateAPIVersion && !cli.negotiateVersion {
|
||||
if cli.negotiated.Load() && !options.ForceNegotiate {
|
||||
// API version was already negotiated or manually set.
|
||||
return cli.ping(ctx)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestServiceCreateError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestServiceCreateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceCreate(t.Context(), ServiceCreateOptions{})
|
||||
|
||||
@@ -129,7 +129,7 @@ func TestServiceLogs(t *testing.T) {
|
||||
}
|
||||
|
||||
func ExampleClient_ServiceLogs_withTimeout() {
|
||||
client, err := New(FromEnv, WithAPIVersionNegotiation())
|
||||
client, err := New(FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestServiceUpdateError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestServiceUpdateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceUpdate(t.Context(), "service_id", ServiceUpdateOptions{})
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestVolumeRemoveError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestVolumeRemoveConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.VolumeRemove(t.Context(), "volume_id", VolumeRemoveOptions{})
|
||||
|
||||
2
vendor/github.com/moby/moby/client/README.md
generated
vendored
2
vendor/github.com/moby/moby/client/README.md
generated
vendored
@@ -27,7 +27,7 @@ func main() {
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
25
vendor/github.com/moby/moby/client/client.go
generated
vendored
25
vendor/github.com/moby/moby/client/client.go
generated
vendored
@@ -8,10 +8,8 @@ https://docs.docker.com/reference/api/engine/
|
||||
|
||||
You use the library by constructing a client object using [New]
|
||||
and calling methods on it. The client can be configured from environment
|
||||
variables by passing the [FromEnv] option, and the [WithAPIVersionNegotiation]
|
||||
option to allow downgrading the API version used when connecting with an older
|
||||
daemon version. Other options can be configured manually by passing any of
|
||||
the available [Opt] options.
|
||||
variables by passing the [FromEnv] option. Other options can be configured
|
||||
manually by passing any of the available [Opt] options.
|
||||
|
||||
For example, to list running containers (the equivalent of "docker ps"):
|
||||
|
||||
@@ -30,7 +28,7 @@ For example, to list running containers (the equivalent of "docker ps"):
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -103,9 +101,9 @@ import (
|
||||
const DummyHost = "api.moby.localhost"
|
||||
|
||||
// MaxAPIVersion is the highest REST API version supported by the client.
|
||||
// If API-version negotiation is enabled (see [WithAPIVersionNegotiation],
|
||||
// the client may downgrade its API version. Similarly, the [WithAPIVersion]
|
||||
// and [WithAPIVersionFromEnv] options allow overriding the version.
|
||||
// If API-version negotiation is enabled, the client may downgrade its API version.
|
||||
// Similarly, the [WithAPIVersion] and [WithAPIVersionFromEnv] options allow
|
||||
// overriding the version and disable API-version negotiation.
|
||||
//
|
||||
// This version may be lower than the version of the api library module used.
|
||||
const MaxAPIVersion = "1.52"
|
||||
@@ -172,8 +170,13 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
|
||||
// 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 ([FromEnv]), and has automatic
|
||||
// API version negotiation enabled ([WithAPIVersionNegotiation]).
|
||||
// itself with values from environment variables ([FromEnv]).
|
||||
//
|
||||
// By default, the client automatically negotiates the API version to use when
|
||||
// making requests. API version negotiation is performed on the first request;
|
||||
// subsequent requests do not re-negotiate. Use [WithAPIVersion] or
|
||||
// [WithAPIVersionFromEnv] to configure the client with a fixed API version
|
||||
// and disable API version negotiation.
|
||||
//
|
||||
// cli, err := client.New(
|
||||
// client.FromEnv,
|
||||
@@ -282,7 +285,7 @@ func (cli *Client) Close() error {
|
||||
// be negotiated when making the actual requests, and for which cases
|
||||
// we cannot do the negotiation lazily.
|
||||
func (cli *Client) checkVersion(ctx context.Context) error {
|
||||
if cli.negotiated.Load() || !cli.negotiateVersion {
|
||||
if cli.negotiated.Load() {
|
||||
return nil
|
||||
}
|
||||
_, err := cli.Ping(ctx, PingOptions{
|
||||
|
||||
10
vendor/github.com/moby/moby/client/client_options.go
generated
vendored
10
vendor/github.com/moby/moby/client/client_options.go
generated
vendored
@@ -55,12 +55,6 @@ type clientConfig struct {
|
||||
// takes precedence. Either field disables API-version negotiation.
|
||||
envAPIVersion string
|
||||
|
||||
// negotiateVersion indicates if the client should automatically negotiate
|
||||
// the API version to use when making requests. API version negotiation is
|
||||
// performed on the first request, after which negotiated is set to "true"
|
||||
// so that subsequent requests do not re-negotiate.
|
||||
negotiateVersion bool
|
||||
|
||||
// traceOpts is a list of options to configure the tracing span.
|
||||
traceOpts []otelhttp.Option
|
||||
}
|
||||
@@ -325,9 +319,11 @@ func WithVersionFromEnv() Opt {
|
||||
// With this option enabled, the client automatically negotiates the API version
|
||||
// to use when making requests. API version negotiation is performed on the first
|
||||
// request; subsequent requests do not re-negotiate.
|
||||
//
|
||||
// Deprecated: API-version negotiation is now enabled by default. Use [WithAPIVersion]
|
||||
// or [WithAPIVersionFromEnv] to disable API version negotiation.
|
||||
func WithAPIVersionNegotiation() Opt {
|
||||
return func(c *clientConfig) error {
|
||||
c.negotiateVersion = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
7
vendor/github.com/moby/moby/client/ping.go
generated
vendored
7
vendor/github.com/moby/moby/client/ping.go
generated
vendored
@@ -71,11 +71,12 @@ type SwarmStatus struct {
|
||||
// for other non-success status codes, failing to connect to the API, or failing
|
||||
// to parse the API response.
|
||||
func (cli *Client) Ping(ctx context.Context, options PingOptions) (PingResult, error) {
|
||||
if cli.negotiated.Load() && !options.ForceNegotiate {
|
||||
// API version was already negotiated or manually set.
|
||||
if !options.NegotiateAPIVersion {
|
||||
// No API version negotiation needed; just return ping response.
|
||||
return cli.ping(ctx)
|
||||
}
|
||||
if !options.NegotiateAPIVersion && !cli.negotiateVersion {
|
||||
if cli.negotiated.Load() && !options.ForceNegotiate {
|
||||
// API version was already negotiated or manually set.
|
||||
return cli.ping(ctx)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user