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
import (
"errors"
"github.com/coreos/etcd/pkg/types"
)
type RaftNodeInfo struct {
ClusterSize int `json:"clusterSize"`
Role string `json:"role"`
@ -19,22 +24,49 @@ func NewPublicRaftAPI(raftService *RaftService) *PublicRaftAPI {
}
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
}
// 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) {
if err := s.checkIfNodeInCluster(); err != nil {
return 0, err
}
return s.raftService.raftProtocolManager.ProposeNewPeer(enodeId, false)
}
func (s *PublicRaftAPI) AddLearner(enodeId string) (uint16, error) {
if err := s.checkIfNodeInCluster(); err != nil {
return 0, err
}
return s.raftService.raftProtocolManager.ProposeNewPeer(enodeId, true)
}
func (s *PublicRaftAPI) PromoteToPeer(raftId uint16) (bool, error) {
if err := s.checkIfNodeInCluster(); err != nil {
return false, err
}
return s.raftService.raftProtocolManager.PromoteToPeer(raftId)
}
func (s *PublicRaftAPI) RemovePeer(raftId uint16) error {
if err := s.checkIfNodeInCluster(); err != nil {
return err
}
return s.raftService.raftProtocolManager.ProposePeerRemoval(raftId)
}
@ -48,21 +80,31 @@ func (s *PublicRaftAPI) Leader() (string, 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()
if nodeInfo.Role == "" {
return []ClusterInfo{}, nil
}
noLeader := false
leaderAddr, err := s.raftService.raftProtocolManager.LeaderAddress()
if err != nil {
if err == errNoLeaderElected && s.Role() == "" {
noLeader = true
if s.raftService.raftProtocolManager.NodeInfo().Role == "" {
return []ClusterInfo{}, nil
}
return []ClusterInfo{}, err
}
peerAddresses := append(nodeInfo.PeerAddresses, nodeInfo.Address)
clustInfo := make([]ClusterInfo, len(peerAddresses))
for i, a := range peerAddresses {
role := ""
if !noLeader {
if a.RaftId == leaderAddr.RaftId {
role = "minter"
} else if s.raftService.raftProtocolManager.isLearner(a.RaftId) {
@ -70,11 +112,25 @@ func (s *PublicRaftAPI) Cluster() ([]ClusterInfo, error) {
} 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
}
// 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) {
return s.raftService.raftProtocolManager.FetchRaftId(enodeId)
}

View File

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