blob: 896cb36aa452fcfa0d07c4741b94ffe269693198 [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// 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/pkg/capnslog"
26 "go.etcd.io/etcd/pkg/types"
27)
28
29var (
30 plog = capnslog.NewPackageLogger("go.etcd.io/etcd/v3", "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 // IsLearner indicates if the member is raft learner.
39 IsLearner bool `json:"isLearner,omitempty"`
40}
41
42// Attributes represents all the non-raft related attributes of an etcd member.
43type Attributes struct {
44 Name string `json:"name,omitempty"`
45 ClientURLs []string `json:"clientURLs,omitempty"`
46}
47
48type Member struct {
49 ID types.ID `json:"id"`
50 RaftAttributes
51 Attributes
52}
53
54// NewMember creates a Member without an ID and generates one based on the
55// cluster name, peer URLs, and time. This is used for bootstrapping/adding new member.
56func NewMember(name string, peerURLs types.URLs, clusterName string, now *time.Time) *Member {
57 return newMember(name, peerURLs, clusterName, now, false)
58}
59
60// NewMemberAsLearner creates a learner Member without an ID and generates one based on the
61// cluster name, peer URLs, and time. This is used for adding new learner member.
62func NewMemberAsLearner(name string, peerURLs types.URLs, clusterName string, now *time.Time) *Member {
63 return newMember(name, peerURLs, clusterName, now, true)
64}
65
66func newMember(name string, peerURLs types.URLs, clusterName string, now *time.Time, isLearner bool) *Member {
67 m := &Member{
68 RaftAttributes: RaftAttributes{
69 PeerURLs: peerURLs.StringSlice(),
70 IsLearner: isLearner,
71 },
72 Attributes: Attributes{Name: name},
73 }
74
75 var b []byte
76 sort.Strings(m.PeerURLs)
77 for _, p := range m.PeerURLs {
78 b = append(b, []byte(p)...)
79 }
80
81 b = append(b, []byte(clusterName)...)
82 if now != nil {
83 b = append(b, []byte(fmt.Sprintf("%d", now.Unix()))...)
84 }
85
86 hash := sha1.Sum(b)
87 m.ID = types.ID(binary.BigEndian.Uint64(hash[:8]))
88 return m
89}
90
91// PickPeerURL chooses a random address from a given Member's PeerURLs.
92// It will panic if there is no PeerURLs available in Member.
93func (m *Member) PickPeerURL() string {
94 if len(m.PeerURLs) == 0 {
95 panic("member should always have some peer url")
96 }
97 return m.PeerURLs[rand.Intn(len(m.PeerURLs))]
98}
99
100func (m *Member) Clone() *Member {
101 if m == nil {
102 return nil
103 }
104 mm := &Member{
105 ID: m.ID,
106 RaftAttributes: RaftAttributes{
107 IsLearner: m.IsLearner,
108 },
109 Attributes: Attributes{
110 Name: m.Name,
111 },
112 }
113 if m.PeerURLs != nil {
114 mm.PeerURLs = make([]string, len(m.PeerURLs))
115 copy(mm.PeerURLs, m.PeerURLs)
116 }
117 if m.ClientURLs != nil {
118 mm.ClientURLs = make([]string, len(m.ClientURLs))
119 copy(mm.ClientURLs, m.ClientURLs)
120 }
121 return mm
122}
123
124func (m *Member) IsStarted() bool {
125 return len(m.Name) != 0
126}
127
128// MembersByID implements sort by ID interface
129type MembersByID []*Member
130
131func (ms MembersByID) Len() int { return len(ms) }
132func (ms MembersByID) Less(i, j int) bool { return ms[i].ID < ms[j].ID }
133func (ms MembersByID) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
134
135// MembersByPeerURLs implements sort by peer urls interface
136type MembersByPeerURLs []*Member
137
138func (ms MembersByPeerURLs) Len() int { return len(ms) }
139func (ms MembersByPeerURLs) Less(i, j int) bool {
140 return ms[i].PeerURLs[0] < ms[j].PeerURLs[0]
141}
142func (ms MembersByPeerURLs) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }