...

Source file src/go.etcd.io/etcd/server/v3/etcdserver/api/membership/member.go

Documentation: go.etcd.io/etcd/server/v3/etcdserver/api/membership

     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  	"strings"
    24  	"time"
    25  
    26  	"go.etcd.io/etcd/client/pkg/v3/types"
    27  )
    28  
    29  // RaftAttributes represents the raft related attributes of an etcd member.
    30  type RaftAttributes struct {
    31  	// PeerURLs is the list of peers in the raft cluster.
    32  	// TODO(philips): ensure these are URLs
    33  	PeerURLs []string `json:"peerURLs"`
    34  	// IsLearner indicates if the member is raft learner.
    35  	IsLearner bool `json:"isLearner,omitempty"`
    36  }
    37  
    38  // Attributes represents all the non-raft related attributes of an etcd member.
    39  type Attributes struct {
    40  	Name       string   `json:"name,omitempty"`
    41  	ClientURLs []string `json:"clientURLs,omitempty"`
    42  }
    43  
    44  type Member struct {
    45  	ID types.ID `json:"id"`
    46  	RaftAttributes
    47  	Attributes
    48  }
    49  
    50  // NewMember creates a Member without an ID and generates one based on the
    51  // cluster name, peer URLs, and time. This is used for bootstrapping/adding new member.
    52  func NewMember(name string, peerURLs types.URLs, clusterName string, now *time.Time) *Member {
    53  	memberId := computeMemberId(peerURLs, clusterName, now)
    54  	return newMember(name, peerURLs, memberId, false)
    55  }
    56  
    57  // NewMemberAsLearner creates a learner Member without an ID and generates one based on the
    58  // cluster name, peer URLs, and time. This is used for adding new learner member.
    59  func NewMemberAsLearner(name string, peerURLs types.URLs, clusterName string, now *time.Time) *Member {
    60  	memberId := computeMemberId(peerURLs, clusterName, now)
    61  	return newMember(name, peerURLs, memberId, true)
    62  }
    63  
    64  func computeMemberId(peerURLs types.URLs, clusterName string, now *time.Time) types.ID {
    65  	peerURLstrs := peerURLs.StringSlice()
    66  	sort.Strings(peerURLstrs)
    67  	joinedPeerUrls := strings.Join(peerURLstrs, "")
    68  	b := []byte(joinedPeerUrls)
    69  
    70  	b = append(b, []byte(clusterName)...)
    71  	if now != nil {
    72  		b = append(b, []byte(fmt.Sprintf("%d", now.Unix()))...)
    73  	}
    74  
    75  	hash := sha1.Sum(b)
    76  	return types.ID(binary.BigEndian.Uint64(hash[:8]))
    77  }
    78  
    79  func newMember(name string, peerURLs types.URLs, memberId types.ID, isLearner bool) *Member {
    80  	m := &Member{
    81  		RaftAttributes: RaftAttributes{
    82  			PeerURLs:  peerURLs.StringSlice(),
    83  			IsLearner: isLearner,
    84  		},
    85  		Attributes: Attributes{Name: name},
    86  		ID:         memberId,
    87  	}
    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.
    93  func (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  
   100  func (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  
   124  func (m *Member) IsStarted() bool {
   125  	return len(m.Name) != 0
   126  }
   127  
   128  // MembersByID implements sort by ID interface
   129  type MembersByID []*Member
   130  
   131  func (ms MembersByID) Len() int           { return len(ms) }
   132  func (ms MembersByID) Less(i, j int) bool { return ms[i].ID < ms[j].ID }
   133  func (ms MembersByID) Swap(i, j int)      { ms[i], ms[j] = ms[j], ms[i] }
   134  
   135  // MembersByPeerURLs implements sort by peer urls interface
   136  type MembersByPeerURLs []*Member
   137  
   138  func (ms MembersByPeerURLs) Len() int { return len(ms) }
   139  func (ms MembersByPeerURLs) Less(i, j int) bool {
   140  	return ms[i].PeerURLs[0] < ms[j].PeerURLs[0]
   141  }
   142  func (ms MembersByPeerURLs) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
   143  

View as plain text