Skip to content

Commit

Permalink
a NonVoter node should never try to bootstrap (#492)
Browse files Browse the repository at this point in the history
This is a follow-up to #483
  • Loading branch information
rboyer committed Mar 1, 2022
1 parent e76e6e4 commit 1979b11
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 0 deletions.
4 changes: 4 additions & 0 deletions api.go
Expand Up @@ -36,6 +36,10 @@ var (
// follower or candidate node.
ErrNotLeader = errors.New("node is not the leader")

// ErrNotVoter is returned when an operation can't be completed on a
// non-voter node.
ErrNotVoter = errors.New("node is not a voter")

// ErrLeadershipLost is returned when a leader fails to commit a log entry
// because it's been deposed in the process.
ErrLeadershipLost = errors.New("leadership lost while committing log")
Expand Down
5 changes: 5 additions & 0 deletions raft.go
Expand Up @@ -233,6 +233,11 @@ func (r *Raft) runFollower() {
// the Raft object's member BootstrapCluster for more details. This must only be
// called on the main thread, and only makes sense in the follower state.
func (r *Raft) liveBootstrap(configuration Configuration) error {
if !hasVote(configuration, r.localID) {
// Reject this operation since we are not a voter
return ErrNotVoter
}

// Use the pre-init API to make the static updates.
cfg := r.config()
err := BootstrapCluster(&cfg, r.logs, r.stable, r.snapshots, r.trans, configuration)
Expand Down
25 changes: 25 additions & 0 deletions raft_test.go
Expand Up @@ -99,6 +99,31 @@ func TestRaft_LiveBootstrap(t *testing.T) {
}
}

func TestRaft_LiveBootstrap_From_NonVoter(t *testing.T) {
// Make the cluster.
c := MakeClusterNoBootstrap(2, t, nil)
defer c.Close()

// Build the configuration.
configuration := Configuration{}
for i, r := range c.rafts {
server := Server{
ID: r.localID,
Address: r.localAddr,
}
if i == 0 {
server.Suffrage = Nonvoter
}
configuration.Servers = append(configuration.Servers, server)
}

// Bootstrap one of the nodes live (the non-voter).
boot := c.rafts[0].BootstrapCluster(configuration)
if err := boot.Error(); err != ErrNotVoter {
t.Fatalf("bootstrap should have failed: %v", err)
}
}

func TestRaft_RecoverCluster_NoState(t *testing.T) {
c := MakeClusterNoBootstrap(1, t, nil)
defer c.Close()
Expand Down

0 comments on commit 1979b11

Please sign in to comment.