raft.cluster was throwing an error when there was no leader in the network. Fixed the same.

added nodeActive attribute to the api response which indicates if the node is active in raft cluster.
added error handling for other apis
This commit is contained in:
vsmk98 2020-01-29 17:41:37 +08:00
parent 956d7747cf
commit 48ffc86336
2 changed files with 67 additions and 10 deletions

View File

@ -1,5 +1,10 @@
package raft package raft
import (
"errors"
"github.com/coreos/etcd/pkg/types"
)
type RaftNodeInfo struct { type RaftNodeInfo struct {
ClusterSize int `json:"clusterSize"` ClusterSize int `json:"clusterSize"`
Role string `json:"role"` Role string `json:"role"`
@ -19,22 +24,49 @@ func NewPublicRaftAPI(raftService *RaftService) *PublicRaftAPI {
} }
func (s *PublicRaftAPI) Role() string { func (s *PublicRaftAPI) Role() string {
if err := s.checkIfNodeInCluster(); err != nil {
return ""
}
_, err := s.raftService.raftProtocolManager.LeaderAddress()
if err != nil {
return ""
}
return s.raftService.raftProtocolManager.NodeInfo().Role return s.raftService.raftProtocolManager.NodeInfo().Role
} }
// helper function to check if self node is part of cluster
func (s *PublicRaftAPI) checkIfNodeInCluster() error {
if s.raftService.raftProtocolManager.IsIDRemoved(uint64(s.raftService.raftProtocolManager.raftId)) {
return errors.New("node not part of raft cluster. operations not allowed")
}
return nil
}
func (s *PublicRaftAPI) AddPeer(enodeId string) (uint16, error) { func (s *PublicRaftAPI) AddPeer(enodeId string) (uint16, error) {
if err := s.checkIfNodeInCluster(); err != nil {
return 0, err
}
return s.raftService.raftProtocolManager.ProposeNewPeer(enodeId, false) return s.raftService.raftProtocolManager.ProposeNewPeer(enodeId, false)
} }
func (s *PublicRaftAPI) AddLearner(enodeId string) (uint16, error) { func (s *PublicRaftAPI) AddLearner(enodeId string) (uint16, error) {
if err := s.checkIfNodeInCluster(); err != nil {
return 0, err
}
return s.raftService.raftProtocolManager.ProposeNewPeer(enodeId, true) return s.raftService.raftProtocolManager.ProposeNewPeer(enodeId, true)
} }
func (s *PublicRaftAPI) PromoteToPeer(raftId uint16) (bool, error) { func (s *PublicRaftAPI) PromoteToPeer(raftId uint16) (bool, error) {
if err := s.checkIfNodeInCluster(); err != nil {
return false, err
}
return s.raftService.raftProtocolManager.PromoteToPeer(raftId) return s.raftService.raftProtocolManager.PromoteToPeer(raftId)
} }
func (s *PublicRaftAPI) RemovePeer(raftId uint16) error { func (s *PublicRaftAPI) RemovePeer(raftId uint16) error {
if err := s.checkIfNodeInCluster(); err != nil {
return err
}
return s.raftService.raftProtocolManager.ProposePeerRemoval(raftId) return s.raftService.raftProtocolManager.ProposePeerRemoval(raftId)
} }
@ -48,33 +80,57 @@ func (s *PublicRaftAPI) Leader() (string, error) {
} }
func (s *PublicRaftAPI) Cluster() ([]ClusterInfo, error) { func (s *PublicRaftAPI) Cluster() ([]ClusterInfo, error) {
// check if the node has already been removed from cluster
// if yes return nil
if err := s.checkIfNodeInCluster(); err != nil {
return []ClusterInfo{}, nil
}
nodeInfo := s.raftService.raftProtocolManager.NodeInfo() nodeInfo := s.raftService.raftProtocolManager.NodeInfo()
if nodeInfo.Role == "" { if nodeInfo.Role == "" {
return []ClusterInfo{}, nil return []ClusterInfo{}, nil
} }
noLeader := false
leaderAddr, err := s.raftService.raftProtocolManager.LeaderAddress() leaderAddr, err := s.raftService.raftProtocolManager.LeaderAddress()
if err != nil { if err != nil {
if err == errNoLeaderElected && s.Role() == "" { noLeader = true
if s.raftService.raftProtocolManager.NodeInfo().Role == "" {
return []ClusterInfo{}, nil return []ClusterInfo{}, nil
} }
return []ClusterInfo{}, err
} }
peerAddresses := append(nodeInfo.PeerAddresses, nodeInfo.Address) peerAddresses := append(nodeInfo.PeerAddresses, nodeInfo.Address)
clustInfo := make([]ClusterInfo, len(peerAddresses)) clustInfo := make([]ClusterInfo, len(peerAddresses))
for i, a := range peerAddresses { for i, a := range peerAddresses {
role := "" role := ""
if a.RaftId == leaderAddr.RaftId { if !noLeader {
role = "minter" if a.RaftId == leaderAddr.RaftId {
} else if s.raftService.raftProtocolManager.isLearner(a.RaftId) { role = "minter"
role = "learner" } else if s.raftService.raftProtocolManager.isLearner(a.RaftId) {
} else if s.raftService.raftProtocolManager.isVerifier(a.RaftId) { role = "learner"
role = "verifier" } else if s.raftService.raftProtocolManager.isVerifier(a.RaftId) {
role = "verifier"
}
} }
clustInfo[i] = ClusterInfo{*a, role} clustInfo[i] = ClusterInfo{*a, role, s.checkIfNodeIsActive(a.RaftId)}
} }
return clustInfo, nil return clustInfo, nil
} }
// helper function to check of the raft node is active
// of the raftnode is active ActiveSince returns non-zero time
func (s *PublicRaftAPI) checkIfNodeIsActive(raftId uint16) bool {
if raftId == s.raftService.raftProtocolManager.raftId {
return true
}
activeSince := s.raftService.raftProtocolManager.transport.ActiveSince(types.ID(raftId))
if activeSince.IsZero() {
return false
}
return true
}
func (s *PublicRaftAPI) GetRaftId(enodeId string) (uint16, error) { func (s *PublicRaftAPI) GetRaftId(enodeId string) (uint16, error) {
return s.raftService.raftProtocolManager.FetchRaftId(enodeId) return s.raftService.raftProtocolManager.FetchRaftId(enodeId)
} }

View File

@ -29,7 +29,8 @@ type Address struct {
type ClusterInfo struct { type ClusterInfo struct {
Address Address
Role string `json:"role"` Role string `json:"role"`
NodeActive bool `json:"nodeActive"`
} }
func newAddress(raftId uint16, raftPort int, node *enode.Node, withHostname bool) *Address { func newAddress(raftId uint16, raftPort int, node *enode.Node, withHostname bool) *Address {