members.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. Copyright 2014 CoreOS, Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package client
  14. import (
  15. "bytes"
  16. "encoding/json"
  17. "fmt"
  18. "net/http"
  19. "net/url"
  20. "path"
  21. "time"
  22. "github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
  23. "github.com/coreos/etcd/pkg/types"
  24. )
  25. var (
  26. DefaultV2MembersPrefix = "/v2/members"
  27. )
  28. func NewMembersAPI(tr *http.Transport, ep string, to time.Duration) (MembersAPI, error) {
  29. u, err := url.Parse(ep)
  30. if err != nil {
  31. return nil, err
  32. }
  33. u.Path = path.Join(u.Path, DefaultV2MembersPrefix)
  34. c := &httpClient{
  35. transport: tr,
  36. endpoint: *u,
  37. timeout: to,
  38. }
  39. mAPI := httpMembersAPI{
  40. client: c,
  41. }
  42. return &mAPI, nil
  43. }
  44. type MembersAPI interface {
  45. List() ([]httptypes.Member, error)
  46. Add(peerURL string) (*httptypes.Member, error)
  47. Remove(mID string) error
  48. }
  49. type httpMembersAPI struct {
  50. client *httpClient
  51. }
  52. func (m *httpMembersAPI) List() ([]httptypes.Member, error) {
  53. code, body, err := m.client.doWithTimeout(&membersAPIActionList{})
  54. if err != nil {
  55. return nil, err
  56. }
  57. if err := assertStatusCode(http.StatusOK, code); err != nil {
  58. return nil, err
  59. }
  60. var mCollection httptypes.MemberCollection
  61. if err := json.Unmarshal(body, &mCollection); err != nil {
  62. return nil, err
  63. }
  64. return []httptypes.Member(mCollection), nil
  65. }
  66. func (m *httpMembersAPI) Add(peerURL string) (*httptypes.Member, error) {
  67. urls, err := types.NewURLs([]string{peerURL})
  68. if err != nil {
  69. return nil, err
  70. }
  71. req := &membersAPIActionAdd{peerURLs: urls}
  72. code, body, err := m.client.doWithTimeout(req)
  73. if err != nil {
  74. return nil, err
  75. }
  76. if err := assertStatusCode(http.StatusCreated, code); err != nil {
  77. return nil, err
  78. }
  79. var memb httptypes.Member
  80. if err := json.Unmarshal(body, &memb); err != nil {
  81. return nil, err
  82. }
  83. return &memb, nil
  84. }
  85. func (m *httpMembersAPI) Remove(memberID string) error {
  86. req := &membersAPIActionRemove{memberID: memberID}
  87. code, _, err := m.client.doWithTimeout(req)
  88. if err != nil {
  89. return err
  90. }
  91. return assertStatusCode(http.StatusNoContent, code)
  92. }
  93. type membersAPIActionList struct{}
  94. func (l *membersAPIActionList) httpRequest(ep url.URL) *http.Request {
  95. req, _ := http.NewRequest("GET", ep.String(), nil)
  96. return req
  97. }
  98. type membersAPIActionRemove struct {
  99. memberID string
  100. }
  101. func (d *membersAPIActionRemove) httpRequest(ep url.URL) *http.Request {
  102. ep.Path = path.Join(ep.Path, d.memberID)
  103. req, _ := http.NewRequest("DELETE", ep.String(), nil)
  104. return req
  105. }
  106. type membersAPIActionAdd struct {
  107. peerURLs types.URLs
  108. }
  109. func (a *membersAPIActionAdd) httpRequest(ep url.URL) *http.Request {
  110. m := httptypes.MemberCreateRequest{PeerURLs: a.peerURLs}
  111. b, _ := json.Marshal(&m)
  112. req, _ := http.NewRequest("POST", ep.String(), bytes.NewReader(b))
  113. req.Header.Set("Content-Type", "application/json")
  114. return req
  115. }
  116. func assertStatusCode(want, got int) (err error) {
  117. if want != got {
  118. err = fmt.Errorf("unexpected status code %d", got)
  119. }
  120. return err
  121. }