From 00ee3e71069cfc99f4976ce58075806ae004f492 Mon Sep 17 00:00:00 2001 From: "shaun.thium" Date: Tue, 13 Sep 2016 11:42:51 -0700 Subject: [PATCH] client: add GetVersion method for retrieving etcdserver and etcdcluster version this adds a GetVersion method to the Client interface for retrieving information about the etcdserver and etcdcluster. --- client/client.go | 44 +++++++++++++++++++++++++++++++++++++++++++ client/client_test.go | 31 ++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/client/client.go b/client/client.go index 4c4d41eb9cf..65c901a041a 100644 --- a/client/client.go +++ b/client/client.go @@ -15,6 +15,7 @@ package client import ( + "encoding/json" "errors" "fmt" "io/ioutil" @@ -202,6 +203,9 @@ type Client interface { // returned SetEndpoints(eps []string) error + // GetVersion retrieves the current etcd server and cluster version + GetVersion(ctx context.Context) (*VersionResponse, error) + httpClient } @@ -440,6 +444,46 @@ func (c *httpClusterClient) AutoSync(ctx context.Context, interval time.Duration } } +type VersionResponse struct { + // ServerVersion represents the version of the current server + // that the client is running on. + ServerVersion string `json:"server_version"` + + // ClusterVersion represents the cluster architecture version + // of the current cluster. + ClusterVersion string `json:"cluster_version"` +} + +func (c *httpClusterClient) GetVersion(ctx context.Context) (*VersionResponse, error) { + act := &getAction{Prefix: "/version"} + + resp, body, err := c.Do(ctx, act) + if err != nil { + return nil, err + } + + switch resp.StatusCode { + case http.StatusOK: + if len(body) == 0 { + return nil, ErrEmptyBody + } + var m map[string]string + if err := json.Unmarshal(body, &m); err != nil { + return nil, ErrInvalidJSON + } + return &VersionResponse{ + ServerVersion: m["etcdserver"], + ClusterVersion: m["etcdcluster"], + }, nil + default: + var etcdErr Error + if err := json.Unmarshal(body, &etcdErr); err != nil { + return nil, ErrInvalidJSON + } + return nil, etcdErr + } +} + type roundTripResponse struct { resp *http.Response err error diff --git a/client/client_test.go b/client/client_test.go index aaf2bec476f..9012d949067 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -860,6 +860,37 @@ func TestHTTPClusterClientAutoSyncFail(t *testing.T) { } } +func TestHTTPClusterClientGetVersion(t *testing.T) { + body := []byte(`{"etcdserver":"2.3.2","etcdcluster":"2.3.0"}`) + cf := newStaticHTTPClientFactory([]staticHTTPResponse{ + { + resp: http.Response{StatusCode: http.StatusOK, Header: http.Header{"Content-Length": []string{"44"}}}, + body: body, + }, + }) + + hc := &httpClusterClient{ + clientFactory: cf, + rand: rand.New(rand.NewSource(0)), + } + err := hc.SetEndpoints([]string{"http://127.0.0.1:4003", "http://127.0.0.1:2379", "http://127.0.0.1:4001", "http://127.0.0.1:4002"}) + if err != nil { + t.Fatalf("unexpected error during setup: %#v", err) + } + + actual, err := hc.GetVersion(context.Background()) + if err != nil { + t.Errorf("non-nil error: %#v", err) + } + expected := &VersionResponse{ + ServerVersion: "2.3.2", + ClusterVersion: "2.3.0", + } + if !reflect.DeepEqual(expected, actual) { + t.Errorf("incorrect Response: want=%#v got=%#v", expected, actual) + } +} + // TestHTTPClusterClientSyncPinEndpoint tests that Sync() pins the endpoint when // it gets the exactly same member list as before. func TestHTTPClusterClientSyncPinEndpoint(t *testing.T) {