mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
client: MembersAPI.List
This commit is contained in:
parent
00dcbf8bf7
commit
cba19e348f
155
client/members.go
Normal file
155
client/members.go
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
Copyright 2014 CoreOS, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultV2MembersPrefix = "/v2/admin/members"
|
||||
)
|
||||
|
||||
func NewMembersAPI(tr *http.Transport, ep string, to time.Duration) (MembersAPI, error) {
|
||||
u, err := url.Parse(ep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u.Path = path.Join(u.Path, DefaultV2MembersPrefix)
|
||||
|
||||
c := &httpClient{
|
||||
transport: tr,
|
||||
endpoint: *u,
|
||||
timeout: to,
|
||||
}
|
||||
|
||||
mAPI := httpMembersAPI{
|
||||
client: c,
|
||||
}
|
||||
|
||||
return &mAPI, nil
|
||||
}
|
||||
|
||||
type MembersAPI interface {
|
||||
List() ([]Member, error)
|
||||
}
|
||||
|
||||
type Member struct {
|
||||
ID uint64
|
||||
Name string
|
||||
PeerURLs []url.URL
|
||||
ClientURLs []url.URL
|
||||
}
|
||||
|
||||
func (m *Member) UnmarshalJSON(data []byte) (err error) {
|
||||
rm := struct {
|
||||
ID uint64
|
||||
Name string
|
||||
PeerURLs []string
|
||||
ClientURLs []string
|
||||
}{}
|
||||
|
||||
if err := json.Unmarshal(data, &rm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parseURLs := func(strs []string) ([]url.URL, error) {
|
||||
urls := make([]url.URL, len(strs))
|
||||
for i, s := range strs {
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
urls[i] = *u
|
||||
}
|
||||
|
||||
return urls, nil
|
||||
}
|
||||
|
||||
if m.PeerURLs, err = parseURLs(rm.PeerURLs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.ClientURLs, err = parseURLs(rm.ClientURLs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.ID = rm.ID
|
||||
m.Name = rm.Name
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type membersCollection struct {
|
||||
Members []Member
|
||||
}
|
||||
|
||||
type httpMembersAPI struct {
|
||||
client *httpClient
|
||||
}
|
||||
|
||||
func (m *httpMembersAPI) List() ([]Member, error) {
|
||||
httpresp, body, err := m.client.doWithTimeout(&membersAPIActionList{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mResponse := httpMembersAPIResponse{
|
||||
code: httpresp.StatusCode,
|
||||
body: body,
|
||||
}
|
||||
|
||||
if err = mResponse.err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mCollection membersCollection
|
||||
if err = mResponse.unmarshalBody(&mCollection); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mCollection.Members, nil
|
||||
}
|
||||
|
||||
type httpMembersAPIResponse struct {
|
||||
code int
|
||||
body []byte
|
||||
}
|
||||
|
||||
func (r *httpMembersAPIResponse) err() (err error) {
|
||||
if r.code != http.StatusOK {
|
||||
err = fmt.Errorf("unrecognized status code %d", r.code)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *httpMembersAPIResponse) unmarshalBody(dst interface{}) (err error) {
|
||||
return json.Unmarshal(r.body, dst)
|
||||
}
|
||||
|
||||
type membersAPIActionList struct{}
|
||||
|
||||
func (l *membersAPIActionList) httpRequest(ep url.URL) *http.Request {
|
||||
req, _ := http.NewRequest("GET", ep.String(), nil)
|
||||
return req
|
||||
}
|
168
client/members_test.go
Normal file
168
client/members_test.go
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
Copyright 2014 CoreOS, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMembersAPIListAction(t *testing.T) {
|
||||
ep := url.URL{Scheme: "http", Host: "example.com/v2/admin/members"}
|
||||
wantURL := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "example.com",
|
||||
Path: "/v2/admin/members",
|
||||
}
|
||||
|
||||
act := &membersAPIActionList{}
|
||||
got := *act.httpRequest(ep)
|
||||
err := assertResponse(got, wantURL, http.Header{}, nil)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMembersAPIUnmarshalMember(t *testing.T) {
|
||||
tests := []struct {
|
||||
body []byte
|
||||
wantMember Member
|
||||
wantError bool
|
||||
}{
|
||||
// no URLs, just check ID & Name
|
||||
{
|
||||
body: []byte(`{"id": 1, "name": "dungarees"}`),
|
||||
wantMember: Member{ID: 1, Name: "dungarees", PeerURLs: []url.URL{}, ClientURLs: []url.URL{}},
|
||||
},
|
||||
|
||||
// both client and peer URLs
|
||||
{
|
||||
body: []byte(`{"peerURLs": ["http://127.0.0.1:4001"], "clientURLs": ["http://127.0.0.1:4001"]}`),
|
||||
wantMember: Member{
|
||||
PeerURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:4001"},
|
||||
},
|
||||
ClientURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:4001"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// multiple peer URLs
|
||||
{
|
||||
body: []byte(`{"peerURLs": ["http://127.0.0.1:4001", "https://example.com"]}`),
|
||||
wantMember: Member{
|
||||
PeerURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:4001"},
|
||||
{Scheme: "https", Host: "example.com"},
|
||||
},
|
||||
ClientURLs: []url.URL{},
|
||||
},
|
||||
},
|
||||
|
||||
// multiple client URLs
|
||||
{
|
||||
body: []byte(`{"clientURLs": ["http://127.0.0.1:4001", "https://example.com"]}`),
|
||||
wantMember: Member{
|
||||
PeerURLs: []url.URL{},
|
||||
ClientURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:4001"},
|
||||
{Scheme: "https", Host: "example.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// invalid JSON
|
||||
{
|
||||
body: []byte(`{"peerU`),
|
||||
wantError: true,
|
||||
},
|
||||
|
||||
// valid JSON, invalid URL
|
||||
{
|
||||
body: []byte(`{"peerURLs": [":"]}`),
|
||||
wantError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
got := Member{}
|
||||
err := json.Unmarshal(tt.body, &got)
|
||||
if tt.wantError != (err != nil) {
|
||||
t.Errorf("#%d: want error %t, got %v", i, tt.wantError, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.wantMember, got) {
|
||||
t.Errorf("#%d: incorrect output: want=%#v, got=%#v", i, tt.wantMember, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMembersAPIUnmarshalMembers(t *testing.T) {
|
||||
body := []byte(`{"members":[{"id":176869799018424574,"peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":297577273835923749,"peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":10666918107976480891,"peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`)
|
||||
|
||||
want := membersCollection{
|
||||
Members: []Member{
|
||||
{
|
||||
ID: 176869799018424574,
|
||||
Name: "node3",
|
||||
PeerURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:7003"},
|
||||
},
|
||||
ClientURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:4003"},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 297577273835923749,
|
||||
Name: "node1",
|
||||
PeerURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:2380"},
|
||||
{Scheme: "http", Host: "127.0.0.1:7001"},
|
||||
},
|
||||
ClientURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:2379"},
|
||||
{Scheme: "http", Host: "127.0.0.1:4001"},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 10666918107976480891,
|
||||
Name: "node2",
|
||||
PeerURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:7002"},
|
||||
},
|
||||
ClientURLs: []url.URL{
|
||||
{Scheme: "http", Host: "127.0.0.1:4002"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
got := membersCollection{}
|
||||
err := json.Unmarshal(body, &got)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Errorf("Incorrect output: want=%#v, got=%#v", want, got)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user