etcd/client/members.go

159 lines
3.8 KiB
Go
Raw Normal View History

2014-10-25 20:49:35 +04:00
/*
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 (
2014-10-30 00:35:31 +03:00
"bytes"
2014-10-25 20:49:35 +04:00
"encoding/json"
"fmt"
"net/http"
"net/url"
"path"
"time"
"github.com/coreos/etcd/Godeps/_workspace/src/code.google.com/p/go.net/context"
"github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
"github.com/coreos/etcd/pkg/types"
2014-10-25 20:49:35 +04:00
)
var (
DefaultV2MembersPrefix = "/v2/members"
2014-10-25 20:49:35 +04:00
)
func NewMembersAPI(c httpActionDo, to time.Duration) MembersAPI {
return &httpMembersAPI{
client: c,
timeout: to,
2014-10-25 20:49:35 +04:00
}
}
type MembersAPI interface {
List() ([]httptypes.Member, error)
2014-10-30 00:35:31 +03:00
Add(peerURL string) (*httptypes.Member, error)
Remove(mID string) error
2014-10-25 20:49:35 +04:00
}
type httpMembersAPI struct {
client httpActionDo
timeout time.Duration
2014-10-25 20:49:35 +04:00
}
func (m *httpMembersAPI) List() ([]httptypes.Member, error) {
req := &membersAPIActionList{}
ctx, cancel := context.WithTimeout(context.Background(), m.timeout)
resp, body, err := m.client.Do(ctx, req)
cancel()
2014-10-25 20:49:35 +04:00
if err != nil {
return nil, err
}
if err := assertStatusCode(http.StatusOK, resp.StatusCode); err != nil {
2014-10-25 20:49:35 +04:00
return nil, err
}
var mCollection httptypes.MemberCollection
if err := json.Unmarshal(body, &mCollection); err != nil {
2014-10-25 20:49:35 +04:00
return nil, err
}
return []httptypes.Member(mCollection), nil
2014-10-25 20:49:35 +04:00
}
2014-10-30 00:35:31 +03:00
func (m *httpMembersAPI) Add(peerURL string) (*httptypes.Member, error) {
urls, err := types.NewURLs([]string{peerURL})
if err != nil {
return nil, err
}
req := &membersAPIActionAdd{peerURLs: urls}
ctx, cancel := context.WithTimeout(context.Background(), m.timeout)
resp, body, err := m.client.Do(ctx, req)
cancel()
2014-10-30 00:35:31 +03:00
if err != nil {
return nil, err
}
if err := assertStatusCode(http.StatusCreated, resp.StatusCode); err != nil {
2014-10-30 00:35:31 +03:00
return nil, err
}
var memb httptypes.Member
if err := json.Unmarshal(body, &memb); err != nil {
return nil, err
}
return &memb, nil
2014-10-25 20:49:35 +04:00
}
2014-10-30 00:35:31 +03:00
func (m *httpMembersAPI) Remove(memberID string) error {
req := &membersAPIActionRemove{memberID: memberID}
ctx, cancel := context.WithTimeout(context.Background(), m.timeout)
resp, _, err := m.client.Do(ctx, req)
cancel()
2014-10-30 00:35:31 +03:00
if err != nil {
return err
2014-10-25 20:49:35 +04:00
}
2014-10-30 00:35:31 +03:00
return assertStatusCode(http.StatusNoContent, resp.StatusCode)
2014-10-25 20:49:35 +04:00
}
type membersAPIActionList struct{}
func (l *membersAPIActionList) HTTPRequest(ep url.URL) *http.Request {
2014-10-31 21:44:28 +03:00
u := v2MembersURL(ep)
req, _ := http.NewRequest("GET", u.String(), nil)
2014-10-25 20:49:35 +04:00
return req
}
2014-10-30 00:35:31 +03:00
type membersAPIActionRemove struct {
memberID string
}
func (d *membersAPIActionRemove) HTTPRequest(ep url.URL) *http.Request {
2014-10-31 21:44:28 +03:00
u := v2MembersURL(ep)
u.Path = path.Join(u.Path, d.memberID)
req, _ := http.NewRequest("DELETE", u.String(), nil)
2014-10-30 00:35:31 +03:00
return req
}
type membersAPIActionAdd struct {
peerURLs types.URLs
2014-10-30 00:35:31 +03:00
}
func (a *membersAPIActionAdd) HTTPRequest(ep url.URL) *http.Request {
2014-10-31 21:44:28 +03:00
u := v2MembersURL(ep)
m := httptypes.MemberCreateRequest{PeerURLs: a.peerURLs}
2014-10-30 00:35:31 +03:00
b, _ := json.Marshal(&m)
2014-10-31 21:44:28 +03:00
req, _ := http.NewRequest("POST", u.String(), bytes.NewReader(b))
2014-10-30 00:35:31 +03:00
req.Header.Set("Content-Type", "application/json")
return req
}
func assertStatusCode(want, got int) (err error) {
if want != got {
err = fmt.Errorf("unexpected status code %d", got)
}
return err
}
2014-10-31 21:44:28 +03:00
// v2MembersURL add the necessary path to the provided endpoint
// to route requests to the default v2 members API.
func v2MembersURL(ep url.URL) *url.URL {
ep.Path = path.Join(ep.Path, DefaultV2MembersPrefix)
return &ep
}