Przeglądaj źródła

client: Ping(): add handling for swarm status headers

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 3 lat temu
rodzic
commit
1e645fb70f
4 zmienionych plików z 38 dodań i 0 usunięć
  1. 10 0
      api/types/swarm/swarm.go
  2. 9 0
      api/types/types.go
  3. 9 0
      client/ping.go
  4. 10 0
      client/ping_test.go

+ 10 - 0
api/types/swarm/swarm.go

@@ -213,6 +213,16 @@ type Info struct {
 	Warnings []string `json:",omitempty"`
 	Warnings []string `json:",omitempty"`
 }
 }
 
 
+// Status provides information about the current swarm status and role,
+// obtained from the "Swarm" header in the API response.
+type Status struct {
+	// NodeState represents the state of the node.
+	NodeState LocalNodeState
+
+	// ControlAvailable indicates if the node is a swarm manager.
+	ControlAvailable bool
+}
+
 // Peer represents a peer.
 // Peer represents a peer.
 type Peer struct {
 type Peer struct {
 	NodeID string
 	NodeID string

+ 9 - 0
api/types/types.go

@@ -188,6 +188,15 @@ type Ping struct {
 	OSType         string
 	OSType         string
 	Experimental   bool
 	Experimental   bool
 	BuilderVersion BuilderVersion
 	BuilderVersion BuilderVersion
+
+	// SwarmStatus provides information about the current swarm status of the
+	// engine, obtained from the "Swarm" header in the API response.
+	//
+	// It can be a nil struct if the API version does not provide this header
+	// in the ping response, or if an error occurred, in which case the client
+	// should use other ways to get the current swarm status, such as the /swarm
+	// endpoint.
+	SwarmStatus *swarm.Status
 }
 }
 
 
 // ComponentVersion describes the version information for a specific component.
 // ComponentVersion describes the version information for a specific component.

+ 9 - 0
client/ping.go

@@ -4,8 +4,10 @@ import (
 	"context"
 	"context"
 	"net/http"
 	"net/http"
 	"path"
 	"path"
+	"strings"
 
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/swarm"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/errdefs"
 )
 )
 
 
@@ -61,6 +63,13 @@ func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) {
 	if bv := resp.header.Get("Builder-Version"); bv != "" {
 	if bv := resp.header.Get("Builder-Version"); bv != "" {
 		ping.BuilderVersion = types.BuilderVersion(bv)
 		ping.BuilderVersion = types.BuilderVersion(bv)
 	}
 	}
+	if si := resp.header.Get("Swarm"); si != "" {
+		parts := strings.SplitN(si, "/", 2)
+		ping.SwarmStatus = &swarm.Status{
+			NodeState:        swarm.LocalNodeState(parts[0]),
+			ControlAvailable: len(parts) == 2 && parts[1] == "manager",
+		}
+	}
 	err := cli.checkResponseErr(resp)
 	err := cli.checkResponseErr(resp)
 	return ping, errdefs.FromStatusCode(err, resp.statusCode)
 	return ping, errdefs.FromStatusCode(err, resp.statusCode)
 }
 }

+ 10 - 0
client/ping_test.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
+	"github.com/docker/docker/api/types/swarm"
 	"gotest.tools/v3/assert"
 	"gotest.tools/v3/assert"
 	is "gotest.tools/v3/assert/cmp"
 	is "gotest.tools/v3/assert/cmp"
 )
 )
@@ -25,6 +26,7 @@ func TestPingFail(t *testing.T) {
 				resp.Header = http.Header{}
 				resp.Header = http.Header{}
 				resp.Header.Set("API-Version", "awesome")
 				resp.Header.Set("API-Version", "awesome")
 				resp.Header.Set("Docker-Experimental", "true")
 				resp.Header.Set("Docker-Experimental", "true")
+				resp.Header.Set("Swarm", "inactive")
 			}
 			}
 			resp.Body = io.NopCloser(strings.NewReader("some error with the server"))
 			resp.Body = io.NopCloser(strings.NewReader("some error with the server"))
 			return resp, nil
 			return resp, nil
