Browse code

Merge pull request #51530 from thaJeztah/allow_renegotiate

client: client.Ping: allow ForceNegotiate with manual override

Sebastiaan van Stijn authored on 2025/11/15 04:07:27
Showing 3 changed files
... ...
@@ -437,19 +437,28 @@ func TestNegotiateAPIVersionWithEmptyVersion(t *testing.T) {
437 437
 // TestNegotiateAPIVersionWithFixedVersion asserts that initializing a client
438 438
 // with a fixed version disables API-version negotiation
439 439
 func TestNegotiateAPIVersionWithFixedVersion(t *testing.T) {
440
-	const customVersion = "1.50"
440
+	const (
441
+		customVersion = "1.50"
442
+		pingVersion   = "1.49"
443
+	)
441 444
 	client, err := New(
442 445
 		WithAPIVersion(customVersion),
443
-		WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{"1.49"}}, "OK")),
446
+		WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{pingVersion}}, "OK")),
444 447
 	)
445 448
 	assert.NilError(t, err)
446 449
 
447 450
 	_, err = client.Ping(t.Context(), PingOptions{
448 451
 		NegotiateAPIVersion: true,
449
-		ForceNegotiate:      true,
450 452
 	})
451 453
 	assert.NilError(t, err)
452 454
 	assert.Check(t, is.Equal(client.ClientVersion(), customVersion))
455
+
456
+	_, err = client.Ping(t.Context(), PingOptions{
457
+		NegotiateAPIVersion: true,
458
+		ForceNegotiate:      true,
459
+	})
460
+	assert.NilError(t, err)
461
+	assert.Check(t, is.Equal(client.ClientVersion(), pingVersion))
453 462
 }
454 463
 
455 464
 func TestClientRedirect(t *testing.T) {
... ...
@@ -29,9 +29,8 @@ type PingOptions struct {
29 29
 	NegotiateAPIVersion bool
30 30
 
31 31
 	// ForceNegotiate forces the client to re-negotiate the API version, even if
32
-	// API-version negotiation already happened. This option cannot be
33
-	// used if the client is configured with a fixed version using (using
34
-	// [WithAPIVersion] or [WithAPIVersionFromEnv]).
32
+	// API-version negotiation already happened or it the client is configured
33
+	// with a fixed version (using [WithAPIVersion] or [WithAPIVersionFromEnv]).
35 34
 	//
36 35
 	// This option has no effect if NegotiateAPIVersion is not set.
37 36
 	ForceNegotiate bool
... ...
@@ -72,7 +71,8 @@ type SwarmStatus struct {
72 72
 // for other non-success status codes, failing to connect to the API, or failing
73 73
 // to parse the API response.
74 74
 func (cli *Client) Ping(ctx context.Context, options PingOptions) (PingResult, error) {
75
-	if cli.manualOverride {
75
+	if (cli.manualOverride || cli.negotiated.Load()) && !options.ForceNegotiate {
76
+		// API version was already negotiated or manually set.
76 77
 		return cli.ping(ctx)
77 78
 	}
78 79
 	if !options.NegotiateAPIVersion && !cli.negotiateVersion {
... ...
@@ -29,9 +29,8 @@ type PingOptions struct {
29 29
 	NegotiateAPIVersion bool
30 30
 
31 31
 	// ForceNegotiate forces the client to re-negotiate the API version, even if
32
-	// API-version negotiation already happened. This option cannot be
33
-	// used if the client is configured with a fixed version using (using
34
-	// [WithAPIVersion] or [WithAPIVersionFromEnv]).
32
+	// API-version negotiation already happened or it the client is configured
33
+	// with a fixed version (using [WithAPIVersion] or [WithAPIVersionFromEnv]).
35 34
 	//
36 35
 	// This option has no effect if NegotiateAPIVersion is not set.
37 36
 	ForceNegotiate bool
... ...
@@ -72,7 +71,8 @@ type SwarmStatus struct {
72 72
 // for other non-success status codes, failing to connect to the API, or failing
73 73
 // to parse the API response.
74 74
 func (cli *Client) Ping(ctx context.Context, options PingOptions) (PingResult, error) {
75
-	if cli.manualOverride {
75
+	if (cli.manualOverride || cli.negotiated.Load()) && !options.ForceNegotiate {
76
+		// API version was already negotiated or manually set.
76 77
 		return cli.ping(ctx)
77 78
 	}
78 79
 	if !options.NegotiateAPIVersion && !cli.negotiateVersion {