client: client.Ping: allow ForceNegotiate with manual override

While a manual overridden version shouldn't perform automatic version
negotiation, the "ForceNegotiate" option could still be used to (re)
negotiate a version. This allows a client to be configured with an
initial API version, then triggered to perform API-version negotiation.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-11-14 14:52:14 +01:00
parent c151d52562
commit 6857132911
3 changed files with 20 additions and 11 deletions

View File

@@ -437,19 +437,28 @@ func TestNegotiateAPIVersionWithEmptyVersion(t *testing.T) {
// TestNegotiateAPIVersionWithFixedVersion asserts that initializing a client
// with a fixed version disables API-version negotiation
func TestNegotiateAPIVersionWithFixedVersion(t *testing.T) {
const customVersion = "1.50"
const (
customVersion = "1.50"
pingVersion = "1.49"
)
client, err := New(
WithAPIVersion(customVersion),
WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{"1.49"}}, "OK")),
WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{pingVersion}}, "OK")),
)
assert.NilError(t, err)
_, err = client.Ping(t.Context(), PingOptions{
NegotiateAPIVersion: true,
})
assert.NilError(t, err)
assert.Check(t, is.Equal(client.ClientVersion(), customVersion))
_, err = client.Ping(t.Context(), PingOptions{
NegotiateAPIVersion: true,
ForceNegotiate: true,
})
assert.NilError(t, err)
assert.Check(t, is.Equal(client.ClientVersion(), customVersion))
assert.Check(t, is.Equal(client.ClientVersion(), pingVersion))
}
// TestCustomAPIVersion tests initializing the client with a custom

View File

@@ -29,9 +29,8 @@ type PingOptions struct {
NegotiateAPIVersion bool
// ForceNegotiate forces the client to re-negotiate the API version, even if
// API-version negotiation already happened. This option cannot be
// used if the client is configured with a fixed version using (using
// [WithAPIVersion] or [WithAPIVersionFromEnv]).
// API-version negotiation already happened or it the client is configured
// with a fixed version (using [WithAPIVersion] or [WithAPIVersionFromEnv]).
//
// This option has no effect if NegotiateAPIVersion is not set.
ForceNegotiate bool
@@ -72,7 +71,8 @@ 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.manualOverride {
if (cli.manualOverride || cli.negotiated.Load()) && !options.ForceNegotiate {
// API version was already negotiated or manually set.
return cli.ping(ctx)
}
if !options.NegotiateAPIVersion && !cli.negotiateVersion {

View File

@@ -29,9 +29,8 @@ type PingOptions struct {
NegotiateAPIVersion bool
// ForceNegotiate forces the client to re-negotiate the API version, even if
// API-version negotiation already happened. This option cannot be
// used if the client is configured with a fixed version using (using
// [WithAPIVersion] or [WithAPIVersionFromEnv]).
// API-version negotiation already happened or it the client is configured
// with a fixed version (using [WithAPIVersion] or [WithAPIVersionFromEnv]).
//
// This option has no effect if NegotiateAPIVersion is not set.
ForceNegotiate bool
@@ -72,7 +71,8 @@ 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.manualOverride {
if (cli.manualOverride || cli.negotiated.Load()) && !options.ForceNegotiate {
// API version was already negotiated or manually set.
return cli.ping(ctx)
}
if !options.NegotiateAPIVersion && !cli.negotiateVersion {