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 }