@@ -35,12 +37,15 @@ func TestPingFail(t *testing.T) {
 	assert.ErrorContains(t, err, "some error with the server")
 	assert.ErrorContains(t, err, "some error with the server")
 	assert.Check(t, is.Equal(false, ping.Experimental))
 	assert.Check(t, is.Equal(false, ping.Experimental))
 	assert.Check(t, is.Equal("", ping.APIVersion))
 	assert.Check(t, is.Equal("", ping.APIVersion))
+	var si *swarm.Status
+	assert.Check(t, is.Equal(si, ping.SwarmStatus))
 
 
 	withHeader = true
 	withHeader = true
 	ping2, err := client.Ping(context.Background())
 	ping2, err := client.Ping(context.Background())
 	assert.ErrorContains(t, err, "some error with the server")
 	assert.ErrorContains(t, err, "some error with the server")
 	assert.Check(t, is.Equal(true, ping2.Experimental))
 	assert.Check(t, is.Equal(true, ping2.Experimental))
 	assert.Check(t, is.Equal("awesome", ping2.APIVersion))
 	assert.Check(t, is.Equal("awesome", ping2.APIVersion))
+	assert.Check(t, is.Equal(swarm.Status{NodeState: "inactive"}, *ping2.SwarmStatus))
 }
 }
 
 
 // TestPingWithError tests the case where there is a protocol error in the ping.
 // TestPingWithError tests the case where there is a protocol error in the ping.
@@ -52,6 +57,7 @@ func TestPingWithError(t *testing.T) {
 			resp.Header = http.Header{}
 			resp.Header = http.Header{}
 			resp.Header.Set("API-Version", "awesome")
 			resp.Header.Set("API-Version", "awesome")
 			resp.Header.Set("Docker-Experimental", "true")
 			resp.Header.Set("Docker-Experimental", "true")
+			resp.Header.Set("Swarm", "active/manager")
 			resp.Body = io.NopCloser(strings.NewReader("some error with the server"))
 			resp.Body = io.NopCloser(strings.NewReader("some error with the server"))
 			return resp, errors.New("some error")
 			return resp, errors.New("some error")
 		}),
 		}),
@@ -61,6 +67,8 @@ func TestPingWithError(t *testing.T) {
 	assert.ErrorContains(t, err, "some error")
 	assert.ErrorContains(t, err, "some error")
 	assert.Check(t, is.Equal(false, ping.Experimental))
 	assert.Check(t, is.Equal(false, ping.Experimental))
 	assert.Check(t, is.Equal("", ping.APIVersion))
 	assert.Check(t, is.Equal("", ping.APIVersion))
+	var si *swarm.Status
+	assert.Check(t, is.Equal(si, ping.SwarmStatus))
 }
 }
 
 
 // TestPingSuccess tests that we are able to get the expected API headers/ping
 // TestPingSuccess tests that we are able to get the expected API headers/ping
@@ -72,6 +80,7 @@ func TestPingSuccess(t *testing.T) {
 			resp.Header = http.Header{}
 			resp.Header = http.Header{}
 			resp.Header.Set("API-Version", "awesome")
 			resp.Header.Set("API-Version", "awesome")
 			resp.Header.Set("Docker-Experimental", "true")
 			resp.Header.Set("Docker-Experimental", "true")
+			resp.Header.Set("Swarm", "active/manager")
 			resp.Body = io.NopCloser(strings.NewReader("OK"))
 			resp.Body = io.NopCloser(strings.NewReader("OK"))
 			return resp, nil
 			return resp, nil
 		}),
 		}),
@@ -80,6 +89,7 @@ func TestPingSuccess(t *testing.T) {
 	assert.NilError(t, err)
 	assert.NilError(t, err)
 	assert.Check(t, is.Equal(true, ping.Experimental))
 	assert.Check(t, is.Equal(true, ping.Experimental))
 	assert.Check(t, is.Equal("awesome", ping.APIVersion))
 	assert.Check(t, is.Equal("awesome", ping.APIVersion))
+	assert.Check(t, is.Equal(swarm.Status{NodeState: "active", ControlAvailable: true}, *ping.SwarmStatus))
 }
 }
 
 
 // TestPingHeadFallback tests that the client falls back to GET if HEAD fails.
 // TestPingHeadFallback tests that the client falls back to GET if HEAD fails.