client: rename/deprecate WithVersion, WithVersionFromEnv

Add WithAPIVersion and WithAPIVersionFromEnv to be more clear on
the intent, and to align with other related options and fields.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-11-12 16:39:20 +01:00
parent e5db2380f5
commit dae3650dcc
34 changed files with 111 additions and 77 deletions

View File

@@ -104,9 +104,8 @@ const DummyHost = "api.moby.localhost"
// MaxAPIVersion is the highest REST API version supported by the client. // MaxAPIVersion is the highest REST API version supported by the client.
// If API-version negotiation is enabled (see [WithAPIVersionNegotiation], // If API-version negotiation is enabled (see [WithAPIVersionNegotiation],
// [Client.NegotiateAPIVersion]), the client may downgrade its API version. // the client may downgrade its API version. Similarly, the [WithAPIVersion]
// Similarly, the [WithVersion] and [WithVersionFromEnv] allow overriding // and [WithAPIVersionFromEnv] options allow overriding the version.
// the version.
// //
// This version may be lower than the version of the api library module used. // This version may be lower than the version of the api library module used.
const MaxAPIVersion = "1.52" const MaxAPIVersion = "1.52"

View File

@@ -56,7 +56,7 @@ type Opt func(*clientConfig) error
// FromEnv configures the client with values from environment variables. It // FromEnv configures the client with values from environment variables. It
// is the equivalent of using the [WithTLSClientConfigFromEnv], [WithHostFromEnv], // is the equivalent of using the [WithTLSClientConfigFromEnv], [WithHostFromEnv],
// and [WithVersionFromEnv] options. // and [WithAPIVersionFromEnv] options.
// //
// FromEnv uses the following environment variables: // FromEnv uses the following environment variables:
// //
@@ -71,7 +71,7 @@ func FromEnv(c *clientConfig) error {
ops := []Opt{ ops := []Opt{
WithTLSClientConfigFromEnv(), WithTLSClientConfigFromEnv(),
WithHostFromEnv(), WithHostFromEnv(),
WithVersionFromEnv(), WithAPIVersionFromEnv(),
} }
for _, op := range ops { for _, op := range ops {
if err := op(c); err != nil { if err := op(c); err != nil {
@@ -241,14 +241,15 @@ func WithTLSClientConfigFromEnv() Opt {
} }
} }
// WithVersion overrides the client version with the specified one. If an empty // WithAPIVersion overrides the client's API version with the specified one,
// version is provided, the value is ignored to allow version negotiation // and disables API version negotiation. If an empty version is provided,
// (see [WithAPIVersionNegotiation]). // this option is ignored to allow version negotiation. The given version
// should be formatted "<major>.<minor>" (for example, "1.52").
// //
// WithVersion does not validate if the client supports the given version, // WithAPIVersion does not validate if the client supports the given version,
// and callers should verify if the version is in the correct format and // and callers should verify if the version is in the correct format and
// lower than the maximum supported version as defined by [MaxAPIVersion]. // lower than the maximum supported version as defined by [MaxAPIVersion].
func WithVersion(version string) Opt { func WithAPIVersion(version string) Opt {
return func(c *clientConfig) error { return func(c *clientConfig) error {
if v := strings.TrimPrefix(version, "v"); v != "" { if v := strings.TrimPrefix(version, "v"); v != "" {
c.version = v c.version = v
@@ -258,17 +259,34 @@ func WithVersion(version string) Opt {
} }
} }
// WithVersionFromEnv overrides the client version with the version specified in // WithVersion overrides the client version with the specified one.
//
// Deprecated: use [WithAPIVersion] instead.
func WithVersion(version string) Opt {
return WithAPIVersion(version)
}
// WithAPIVersionFromEnv overrides the client version with the version specified in
// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable. // the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
// If DOCKER_API_VERSION is not set, or set to an empty value, the version // If DOCKER_API_VERSION is not set, or set to an empty value, the version
// is not modified. // is not modified.
// //
// WithVersion does not validate if the client supports the given version, // WithAPIVersionFromEnv does not validate if the client supports the given version,
// and callers should verify if the version is in the correct format and // and callers should verify if the version is in the correct format and
// lower than the maximum supported version as defined by [MaxAPIVersion]. // lower than the maximum supported version as defined by [MaxAPIVersion].
func WithAPIVersionFromEnv() Opt {
return func(c *clientConfig) error {
return WithAPIVersion(os.Getenv(EnvOverrideAPIVersion))(c)
}
}
// WithVersionFromEnv overrides the client version with the version specified in
// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
//
// Deprecated: use [WithAPIVersionFromEnv] instead.
func WithVersionFromEnv() Opt { func WithVersionFromEnv() Opt {
return func(c *clientConfig) error { return func(c *clientConfig) error {
return WithVersion(os.Getenv(EnvOverrideAPIVersion))(c) return WithAPIVersion(os.Getenv(EnvOverrideAPIVersion))(c)
} }
} }

View File

@@ -44,8 +44,8 @@ func TestOptionWithTimeout(t *testing.T) {
assert.Check(t, is.Equal(c.client.Timeout, timeout)) assert.Check(t, is.Equal(c.client.Timeout, timeout))
} }
func TestOptionWithVersionFromEnv(t *testing.T) { func TestOptionAPIWithVersionFromEnv(t *testing.T) {
c, err := New(WithVersionFromEnv()) c, err := New(WithAPIVersionFromEnv())
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, c.client != nil) assert.Check(t, c.client != nil)
assert.Check(t, is.Equal(c.version, MaxAPIVersion)) assert.Check(t, is.Equal(c.version, MaxAPIVersion))
@@ -53,7 +53,7 @@ func TestOptionWithVersionFromEnv(t *testing.T) {
t.Setenv("DOCKER_API_VERSION", "2.9999") t.Setenv("DOCKER_API_VERSION", "2.9999")
c, err = New(WithVersionFromEnv()) c, err = New(WithAPIVersionFromEnv())
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, c.client != nil) assert.Check(t, c.client != nil)
assert.Check(t, is.Equal(c.version, "2.9999")) assert.Check(t, is.Equal(c.version, "2.9999"))

View File

@@ -175,7 +175,7 @@ func TestGetAPIPath(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
for _, tc := range tests { for _, tc := range tests {
client, err := New( client, err := New(
WithVersion(tc.version), WithAPIVersion(tc.version),
WithHost("tcp://localhost:2375"), WithHost("tcp://localhost:2375"),
) )
assert.NilError(t, err) assert.NilError(t, err)
@@ -338,7 +338,7 @@ func TestNegotiateAPIVersion(t *testing.T) {
// Note that this check is redundant, as WithVersion() considers // Note that this check is redundant, as WithVersion() considers
// an empty version equivalent to "not setting a version", but // an empty version equivalent to "not setting a version", but
// doing this just to be explicit we are using the default. // doing this just to be explicit we are using the default.
opts = append(opts, WithVersion(tc.clientVersion)) opts = append(opts, WithAPIVersion(tc.clientVersion))
} }
client, err := New(opts...) client, err := New(opts...)
assert.NilError(t, err) assert.NilError(t, err)
@@ -422,7 +422,7 @@ func TestNegotiateAPIVersionAutomatic(t *testing.T) {
// with an empty version string does still allow API-version negotiation // with an empty version string does still allow API-version negotiation
func TestNegotiateAPIVersionWithEmptyVersion(t *testing.T) { func TestNegotiateAPIVersionWithEmptyVersion(t *testing.T) {
client, err := New( client, err := New(
WithVersion(""), WithAPIVersion(""),
WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{"1.50"}}, "OK")), WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{"1.50"}}, "OK")),
) )
assert.NilError(t, err) assert.NilError(t, err)
@@ -439,7 +439,7 @@ func TestNegotiateAPIVersionWithEmptyVersion(t *testing.T) {
func TestNegotiateAPIVersionWithFixedVersion(t *testing.T) { func TestNegotiateAPIVersionWithFixedVersion(t *testing.T) {
const customVersion = "1.50" const customVersion = "1.50"
client, err := New( client, err := New(
WithVersion(customVersion), WithAPIVersion(customVersion),
WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{"1.49"}}, "OK")), WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{"1.49"}}, "OK")),
) )
assert.NilError(t, err) assert.NilError(t, err)
@@ -515,12 +515,12 @@ func TestCustomAPIVersion(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
client, err := New(WithVersion(tc.version)) client, err := New(WithAPIVersion(tc.version))
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, is.Equal(client.ClientVersion(), tc.expected)) assert.Check(t, is.Equal(client.ClientVersion(), tc.expected))
t.Setenv(EnvOverrideAPIVersion, tc.expected) t.Setenv(EnvOverrideAPIVersion, tc.expected)
client, err = New(WithVersionFromEnv()) client, err = New(WithAPIVersionFromEnv())
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, is.Equal(client.ClientVersion(), tc.expected)) assert.Check(t, is.Equal(client.ClientVersion(), tc.expected))
}) })

