go.etcd.io/etcd@v3.3.27+incompatible/etcdserver/membership/member.go (about) 1 // Copyright 2015 The etcd Authors 2 // 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package membership 16 17 import ( 18 "crypto/sha1" 19 "encoding/binary" 20 "fmt" 21 "math/rand" 22 "sort" 23 "time" 24 25 "github.com/coreos/etcd/pkg/types" 26 "github.com/coreos/pkg/capnslog" 27 ) 28 29 var ( 30 plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "etcdserver/membership") 31 ) 32 33 // RaftAttributes represents the raft related attributes of an etcd member. 34 type RaftAttributes struct { 35 // PeerURLs is the list of peers in the raft cluster. 36 // TODO(philips): ensure these are URLs 37 PeerURLs []string `json:"peerURLs"` 38 } 39 40 // Attributes represents all the non-raft related attributes of an etcd member. 41 type Attributes struct { 42 Name string `json:"name,omitempty"` 43 ClientURLs []string `json:"clientURLs,omitempty"` 44 } 45 46 type Member struct { 47 ID types.ID `json:"id"` 48 RaftAttributes 49 Attributes 50 } 51 52 // NewMember creates a Member without an ID and generates one based on the 53 // cluster name, peer URLs, and time. This is used for bootstrapping/adding new member. 54 func NewMember(name string, peerURLs types.URLs, clusterName string, now *time.Time) *Member { 55 m := &Member{ 56 RaftAttributes: RaftAttributes{PeerURLs: peerURLs.StringSlice()}, 57 Attributes: Attributes{Name: name}, 58 } 59 60 var b []byte 61 sort.Strings(m.PeerURLs) 62 for _, p := range m.PeerURLs { 63 b = append(b, []byte(p)...) 64 } 65 66 b = append(b, []byte(clusterName)...) 67 if now != nil { 68 b = append(b, []byte(fmt.Sprintf("%d", now.Unix()))...) 69 } 70 71 hash := sha1.Sum(b) 72 m.ID = types.ID(binary.BigEndian.Uint64(hash[:8])) 73 return m 74 } 75 76 // PickPeerURL chooses a random address from a given Member's PeerURLs. 77 // It will panic if there is no PeerURLs available in Member. 78 func (m *Member) PickPeerURL() string { 79 if len(m.PeerURLs) == 0 { 80 plog.Panicf("member should always have some peer url") 81 } 82 return m.PeerURLs[rand.Intn(len(m.PeerURLs))] 83 } 84 85 func (m *Member) Clone() *Member { 86 if m == nil { 87 return nil 88 } 89 mm := &Member{ 90 ID: m.ID, 91 Attributes: Attributes{ 92 Name: m.Name, 93 }, 94 } 95 if m.PeerURLs != nil { 96 mm.PeerURLs = make([]string, len(m.PeerURLs)) 97 copy(mm.PeerURLs, m.PeerURLs) 98 } 99 if m.ClientURLs != nil { 100 mm.ClientURLs = make([]string, len(m.ClientURLs)) 101 copy(mm.ClientURLs, m.ClientURLs) 102 } 103 return mm 104 } 105 106 func (m *Member) IsStarted() bool { 107 return len(m.Name) != 0 108 } 109 110 // MembersByID implements sort by ID interface 111 type MembersByID []*Member 112 113 func (ms MembersByID) Len() int { return len(ms) } 114 func (ms MembersByID) Less(i, j int) bool { return ms[i].ID < ms[j].ID } 115 func (ms MembersByID) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] } 116 117 // MembersByPeerURLs implements sort by peer urls interface 118 type MembersByPeerURLs []*Member 119 120 func (ms MembersByPeerURLs) Len() int { return len(ms) } 121 func (ms MembersByPeerURLs) Less(i, j int) bool { 122 return ms[i].PeerURLs[0] < ms[j].PeerURLs[0] 123 } 124 func (ms MembersByPeerURLs) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }