github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/state/raft/membership/cluster.go (about)

     1  package membership
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  
     7  	"github.com/coreos/etcd/raft/raftpb"
     8  	"github.com/docker/swarmkit/api"
     9  	"github.com/docker/swarmkit/watch"
    10  	"github.com/gogo/protobuf/proto"
    11  )
    12  
    13  var (
    14  	// ErrIDExists is thrown when a node wants to join the existing cluster but its ID already exists
    15  	ErrIDExists = errors.New("membership: can't add node to cluster, node id is a duplicate")
    16  	// ErrIDRemoved is thrown when a node tries to perform an operation on an existing cluster but was removed
    17  	ErrIDRemoved = errors.New("membership: node was removed during cluster lifetime")
    18  	// ErrIDNotFound is thrown when we try an operation on a member that does not exist in the cluster list
    19  	ErrIDNotFound = errors.New("membership: member not found in cluster list")
    20  	// ErrConfigChangeInvalid is thrown when a configuration change we received looks invalid in form
    21  	ErrConfigChangeInvalid = errors.New("membership: ConfChange type should be either AddNode, RemoveNode or UpdateNode")
    22  	// ErrCannotUnmarshalConfig is thrown when a node cannot unmarshal a configuration change
    23  	ErrCannotUnmarshalConfig = errors.New("membership: cannot unmarshal configuration change")
    24  	// ErrMemberRemoved is thrown when a node was removed from the cluster
    25  	ErrMemberRemoved = errors.New("raft: member was removed from the cluster")
    26  )
    27  
    28  // Cluster represents a set of active
    29  // raft Members
    30  type Cluster struct {
    31  	mu      sync.RWMutex
    32  	members map[uint64]*Member
    33  
    34  	// removed contains the list of removed Members,
    35  	// those ids cannot be reused
    36  	removed map[uint64]bool
    37  
    38  	PeersBroadcast *watch.Queue
    39  }
    40  
    41  // Member represents a raft Cluster Member
    42  type Member struct {
    43  	*api.RaftMember
    44  }
    45  
    46  // NewCluster creates a new Cluster neighbors list for a raft Member.
    47  func NewCluster() *Cluster {
    48  	// TODO(abronan): generate Cluster ID for federation
    49  
    50  	return &Cluster{
    51  		members:        make(map[uint64]*Member),
    52  		removed:        make(map[uint64]bool),
    53  		PeersBroadcast: watch.NewQueue(),
    54  	}
    55  }
    56  
    57  // Members returns the list of raft Members in the Cluster.
    58  func (c *Cluster) Members() map[uint64]*Member {
    59  	members := make(map[uint64]*Member)
    60  	c.mu.RLock()
    61  	for k, v := range c.members {
    62  		members[k] = v
    63  	}
    64  	c.mu.RUnlock()
    65  	return members
    66  }
    67  
    68  // Removed returns the list of raft Members removed from the Cluster.
    69  func (c *Cluster) Removed() []uint64 {
    70  	c.mu.RLock()
    71  	removed := make([]uint64, 0, len(c.removed))
    72  	for k := range c.removed {
    73  		removed = append(removed, k)
    74  	}
    75  	c.mu.RUnlock()
    76  	return removed
    77  }
    78  
    79  // GetMember returns informations on a given Member.
    80  func (c *Cluster) GetMember(id uint64) *Member {
    81  	c.mu.RLock()
    82  	defer c.mu.RUnlock()
    83  	return c.members[id]
    84  }
    85  
    86  func (c *Cluster) broadcastUpdate() {
    87  	peers := make([]*api.Peer, 0, len(c.members))
    88  	for _, m := range c.members {
    89  		peers = append(peers, &api.Peer{
    90  			NodeID: m.NodeID,
    91  			Addr:   m.Addr,
    92  		})
    93  	}
    94  	c.PeersBroadcast.Publish(peers)
    95  }
    96  
    97  // AddMember adds a node to the Cluster Memberlist.
    98  func (c *Cluster) AddMember(member *Member) error {
    99  	c.mu.Lock()
   100  	defer c.mu.Unlock()
   101  
   102  	if c.removed[member.RaftID] {
   103  		return ErrIDRemoved
   104  	}
   105  
   106  	c.members[member.RaftID] = member
   107  
   108  	c.broadcastUpdate()
   109  	return nil
   110  }
   111  
   112  // RemoveMember removes a node from the Cluster Memberlist, and adds it to
   113  // the removed list.
   114  func (c *Cluster) RemoveMember(id uint64) error {
   115  	c.mu.Lock()
   116  	defer c.mu.Unlock()
   117  	c.removed[id] = true
   118  
   119  	return c.clearMember(id)
   120  }
   121  
   122  // UpdateMember updates member address.
   123  func (c *Cluster) UpdateMember(id uint64, m *api.RaftMember) error {
   124  	c.mu.Lock()
   125  	defer c.mu.Unlock()
   126  
   127  	if c.removed[id] {
   128  		return ErrIDRemoved
   129  	}
   130  
   131  	oldMember, ok := c.members[id]
   132  	if !ok {
   133  		return ErrIDNotFound
   134  	}
   135  
   136  	if oldMember.NodeID != m.NodeID {
   137  		// Should never happen; this is a sanity check
   138  		return errors.New("node ID mismatch match on node update")
   139  	}
   140  
   141  	if oldMember.Addr == m.Addr {
   142  		// nothing to do
   143  		return nil
   144  	}
   145  	oldMember.RaftMember = m
   146  	c.broadcastUpdate()
   147  	return nil
   148  }
   149  
   150  // ClearMember removes a node from the Cluster Memberlist, but does NOT add it
   151  // to the removed list.
   152  func (c *Cluster) ClearMember(id uint64) error {
   153  	c.mu.Lock()
   154  	defer c.mu.Unlock()
   155  
   156  	return c.clearMember(id)
   157  }
   158  
   159  func (c *Cluster) clearMember(id uint64) error {
   160  	if _, ok := c.members[id]; ok {
   161  		delete(c.members, id)
   162  		c.broadcastUpdate()
   163  	}
   164  	return nil
   165  }
   166  
   167  // IsIDRemoved checks if a Member is in the remove set.
   168  func (c *Cluster) IsIDRemoved(id uint64) bool {
   169  	c.mu.RLock()
   170  	defer c.mu.RUnlock()
   171  	return c.removed[id]
   172  }
   173  
   174  // Clear resets the list of active Members and removed Members.
   175  func (c *Cluster) Clear() {
   176  	c.mu.Lock()
   177  
   178  	c.members = make(map[uint64]*Member)
   179  	c.removed = make(map[uint64]bool)
   180  	c.mu.Unlock()
   181  }
   182  
   183  // ValidateConfigurationChange takes a proposed ConfChange and
   184  // ensures that it is valid.
   185  func (c *Cluster) ValidateConfigurationChange(cc raftpb.ConfChange) error {
   186  	c.mu.Lock()
   187  	defer c.mu.Unlock()
   188  
   189  	if c.removed[cc.NodeID] {
   190  		return ErrIDRemoved
   191  	}
   192  	switch cc.Type {
   193  	case raftpb.ConfChangeAddNode:
   194  		if c.members[cc.NodeID] != nil {
   195  			return ErrIDExists
   196  		}
   197  	case raftpb.ConfChangeRemoveNode:
   198  		if c.members[cc.NodeID] == nil {
   199  			return ErrIDNotFound
   200  		}
   201  	case raftpb.ConfChangeUpdateNode:
   202  		if c.members[cc.NodeID] == nil {
   203  			return ErrIDNotFound
   204  		}
   205  	default:
   206  		return ErrConfigChangeInvalid
   207  	}
   208  	m := &api.RaftMember{}
   209  	if err := proto.Unmarshal(cc.Context, m); err != nil {
   210  		return ErrCannotUnmarshalConfig
   211  	}
   212  	return nil
   213  }