View File

@@ -13,7 +13,7 @@ const (
// be used to override the API version to use. Value must be // be used to override the API version to use. Value must be
// formatted as MAJOR.MINOR, for example, "1.19". // formatted as MAJOR.MINOR, for example, "1.19".
// //
// This env-var is read by [FromEnv] and [WithVersionFromEnv] and when set to a // This env-var is read by [FromEnv] and [WithAPIVersionFromEnv] and when set to a
// non-empty value, takes precedence over API version negotiation. // non-empty value, takes precedence over API version negotiation.
// //
// This environment variable should be used for debugging purposes only, as // This environment variable should be used for debugging purposes only, as

View File

@@ -116,7 +116,7 @@ func TestImageListWithSharedSize(t *testing.T) {
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) { client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
query = req.URL.Query() query = req.URL.Query()
return mockResponse(http.StatusOK, nil, "[]")(req) return mockResponse(http.StatusOK, nil, "[]")(req)
}), WithVersion(tc.version)) }), WithAPIVersion(tc.version))
assert.NilError(t, err) assert.NilError(t, err)
_, err = client.ImageList(t.Context(), tc.options) _, err = client.ImageList(t.Context(), tc.options)
assert.NilError(t, err) assert.NilError(t, err)

View File

@@ -20,7 +20,7 @@ type PingOptions struct {
// //
// If a manual override is in place, either through the "DOCKER_API_VERSION" // If a manual override is in place, either through the "DOCKER_API_VERSION"
// ([EnvOverrideAPIVersion]) environment variable, or if the client is initialized // ([EnvOverrideAPIVersion]) environment variable, or if the client is initialized
// with a fixed version ([WithVersion]), no negotiation is performed. // with a fixed version ([WithAPIVersion]), no negotiation is performed.
// //
// If the API server's ping response does not contain an API version, or if the // 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 // client did not get a successful ping response, it assumes it is connected with
@@ -31,7 +31,7 @@ type PingOptions struct {
// ForceNegotiate forces the client to re-negotiate the API version, even if // ForceNegotiate forces the client to re-negotiate the API version, even if
// API-version negotiation already happened. This option cannot be // API-version negotiation already happened. This option cannot be
// used if the client is configured with a fixed version using (using // used if the client is configured with a fixed version using (using
// [WithVersion] or [WithVersionFromEnv]). // [WithAPIVersion] or [WithAPIVersionFromEnv]).
// //
// This option has no effect if NegotiateAPIVersion is not set. // This option has no effect if NegotiateAPIVersion is not set.
ForceNegotiate bool ForceNegotiate bool

View File

@@ -199,7 +199,7 @@ func TestResponseErrors(t *testing.T) {
return mockResponse(http.StatusBadRequest, http.Header{"Content-Type": []string{tc.contentType}}, tc.response)(req) return mockResponse(http.StatusBadRequest, http.Header{"Content-Type": []string{tc.contentType}}, tc.response)(req)
})) }))
if tc.apiVersion != "" { if tc.apiVersion != "" {
client, err = New(WithHTTPClient(client.client), WithVersion(tc.apiVersion)) client, err = New(WithHTTPClient(client.client), WithAPIVersion(tc.apiVersion))
} }
assert.NilError(t, err) assert.NilError(t, err)
_, err = client.Ping(t.Context(), PingOptions{}) _, err = client.Ping(t.Context(), PingOptions{})

