Skip to content

Commit 1979b11

Browse files
authored
a NonVoter node should never try to bootstrap (#492)
This is a follow-up to #483
1 parent e76e6e4 commit 1979b11

File tree

3 files changed

+34
-0
lines changed

3 files changed

+34
-0
lines changed

api.go

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ var (
3636
// follower or candidate node.
3737
ErrNotLeader = errors.New("node is not the leader")
3838

39+
// ErrNotVoter is returned when an operation can't be completed on a
40+
// non-voter node.
41+
ErrNotVoter = errors.New("node is not a voter")
42+
3943
// ErrLeadershipLost is returned when a leader fails to commit a log entry
4044
// because it's been deposed in the process.
4145
ErrLeadershipLost = errors.New("leadership lost while committing log")

raft.go

+5
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,11 @@ func (r *Raft) runFollower() {
233233
// the Raft object's member BootstrapCluster for more details. This must only be
234234
// called on the main thread, and only makes sense in the follower state.
235235
func (r *Raft) liveBootstrap(configuration Configuration) error {
236+
if !hasVote(configuration, r.localID) {
237+
// Reject this operation since we are not a voter
238+
return ErrNotVoter
239+
}
240+
236241
// Use the pre-init API to make the static updates.
237242
cfg := r.config()
238243
err := BootstrapCluster(&cfg, r.logs, r.stable, r.snapshots, r.trans, configuration)

raft_test.go

+25
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,31 @@ func TestRaft_LiveBootstrap(t *testing.T) {
9999
}
100100
}
101101

102+
func TestRaft_LiveBootstrap_From_NonVoter(t *testing.T) {
103+
// Make the cluster.
104+
c := MakeClusterNoBootstrap(2, t, nil)
105+
defer c.Close()
106+
107+
// Build the configuration.
108+
configuration := Configuration{}
109+
for i, r := range c.rafts {
110+
server := Server{
111+
ID: r.localID,
112+
Address: r.localAddr,
113+
}
114+
if i == 0 {
115+
server.Suffrage = Nonvoter
116+
}
117+
configuration.Servers = append(configuration.Servers, server)
118+
}
119+
120+
// Bootstrap one of the nodes live (the non-voter).
121+
boot := c.rafts[0].BootstrapCluster(configuration)
122+
if err := boot.Error(); err != ErrNotVoter {
123+
t.Fatalf("bootstrap should have failed: %v", err)
124+
}
125+
}
126+
102127
func TestRaft_RecoverCluster_NoState(t *testing.T) {
103128
c := MakeClusterNoBootstrap(1, t, nil)
104129
defer c.Close()

0 commit comments

Comments
 (0)