From 48ffc863360ea77422456bd117bac8bcd6f23e8a Mon Sep 17 00:00:00 2001 From: vsmk98 Date: Wed, 29 Jan 2020 17:41:37 +0800 Subject: [PATCH] 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 --- raft/api.go | 74 +++++++++++++++++++++++++++++++++++++++++++++------- raft/peer.go | 3 ++- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/raft/api.go b/raft/api.go index c1c38c532..72b247f20 100755 --- a/raft/api.go +++ b/raft/api.go @@ -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,33 +80,57 @@ 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 a.RaftId == leaderAddr.RaftId { - role = "minter" - } else if s.raftService.raftProtocolManager.isLearner(a.RaftId) { - role = "learner" - } else if s.raftService.raftProtocolManager.isVerifier(a.RaftId) { - role = "verifier" + if !noLeader { + if a.RaftId == leaderAddr.RaftId { + role = "minter" + } else if s.raftService.raftProtocolManager.isLearner(a.RaftId) { + role = "learner" + } 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) } diff --git a/raft/peer.go b/raft/peer.go index 12b5a6414..e5c5c8476 100644 --- a/raft/peer.go +++ b/raft/peer.go @@ -29,7 +29,8 @@ type Address struct { type ClusterInfo struct { 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 {