View File

@@ -133,7 +133,7 @@ func TestLegacyDiskUsage(t *testing.T) {
const legacyVersion = "1.51" const legacyVersion = "1.51"
const expectedURL = "/system/df" const expectedURL = "/system/df"
client, err := New( client, err := New(
WithVersion(legacyVersion), WithAPIVersion(legacyVersion),
WithMockClient(func(req *http.Request) (*http.Response, error) { WithMockClient(func(req *http.Request) (*http.Response, error) {
if err := assertRequest(req, http.MethodGet, "/v"+legacyVersion+expectedURL); err != nil { if err := assertRequest(req, http.MethodGet, "/v"+legacyVersion+expectedURL); err != nil {
return nil, err return nil, err

View File

@@ -109,7 +109,7 @@ func (s *DockerAPISuite) TestAPIImagesSizeCompatibility(c *testing.T) {
assert.Assert(c, img.Size != int64(-1)) assert.Assert(c, img.Size != int64(-1))
} }
apiclient, err = client.New(client.FromEnv, client.WithVersion("v1.24")) apiclient, err = client.New(client.FromEnv, client.WithAPIVersion("v1.24"))
assert.NilError(c, err) assert.NilError(c, err)
defer apiclient.Close() defer apiclient.Close()

View File

@@ -254,7 +254,7 @@ func waitInspect(name, expr, expected string, timeout time.Duration) error {
func getInspectBody(t *testing.T, version, id string) json.RawMessage { func getInspectBody(t *testing.T, version, id string) json.RawMessage {
t.Helper() t.Helper()
apiClient, err := client.New(client.FromEnv, client.WithVersion(version)) apiClient, err := client.New(client.FromEnv, client.WithAPIVersion(version))
assert.NilError(t, err) assert.NilError(t, err)
defer apiClient.Close() defer apiClient.Close()
inspect, err := apiClient.ContainerInspect(testutil.GetContext(t), id, client.ContainerInspectOptions{}) inspect, err := apiClient.ContainerInspect(testutil.GetContext(t), id, client.ContainerInspectOptions{})

View File

@@ -734,7 +734,7 @@ func TestCreateWithMultipleEndpointSettings(t *testing.T) {
for _, tc := range testcases { for _, tc := range testcases {
t.Run("with API v"+tc.apiVersion, func(t *testing.T) { t.Run("with API v"+tc.apiVersion, func(t *testing.T) {
apiClient, err := client.New(client.FromEnv, client.WithVersion(tc.apiVersion)) apiClient, err := client.New(client.FromEnv, client.WithAPIVersion(tc.apiVersion))
assert.NilError(t, err) assert.NilError(t, err)
config := container.Config{ config := container.Config{

View File

@@ -135,7 +135,7 @@ func TestInspectImageManifestPlatform(t *testing.T) {
assert.Check(t, is.DeepEqual(*inspect.ImageManifestDescriptor.Platform, hostPlatform)) assert.Check(t, is.DeepEqual(*inspect.ImageManifestDescriptor.Platform, hostPlatform))
t.Run("pre 1.48", func(t *testing.T) { t.Run("pre 1.48", func(t *testing.T) {
oldClient := request.NewAPIClient(t, client.WithVersion("1.47")) oldClient := request.NewAPIClient(t, client.WithAPIVersion("1.47"))
inspect := container.Inspect(ctx, t, oldClient, ctr) inspect := container.Inspect(ctx, t, oldClient, ctr)
assert.Check(t, is.Nil(inspect.ImageManifestDescriptor)) assert.Check(t, is.Nil(inspect.ImageManifestDescriptor))
}) })

View File

@@ -328,7 +328,7 @@ func TestIpcModeOlderClient(t *testing.T) {
assert.Check(t, is.Equal(string(inspect.Container.HostConfig.IpcMode), "private")) assert.Check(t, is.Equal(string(inspect.Container.HostConfig.IpcMode), "private"))
// main check: using older client creates "shareable" container // main check: using older client creates "shareable" container
apiClient = request.NewAPIClient(t, client.WithVersion("1.39")) apiClient = request.NewAPIClient(t, client.WithAPIVersion("1.39"))
cID = container.Create(ctx, t, apiClient, container.WithAutoRemove) cID = container.Create(ctx, t, apiClient, container.WithAutoRemove)
inspect, err = apiClient.ContainerInspect(ctx, cID, client.ContainerInspectOptions{}) inspect, err = apiClient.ContainerInspect(ctx, cID, client.ContainerInspectOptions{})

View File

@@ -61,7 +61,7 @@ func TestContainerList_Annotations(t *testing.T) {
for _, tc := range testcases { for _, tc := range testcases {
t.Run(fmt.Sprintf("run with version v%s", tc.apiVersion), func(t *testing.T) { t.Run(fmt.Sprintf("run with version v%s", tc.apiVersion), func(t *testing.T) {
apiClient := request.NewAPIClient(t, client.WithVersion(tc.apiVersion)) apiClient := request.NewAPIClient(t, client.WithAPIVersion(tc.apiVersion))
id := container.Create(ctx, t, apiClient, container.WithAnnotations(annotations)) id := container.Create(ctx, t, apiClient, container.WithAnnotations(annotations))
defer container.Remove(ctx, t, apiClient, id, client.ContainerRemoveOptions{Force: true}) defer container.Remove(ctx, t, apiClient, id, client.ContainerRemoveOptions{Force: true})
@@ -186,7 +186,7 @@ func TestContainerList_HealthSummary(t *testing.T) {
for _, tc := range testcases { for _, tc := range testcases {
t.Run(fmt.Sprintf("run with version v%s", tc.apiVersion), func(t *testing.T) { t.Run(fmt.Sprintf("run with version v%s", tc.apiVersion), func(t *testing.T) {
apiClient := request.NewAPIClient(t, client.WithVersion(tc.apiVersion)) apiClient := request.NewAPIClient(t, client.WithAPIVersion(tc.apiVersion))
cID := container.Run(ctx, t, apiClient, container.WithTty(true), container.WithWorkingDir("/foo"), func(c *container.TestContainerConfig) { cID := container.Run(ctx, t, apiClient, container.WithTty(true), container.WithWorkingDir("/foo"), func(c *container.TestContainerConfig) {
c.Config.Healthcheck = &containertypes.HealthConfig{ c.Config.Healthcheck = &containertypes.HealthConfig{

View File

@@ -524,7 +524,7 @@ func TestContainerBindMountReadOnlyDefault(t *testing.T) {
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), minDaemonVersion), "requires API v"+minDaemonVersion) skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), minDaemonVersion), "requires API v"+minDaemonVersion)
if tc.clientVersion != "" { if tc.clientVersion != "" {
c, err := client.New(client.FromEnv, client.WithVersion(tc.clientVersion)) c, err := client.New(client.FromEnv, client.WithAPIVersion(tc.clientVersion))
assert.NilError(t, err, "failed to create client with version v%s", tc.clientVersion) assert.NilError(t, err, "failed to create client with version v%s", tc.clientVersion)
apiClient = c apiClient = c
} }

View File

@@ -139,7 +139,7 @@ func TestCgroupNamespacesRunOlderClient(t *testing.T) {
ctx := testutil.StartSpan(baseContext, t) ctx := testutil.StartSpan(baseContext, t)
d := daemon.New(t, daemon.WithEnvVars("DOCKER_MIN_API_VERSION=1.39"), daemon.WithDefaultCgroupNamespaceMode("private")) d := daemon.New(t, daemon.WithEnvVars("DOCKER_MIN_API_VERSION=1.39"), daemon.WithDefaultCgroupNamespaceMode("private"))
apiClient := d.NewClientT(t, client.WithVersion("1.39")) apiClient := d.NewClientT(t, client.WithAPIVersion("1.39"))
d.StartWithBusybox(ctx, t) d.StartWithBusybox(ctx, t)
defer d.Stop(t) defer d.Stop(t)

View File

@@ -277,7 +277,7 @@ func TestMacAddressIsAppliedToMainNetworkWithShortID(t *testing.T) {
d.StartWithBusybox(ctx, t) d.StartWithBusybox(ctx, t)
defer d.Stop(t) defer d.Stop(t)
apiClient := d.NewClientT(t, client.WithVersion("1.43")) apiClient := d.NewClientT(t, client.WithAPIVersion("1.43"))
n := net.CreateNoError(ctx, t, apiClient, "testnet", net.WithIPAM("192.168.101.0/24", "192.168.101.1")) n := net.CreateNoError(ctx, t, apiClient, "testnet", net.WithIPAM("192.168.101.0/24", "192.168.101.1"))
@@ -309,7 +309,7 @@ func TestStaticIPOutsideSubpool(t *testing.T) {
d.StartWithBusybox(ctx, t) d.StartWithBusybox(ctx, t)
defer d.Stop(t) defer d.Stop(t)
apiClient, err := client.New(client.FromEnv, client.WithVersion("1.43")) apiClient, err := client.New(client.FromEnv, client.WithAPIVersion("1.43"))
assert.NilError(t, err) assert.NilError(t, err)
const netname = "subnet-range" const netname = "subnet-range"

View File

@@ -153,7 +153,7 @@ func TestUpdatePidsLimit(t *testing.T) {
ctx := setupTest(t) ctx := setupTest(t)
apiClient := testEnv.APIClient() apiClient := testEnv.APIClient()
oldAPIClient := request.NewAPIClient(t, client.WithVersion("1.24")) oldAPIClient := request.NewAPIClient(t, client.WithAPIVersion("1.24"))
intPtr := func(i int64) *int64 { intPtr := func(i int64) *int64 {
return &i return &i

View File

@@ -130,7 +130,7 @@ func TestInspectGraphDriverAPIBC(t *testing.T) {
d := daemon.New(t) d := daemon.New(t)
defer d.Stop(t) defer d.Stop(t)
d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false", "--storage-driver="+tc.storageDriver) d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false", "--storage-driver="+tc.storageDriver)
c := d.NewClientT(t, client.WithVersion(tc.apiVersion)) c := d.NewClientT(t, client.WithAPIVersion(tc.apiVersion))
// Check selection of containerd / storage-driver worked. // Check selection of containerd / storage-driver worked.
info := d.Info(t) info := d.Info(t)

View File

@@ -253,7 +253,7 @@ func TestAPIImagesListManifests(t *testing.T) {
t.Run("unsupported before 1.47", func(t *testing.T) { t.Run("unsupported before 1.47", func(t *testing.T) {
// TODO: Remove when MinAPIVersion >= 1.47 // TODO: Remove when MinAPIVersion >= 1.47
c := d.NewClientT(t, client.WithVersion("1.46")) c := d.NewClientT(t, client.WithAPIVersion("1.46"))
imageList, err := c.ImageList(ctx, client.ImageListOptions{Manifests: true}) imageList, err := c.ImageList(ctx, client.ImageListOptions{Manifests: true})
assert.NilError(t, err) assert.NilError(t, err)
@@ -262,7 +262,7 @@ func TestAPIImagesListManifests(t *testing.T) {
assert.Check(t, is.Nil(imageList.Items[0].Manifests)) assert.Check(t, is.Nil(imageList.Items[0].Manifests))
}) })
api147 := d.NewClientT(t, client.WithVersion("1.47")) api147 := d.NewClientT(t, client.WithAPIVersion("1.47"))
t.Run("no manifests if not requested", func(t *testing.T) { t.Run("no manifests if not requested", func(t *testing.T) {
imageList, err := api147.ImageList(ctx, client.ImageListOptions{}) imageList, err := api147.ImageList(ctx, client.ImageListOptions{})

View File

@@ -948,7 +948,7 @@ func TestEmptyPortBindingsBC(t *testing.T) {
defer d.Stop(t) defer d.Stop(t)
createInspect := func(t *testing.T, version string, pbs []networktypes.PortBinding) (networktypes.PortMap, []string) { createInspect := func(t *testing.T, version string, pbs []networktypes.PortBinding) (networktypes.PortMap, []string) {
apiClient := d.NewClientT(t, client.WithVersion(version)) apiClient := d.NewClientT(t, client.WithAPIVersion(version))
defer apiClient.Close() defer apiClient.Close()
// Skip this subtest if the daemon doesn't support the client version. // Skip this subtest if the daemon doesn't support the client version.
@@ -1074,7 +1074,7 @@ func TestBridgeIPAMStatus(t *testing.T) {
d.StartWithBusybox(ctx, t) d.StartWithBusybox(ctx, t)
defer d.Stop(t) defer d.Stop(t)
c := d.NewClientT(t, client.WithVersion("1.52")) c := d.NewClientT(t, client.WithAPIVersion("1.52"))
checkSubnets := func( checkSubnets := func(
netName string, want networktypes.SubnetStatuses, netName string, want networktypes.SubnetStatuses,
@@ -1193,7 +1193,7 @@ func TestBridgeIPAMStatus(t *testing.T) {
}, },
}) })
oldc := d.NewClientT(t, client.WithVersion("1.51")) oldc := d.NewClientT(t, client.WithAPIVersion("1.51"))
res, err := oldc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{}) res, err := oldc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) { if assert.Check(t, err) {
assert.Check(t, res.Network.Status == nil, "expected nil Status with API version 1.51") assert.Check(t, res.Network.Status == nil, "expected nil Status with API version 1.51")

View File

@@ -488,7 +488,7 @@ func TestIpvlanIPAM(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
ctx := testutil.StartSpan(ctx, t) ctx := testutil.StartSpan(ctx, t)
c := d.NewClientT(t, client.WithVersion(tc.apiVersion)) c := d.NewClientT(t, client.WithAPIVersion(tc.apiVersion))
netOpts := []func(*client.NetworkCreateOptions){ netOpts := []func(*client.NetworkCreateOptions){
net.WithIPvlan("", "l3"), net.WithIPvlan("", "l3"),
@@ -551,13 +551,13 @@ func TestIpvlanIPAM(t *testing.T) {
} }
assert.Check(t, is.Equal(strings.TrimSpace(sysctlRes.Combined()), expDisableIPv6)) assert.Check(t, is.Equal(strings.TrimSpace(sysctlRes.Combined()), expDisableIPv6))
cc := d.NewClientT(t, client.WithVersion("1.52")) cc := d.NewClientT(t, client.WithAPIVersion("1.52"))
res, err := cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{}) res, err := cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) { if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) {
assert.Check(t, is.DeepEqual(wantSubnetStatus, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty())) assert.Check(t, is.DeepEqual(wantSubnetStatus, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
} }
cc.Close() cc.Close()
cc = d.NewClientT(t, client.WithVersion("1.51")) cc = d.NewClientT(t, client.WithAPIVersion("1.51"))
res, err = cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{}) res, err = cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
assert.Check(t, err) assert.Check(t, err)
assert.Check(t, res.Network.Status == nil) assert.Check(t, res.Network.Status == nil)

View File

@@ -484,7 +484,7 @@ func TestMacvlanIPAM(t *testing.T) {
for _, tc := range testcases { for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
ctx := testutil.StartSpan(ctx, t) ctx := testutil.StartSpan(ctx, t)
c := d.NewClientT(t, client.WithVersion(tc.apiVersion)) c := d.NewClientT(t, client.WithAPIVersion(tc.apiVersion))
netOpts := []func(*client.NetworkCreateOptions){ netOpts := []func(*client.NetworkCreateOptions){
net.WithMacvlan(""), net.WithMacvlan(""),
@@ -554,13 +554,13 @@ func TestMacvlanIPAM(t *testing.T) {
} }
assert.Check(t, is.Equal(strings.TrimSpace(sysctlRes.Combined()), expDisableIPv6)) assert.Check(t, is.Equal(strings.TrimSpace(sysctlRes.Combined()), expDisableIPv6))
cc := d.NewClientT(t, client.WithVersion("1.52")) cc := d.NewClientT(t, client.WithAPIVersion("1.52"))
res, err := cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{}) res, err := cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) { if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) {
assert.Check(t, is.DeepEqual(wantSubnetStatus, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty())) assert.Check(t, is.DeepEqual(wantSubnetStatus, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
} }
_ = cc.Close() _ = cc.Close()
cc = d.NewClientT(t, client.WithVersion("1.51")) cc = d.NewClientT(t, client.WithAPIVersion("1.51"))
res, err = cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{}) res, err = cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
assert.Check(t, err) assert.Check(t, err)
assert.Check(t, res.Network.Status == nil) assert.Check(t, res.Network.Status == nil)

View File

@@ -1126,7 +1126,7 @@ func TestDisableIPv4(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
c := d.NewClientT(t, client.WithVersion(tc.apiVersion)) c := d.NewClientT(t, client.WithAPIVersion(tc.apiVersion))
const netName = "testnet" const netName = "testnet"
network.CreateNoError(ctx, t, c, netName, network.CreateNoError(ctx, t, c, netName,
@@ -1277,7 +1277,7 @@ func TestSetInterfaceSysctl(t *testing.T) {
d.StartWithBusybox(ctx, t) d.StartWithBusybox(ctx, t)
defer d.Stop(t) defer d.Stop(t)
c := d.NewClientT(t, client.WithVersion("1.46")) c := d.NewClientT(t, client.WithAPIVersion("1.46"))
defer c.Close() defer c.Close()
const scName = "net.ipv4.conf.eth0.forwarding" const scName = "net.ipv4.conf.eth0.forwarding"

View File

@@ -43,7 +43,7 @@ func TestInfoFirewallBackend(t *testing.T) {
// Check FirewallBackend is omitted for API <= 1.48. // Check FirewallBackend is omitted for API <= 1.48.
t.Run("api 1.48", func(t *testing.T) { t.Run("api 1.48", func(t *testing.T) {
c148 := request.NewAPIClient(t, client.WithVersion("1.48")) c148 := request.NewAPIClient(t, client.WithAPIVersion("1.48"))
result, err := c148.Info(ctx, client.InfoOptions{}) result, err := c148.Info(ctx, client.InfoOptions{})
assert.NilError(t, err) assert.NilError(t, err)
info148 := result.Info info148 := result.Info

View File

@@ -194,9 +194,9 @@ func TestInspectCfgdMAC(t *testing.T) {
var copts []client.Opt var copts []client.Opt
if tc.ctrWide { if tc.ctrWide {
copts = append(copts, client.WithVersion("1.43")) copts = append(copts, client.WithAPIVersion("1.43"))
} else { } else {
copts = append(copts, client.WithVersion("1.51")) copts = append(copts, client.WithAPIVersion("1.51"))
} }
c := d.NewClientT(t, copts...) c := d.NewClientT(t, copts...)
defer c.Close() defer c.Close()
@@ -267,7 +267,7 @@ func TestWatchtowerCreate(t *testing.T) {
d.StartWithBusybox(ctx, t) d.StartWithBusybox(ctx, t)
defer d.Stop(t) defer d.Stop(t)
c := d.NewClientT(t, client.WithVersion("1.25")) c := d.NewClientT(t, client.WithAPIVersion("1.25"))
defer c.Close() defer c.Close()
// Create a "/29" network, with a single address in iprange for IPAM to // Create a "/29" network, with a single address in iprange for IPAM to

View File

@@ -30,7 +30,7 @@ func TestDockerNetworkConnectAliasPreV144(t *testing.T) {
d := swarm.NewSwarm(ctx, t, testEnv, daemon.WithEnvVars("DOCKER_MIN_API_VERSION=1.43")) d := swarm.NewSwarm(ctx, t, testEnv, daemon.WithEnvVars("DOCKER_MIN_API_VERSION=1.43"))
defer d.Stop(t) defer d.Stop(t)
apiClient := d.NewClientT(t, client.WithVersion("1.43")) apiClient := d.NewClientT(t, client.WithAPIVersion("1.43"))
defer apiClient.Close() defer apiClient.Close()
name := t.Name() + "test-alias" name := t.Name() + "test-alias"

View File

@@ -53,7 +53,7 @@ func TestAPIClientVersionOldNotSupported(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
vMinInt-- vMinInt--
version := fmt.Sprintf("%s.%d", major, vMinInt) version := fmt.Sprintf("%s.%d", major, vMinInt)
apiClient := request.NewAPIClient(t, client.WithVersion(version)) apiClient := request.NewAPIClient(t, client.WithAPIVersion(version))
expectedErrorMessage := fmt.Sprintf("Error response from daemon: client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", version, minApiVersion) expectedErrorMessage := fmt.Sprintf("Error response from daemon: client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", version, minApiVersion)
_, err = apiClient.ServerVersion(ctx, client.ServerVersionOptions{}) _, err = apiClient.ServerVersion(ctx, client.ServerVersionOptions{})

View File

@@ -306,7 +306,7 @@ func TestVolumePruneAnonymous(t *testing.T) {
assert.Check(t, is.Equal(len(report.VolumesDeleted), 2)) assert.Check(t, is.Equal(len(report.VolumesDeleted), 2))
// Validate that older API versions still have the old behavior of pruning all local volumes // Validate that older API versions still have the old behavior of pruning all local volumes
clientOld, err := client.New(client.FromEnv, client.WithVersion("1.41")) clientOld, err := client.New(client.FromEnv, client.WithAPIVersion("1.41"))
assert.NilError(t, err) assert.NilError(t, err)
defer clientOld.Close() defer clientOld.Close()
assert.Equal(t, clientOld.ClientVersion(), "1.41") assert.Equal(t, clientOld.ClientVersion(), "1.41")

View File

@@ -104,9 +104,8 @@ const DummyHost = "api.moby.localhost"
// MaxAPIVersion is the highest REST API version supported by the client. // MaxAPIVersion is the highest REST API version supported by the client.
// If API-version negotiation is enabled (see [WithAPIVersionNegotiation], // If API-version negotiation is enabled (see [WithAPIVersionNegotiation],
// [Client.NegotiateAPIVersion]), the client may downgrade its API version. // the client may downgrade its API version. Similarly, the [WithAPIVersion]
// Similarly, the [WithVersion] and [WithVersionFromEnv] allow overriding // and [WithAPIVersionFromEnv] options allow overriding the version.
// the version.
// //
// This version may be lower than the version of the api library module used. // This version may be lower than the version of the api library module used.
const MaxAPIVersion = "1.52" const MaxAPIVersion = "1.52"

View File

@@ -56,7 +56,7 @@ type Opt func(*clientConfig) error
// FromEnv configures the client with values from environment variables. It // FromEnv configures the client with values from environment variables. It
// is the equivalent of using the [WithTLSClientConfigFromEnv], [WithHostFromEnv], // is the equivalent of using the [WithTLSClientConfigFromEnv], [WithHostFromEnv],
// and [WithVersionFromEnv] options. // and [WithAPIVersionFromEnv] options.
// //
// FromEnv uses the following environment variables: // FromEnv uses the following environment variables:
// //
@@ -71,7 +71,7 @@ func FromEnv(c *clientConfig) error {
ops := []Opt{ ops := []Opt{
WithTLSClientConfigFromEnv(), WithTLSClientConfigFromEnv(),
WithHostFromEnv(), WithHostFromEnv(),
WithVersionFromEnv(), WithAPIVersionFromEnv(),
} }
for _, op := range ops { for _, op := range ops {
if err := op(c); err != nil { if err := op(c); err != nil {
@@ -241,14 +241,15 @@ func WithTLSClientConfigFromEnv() Opt {
} }
} }
// WithVersion overrides the client version with the specified one. If an empty // WithAPIVersion overrides the client's API version with the specified one,
// version is provided, the value is ignored to allow version negotiation // and disables API version negotiation. If an empty version is provided,
// (see [WithAPIVersionNegotiation]). // this option is ignored to allow version negotiation. The given version
// should be formatted "<major>.<minor>" (for example, "1.52").
// //
// WithVersion does not validate if the client supports the given version, // WithAPIVersion does not validate if the client supports the given version,
// and callers should verify if the version is in the correct format and // and callers should verify if the version is in the correct format and
// lower than the maximum supported version as defined by [MaxAPIVersion]. // lower than the maximum supported version as defined by [MaxAPIVersion].
func WithVersion(version string) Opt { func WithAPIVersion(version string) Opt {
return func(c *clientConfig) error { return func(c *clientConfig) error {
if v := strings.TrimPrefix(version, "v"); v != "" { if v := strings.TrimPrefix(version, "v"); v != "" {
c.version = v c.version = v
@@ -258,17 +259,34 @@ func WithVersion(version string) Opt {
} }
} }
// WithVersionFromEnv overrides the client version with the version specified in // WithVersion overrides the client version with the specified one.
//
// Deprecated: use [WithAPIVersion] instead.
func WithVersion(version string) Opt {
return WithAPIVersion(version)
}
// WithAPIVersionFromEnv overrides the client version with the version specified in
// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable. // the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
// If DOCKER_API_VERSION is not set, or set to an empty value, the version // If DOCKER_API_VERSION is not set, or set to an empty value, the version
// is not modified. // is not modified.
// //
// WithVersion does not validate if the client supports the given version, // WithAPIVersionFromEnv does not validate if the client supports the given version,
// and callers should verify if the version is in the correct format and // and callers should verify if the version is in the correct format and
// lower than the maximum supported version as defined by [MaxAPIVersion]. // lower than the maximum supported version as defined by [MaxAPIVersion].
func WithAPIVersionFromEnv() Opt {
return func(c *clientConfig) error {
return WithAPIVersion(os.Getenv(EnvOverrideAPIVersion))(c)
}
}
// WithVersionFromEnv overrides the client version with the version specified in
// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
//
// Deprecated: use [WithAPIVersionFromEnv] instead.
func WithVersionFromEnv() Opt { func WithVersionFromEnv() Opt {
return func(c *clientConfig) error { return func(c *clientConfig) error {
return WithVersion(os.Getenv(EnvOverrideAPIVersion))(c) return WithAPIVersion(os.Getenv(EnvOverrideAPIVersion))(c)
} }
} }

View File

@@ -13,7 +13,7 @@ const (
// be used to override the API version to use. Value must be // be used to override the API version to use. Value must be
// formatted as MAJOR.MINOR, for example, "1.19". // formatted as MAJOR.MINOR, for example, "1.19".
// //
// This env-var is read by [FromEnv] and [WithVersionFromEnv] and when set to a // This env-var is read by [FromEnv] and [WithAPIVersionFromEnv] and when set to a
// non-empty value, takes precedence over API version negotiation. // non-empty value, takes precedence over API version negotiation.
// //
// This environment variable should be used for debugging purposes only, as // This environment variable should be used for debugging purposes only, as

View File

@@ -20,7 +20,7 @@ type PingOptions struct {
// //
// If a manual override is in place, either through the "DOCKER_API_VERSION" // If a manual override is in place, either through the "DOCKER_API_VERSION"
// ([EnvOverrideAPIVersion]) environment variable, or if the client is initialized // ([EnvOverrideAPIVersion]) environment variable, or if the client is initialized
// with a fixed version ([WithVersion]), no negotiation is performed. // with a fixed version ([WithAPIVersion]), no negotiation is performed.
// //
// If the API server's ping response does not contain an API version, or if the // 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 // client did not get a successful ping response, it assumes it is connected with
@@ -31,7 +31,7 @@ type PingOptions struct {
// ForceNegotiate forces the client to re-negotiate the API version, even if // ForceNegotiate forces the client to re-negotiate the API version, even if
// API-version negotiation already happened. This option cannot be // API-version negotiation already happened. This option cannot be
// used if the client is configured with a fixed version using (using // used if the client is configured with a fixed version using (using
// [WithVersion] or [WithVersionFromEnv]). // [WithAPIVersion] or [WithAPIVersionFromEnv]).
// //
// This option has no effect if NegotiateAPIVersion is not set. // This option has no effect if NegotiateAPIVersion is not set.
ForceNegotiate bool ForceNegotiate bool