blob: 6de74d26f8d4bc06f1a43bddc3fecb305425e09f [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// 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
15package membership
16
17import (
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
29var (
30 plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "etcdserver/membership")
31)
32
33// RaftAttributes represents the raft related attributes of an etcd member.
34type 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.
41type Attributes struct {
42 Name string `json:"name,omitempty"`
43 ClientURLs []string `json:"clientURLs,omitempty"`
44}
45
46type 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.
54func 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.
78func (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
85func (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
106func (m *Member) IsStarted() bool {
107 return len(m.Name) != 0
108}
109
110// MembersByID implements sort by ID interface
111type MembersByID []*Member
112
113func (ms MembersByID) Len() int { return len(ms) }
114func (ms MembersByID) Less(i, j int) bool { return ms[i].ID < ms[j].ID }
115func (ms MembersByID) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
116
117// MembersByPeerURLs implements sort by peer urls interface
118type MembersByPeerURLs []*Member
119
120func (ms MembersByPeerURLs) Len() int { return len(ms) }
121func (ms MembersByPeerURLs) Less(i, j int) bool {
122 return ms[i].PeerURLs[0] < ms[j].PeerURLs[0]
123}
124func (ms MembersByPeerURLs) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }