mirror of https://github.com/hashicorp/consul
Make some final tweaks to autopilot package
parent
a86d11ec0a
commit
d08ab9fd19
|
@ -143,6 +143,14 @@ func NumPeers(raftConfig raft.Configuration) int {
|
||||||
return numPeers
|
return numPeers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveDeadServers triggers a pruning of dead servers in a non-blocking way.
|
||||||
|
func (a *Autopilot) RemoveDeadServers() {
|
||||||
|
select {
|
||||||
|
case a.removeDeadCh <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pruneDeadServers removes up to numPeers/2 failed servers
|
// pruneDeadServers removes up to numPeers/2 failed servers
|
||||||
func (a *Autopilot) pruneDeadServers() error {
|
func (a *Autopilot) pruneDeadServers() error {
|
||||||
conf := a.delegate.AutopilotConfig()
|
conf := a.delegate.AutopilotConfig()
|
||||||
|
@ -223,14 +231,17 @@ func (a *Autopilot) pruneDeadServers() error {
|
||||||
|
|
||||||
// MinRaftProtocol returns the lowest supported Raft protocol among alive servers
|
// MinRaftProtocol returns the lowest supported Raft protocol among alive servers
|
||||||
func (a *Autopilot) MinRaftProtocol() (int, error) {
|
func (a *Autopilot) MinRaftProtocol() (int, error) {
|
||||||
|
return minRaftProtocol(a.delegate.Serf().Members(), a.delegate.IsServer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func minRaftProtocol(members []serf.Member, serverFunc func(serf.Member) (*ServerInfo, error)) (int, error) {
|
||||||
minVersion := -1
|
minVersion := -1
|
||||||
members := a.delegate.Serf().Members()
|
|
||||||
for _, m := range members {
|
for _, m := range members {
|
||||||
if m.Status != serf.StatusAlive {
|
if m.Status != serf.StatusAlive {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
server, err := a.delegate.IsServer(m)
|
server, err := serverFunc(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
package autopilot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/serf/serf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMinRaftProtocol(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
makeMember := func(version string) serf.Member {
|
||||||
|
return serf.Member{
|
||||||
|
Name: "foo",
|
||||||
|
Addr: net.IP([]byte{127, 0, 0, 1}),
|
||||||
|
Tags: map[string]string{
|
||||||
|
"role": "consul",
|
||||||
|
"dc": "dc1",
|
||||||
|
"port": "10000",
|
||||||
|
"vsn": "1",
|
||||||
|
"raft_vsn": version,
|
||||||
|
},
|
||||||
|
Status: serf.StatusAlive,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
members []serf.Member
|
||||||
|
expected int
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
// No servers, error
|
||||||
|
{
|
||||||
|
members: []serf.Member{},
|
||||||
|
expected: -1,
|
||||||
|
err: errors.New("No servers found"),
|
||||||
|
},
|
||||||
|
// One server
|
||||||
|
{
|
||||||
|
members: []serf.Member{
|
||||||
|
makeMember("1"),
|
||||||
|
},
|
||||||
|
expected: 1,
|
||||||
|
},
|
||||||
|
// One server, bad version formatting
|
||||||
|
{
|
||||||
|
members: []serf.Member{
|
||||||
|
makeMember("asdf"),
|
||||||
|
},
|
||||||
|
expected: -1,
|
||||||
|
err: errors.New(`strconv.Atoi: parsing "asdf": invalid syntax`),
|
||||||
|
},
|
||||||
|
// Multiple servers, different versions
|
||||||
|
{
|
||||||
|
members: []serf.Member{
|
||||||
|
makeMember("1"),
|
||||||
|
makeMember("2"),
|
||||||
|
},
|
||||||
|
expected: 1,
|
||||||
|
},
|
||||||
|
// Multiple servers, same version
|
||||||
|
{
|
||||||
|
members: []serf.Member{
|
||||||
|
makeMember("2"),
|
||||||
|
makeMember("2"),
|
||||||
|
},
|
||||||
|
expected: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
serverFunc := func(m serf.Member) (*ServerInfo, error) {
|
||||||
|
return &ServerInfo{}, nil
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
result, err := minRaftProtocol(tc.members, serverFunc)
|
||||||
|
if result != tc.expected {
|
||||||
|
t.Fatalf("bad: %v, %v, %v", result, tc.expected, tc)
|
||||||
|
}
|
||||||
|
if tc.err != nil {
|
||||||
|
if err == nil || tc.err.Error() != err.Error() {
|
||||||
|
t.Fatalf("bad: %v, %v, %v", err, tc.err, tc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -416,7 +416,7 @@ func DefaultConfig() *Config {
|
||||||
|
|
||||||
TLSMinVersion: "tls10",
|
TLSMinVersion: "tls10",
|
||||||
|
|
||||||
// TODO (slackpad) - Until #3744 is done, we need to keep these
|
// TODO (slackpad) - Until #3744 is done, we need to keep these
|
||||||
// in sync with agent/config/default.go.
|
// in sync with agent/config/default.go.
|
||||||
AutopilotConfig: &autopilot.Config{
|
AutopilotConfig: &autopilot.Config{
|
||||||
CleanupDeadServers: true,
|
CleanupDeadServers: true,
|
||||||
|
|
|
@ -738,10 +738,7 @@ func (s *Server) joinConsulServer(m serf.Member, parts *metadata.Server) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger a check to remove dead servers
|
// Trigger a check to remove dead servers
|
||||||
select {
|
s.autopilot.RemoveDeadServers()
|
||||||
case s.autopilotRemoveDeadCh <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,12 +90,6 @@ type Server struct {
|
||||||
// autopilot is the Autopilot instance for this server.
|
// autopilot is the Autopilot instance for this server.
|
||||||
autopilot *autopilot.Autopilot
|
autopilot *autopilot.Autopilot
|
||||||
|
|
||||||
// autopilotRemoveDeadCh is used to trigger a check for dead server removals.
|
|
||||||
autopilotRemoveDeadCh chan struct{}
|
|
||||||
|
|
||||||
// autopilotShutdownCh is used to stop the Autopilot loop.
|
|
||||||
autopilotShutdownCh chan struct{}
|
|
||||||
|
|
||||||
// autopilotWaitGroup is used to block until Autopilot shuts down.
|
// autopilotWaitGroup is used to block until Autopilot shuts down.
|
||||||
autopilotWaitGroup sync.WaitGroup
|
autopilotWaitGroup sync.WaitGroup
|
||||||
|
|
||||||
|
@ -281,25 +275,23 @@ func NewServerLogger(config *Config, logger *log.Logger, tokens *token.Store) (*
|
||||||
|
|
||||||
// Create server.
|
// Create server.
|
||||||
s := &Server{
|
s := &Server{
|
||||||
autopilotRemoveDeadCh: make(chan struct{}),
|
config: config,
|
||||||
autopilotShutdownCh: make(chan struct{}),
|
tokens: tokens,
|
||||||
config: config,
|
connPool: connPool,
|
||||||
tokens: tokens,
|
eventChLAN: make(chan serf.Event, 256),
|
||||||
connPool: connPool,
|
eventChWAN: make(chan serf.Event, 256),
|
||||||
eventChLAN: make(chan serf.Event, 256),
|
logger: logger,
|
||||||
eventChWAN: make(chan serf.Event, 256),
|
leaveCh: make(chan struct{}),
|
||||||
logger: logger,
|
reconcileCh: make(chan serf.Member, 32),
|
||||||
leaveCh: make(chan struct{}),
|
router: router.NewRouter(logger, config.Datacenter),
|
||||||
reconcileCh: make(chan serf.Member, 32),
|
rpcServer: rpc.NewServer(),
|
||||||
router: router.NewRouter(logger, config.Datacenter),
|
rpcTLS: incomingTLS,
|
||||||
rpcServer: rpc.NewServer(),
|
reassertLeaderCh: make(chan chan error),
|
||||||
rpcTLS: incomingTLS,
|
segmentLAN: make(map[string]*serf.Serf, len(config.Segments)),
|
||||||
reassertLeaderCh: make(chan chan error),
|
sessionTimers: NewSessionTimers(),
|
||||||
segmentLAN: make(map[string]*serf.Serf, len(config.Segments)),
|
tombstoneGC: gc,
|
||||||
sessionTimers: NewSessionTimers(),
|
serverLookup: NewServerLookup(),
|
||||||
tombstoneGC: gc,
|
shutdownCh: shutdownCh,
|
||||||
serverLookup: NewServerLookup(),
|
|
||||||
shutdownCh: shutdownCh,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up autopilot
|
// Set up autopilot
|
||||||
|
|
Loading…
Reference in New Issue