cluster.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package etcdserver
  2. import (
  3. "crypto/sha1"
  4. "encoding/binary"
  5. "fmt"
  6. "math/rand"
  7. "net/url"
  8. "sort"
  9. "strings"
  10. "github.com/coreos/etcd/pkg/flags"
  11. "github.com/coreos/etcd/pkg/types"
  12. )
  13. // Cluster is a list of Members that belong to the same raft cluster
  14. type Cluster struct {
  15. id uint64
  16. members map[uint64]*Member
  17. }
  18. func NewCluster() *Cluster {
  19. return &Cluster{members: make(map[uint64]*Member)}
  20. }
  21. func (c Cluster) FindID(id uint64) *Member {
  22. return c.members[id]
  23. }
  24. func (c Cluster) FindName(name string) *Member {
  25. for _, m := range c.members {
  26. if m.Name == name {
  27. return m
  28. }
  29. }
  30. return nil
  31. }
  32. func (c Cluster) Add(m Member) error {
  33. if c.FindID(m.ID) != nil {
  34. return fmt.Errorf("Member exists with identical ID %v", m)
  35. }
  36. c.members[m.ID] = &m
  37. return nil
  38. }
  39. func (c *Cluster) AddSlice(mems []Member) error {
  40. for _, m := range mems {
  41. err := c.Add(m)
  42. if err != nil {
  43. return err
  44. }
  45. }
  46. return nil
  47. }
  48. // Pick chooses a random address from a given Member's addresses, and returns it as
  49. // an addressible URI. If the given member does not exist, an empty string is returned.
  50. func (c Cluster) Pick(id uint64) string {
  51. if m := c.FindID(id); m != nil {
  52. urls := m.PeerURLs
  53. if len(urls) == 0 {
  54. return ""
  55. }
  56. return urls[rand.Intn(len(urls))]
  57. }
  58. return ""
  59. }
  60. // Set parses command line sets of names to IPs formatted like:
  61. // mach0=http://1.1.1.1,mach0=http://2.2.2.2,mach0=http://1.1.1.1,mach1=http://2.2.2.2,mach1=http://3.3.3.3
  62. func (c *Cluster) Set(s string) error {
  63. *c = *NewCluster()
  64. v, err := url.ParseQuery(strings.Replace(s, ",", "&", -1))
  65. if err != nil {
  66. return err
  67. }
  68. for name, urls := range v {
  69. if len(urls) == 0 || urls[0] == "" {
  70. return fmt.Errorf("Empty URL given for %q", name)
  71. }
  72. m := newMember(name, types.URLs(*flags.NewURLsValue(strings.Join(urls, ","))), nil)
  73. err := c.Add(*m)
  74. if err != nil {
  75. return err
  76. }
  77. }
  78. return nil
  79. }
  80. func (c *Cluster) GenID(salt []byte) {
  81. mIDs := c.MemberIDs()
  82. b := make([]byte, 8*len(mIDs))
  83. for i, id := range mIDs {
  84. binary.BigEndian.PutUint64(b[8*i:], id)
  85. }
  86. hash := sha1.Sum(append(b, salt...))
  87. c.id = binary.BigEndian.Uint64(hash[:8])
  88. }
  89. func (c Cluster) String() string {
  90. sl := []string{}
  91. for _, m := range c.members {
  92. for _, u := range m.PeerURLs {
  93. sl = append(sl, fmt.Sprintf("%s=%s", m.Name, u))
  94. }
  95. }
  96. sort.Strings(sl)
  97. return strings.Join(sl, ",")
  98. }
  99. func (c Cluster) ID() uint64 { return c.id }
  100. func (c Cluster) Members() map[uint64]*Member { return c.members }
  101. func (c Cluster) MemberIDs() []uint64 {
  102. var ids []uint64
  103. for _, m := range c.members {
  104. ids = append(ids, m.ID)
  105. }
  106. sort.Sort(types.Uint64Slice(ids))
  107. return ids
  108. }
  109. // PeerURLs returns a list of all peer addresses. Each address is prefixed
  110. // with the scheme (currently "http://"). The returned list is sorted in
  111. // ascending lexicographical order.
  112. func (c Cluster) PeerURLs() []string {
  113. endpoints := make([]string, 0)
  114. for _, p := range c.members {
  115. for _, addr := range p.PeerURLs {
  116. endpoints = append(endpoints, addr)
  117. }
  118. }
  119. sort.Strings(endpoints)
  120. return endpoints
  121. }
  122. // ClientURLs returns a list of all client addresses. Each address is prefixed
  123. // with the scheme (currently "http://"). The returned list is sorted in
  124. // ascending lexicographical order.
  125. func (c Cluster) ClientURLs() []string {
  126. urls := make([]string, 0)
  127. for _, p := range c.members {
  128. for _, url := range p.ClientURLs {
  129. urls = append(urls, url)
  130. }
  131. }
  132. sort.Strings(urls)
  133. return urls
  134. }