Wait to initialize autopilot until all servers are >= 0.8.0

This commit is contained in:
Kyle Havlovitz 2017-04-12 15:28:18 -07:00
parent 56c3f4576e
commit 7d36403291
No known key found for this signature in database
GPG Key ID: 8A5E6B173056AD6C
3 changed files with 38 additions and 4 deletions

View File

@ -10,6 +10,7 @@ import (
"github.com/armon/go-metrics" "github.com/armon/go-metrics"
"github.com/hashicorp/consul/consul/agent" "github.com/hashicorp/consul/consul/agent"
"github.com/hashicorp/consul/consul/structs" "github.com/hashicorp/consul/consul/structs"
"github.com/hashicorp/go-version"
"github.com/hashicorp/raft" "github.com/hashicorp/raft"
"github.com/hashicorp/serf/serf" "github.com/hashicorp/serf/serf"
) )
@ -33,6 +34,8 @@ func (s *Server) stopAutopilot() {
s.autopilotWaitGroup.Wait() s.autopilotWaitGroup.Wait()
} }
var minAutopilotVersion, _ = version.NewVersion("0.8.0")
// autopilotLoop periodically looks for nonvoting servers to promote and dead servers to remove. // autopilotLoop periodically looks for nonvoting servers to promote and dead servers to remove.
func (s *Server) autopilotLoop() { func (s *Server) autopilotLoop() {
defer s.autopilotWaitGroup.Done() defer s.autopilotWaitGroup.Done()
@ -53,6 +56,15 @@ func (s *Server) autopilotLoop() {
break break
} }
// Setup autopilot config if we need to
if autopilotConf == nil {
if err := s.initializeAutopilot(); err != nil {
s.logger.Printf("[ERR] autopilot: %v", err)
}
continue
}
if err := s.autopilotPolicy.PromoteNonVoters(autopilotConf); err != nil { if err := s.autopilotPolicy.PromoteNonVoters(autopilotConf); err != nil {
s.logger.Printf("[ERR] autopilot: error checking for non-voters to promote: %s", err) s.logger.Printf("[ERR] autopilot: error checking for non-voters to promote: %s", err)
} }
@ -68,11 +80,26 @@ func (s *Server) autopilotLoop() {
} }
} }
// lowestServerVersion returns the lowest version among the alive servers
func (s *Server) lowestServerVersion() *version.Version {
lowest := minAutopilotVersion
for _, member := range s.LANMembers() {
if valid, parts := agent.IsConsulServer(member); valid && parts.Status == serf.StatusAlive {
if parts.Build.LessThan(lowest) {
lowest = &parts.Build
}
}
}
return lowest
}
// pruneDeadServers removes up to numPeers/2 failed servers // pruneDeadServers removes up to numPeers/2 failed servers
func (s *Server) pruneDeadServers() error { func (s *Server) pruneDeadServers() error {
state := s.fsm.State() state := s.fsm.State()
_, autopilotConf, err := state.AutopilotConfig() _, autopilotConf, err := state.AutopilotConfig()
if err != nil { if err != nil || autopilotConf == nil {
return err return err
} }

View File

@ -191,6 +191,8 @@ func TestAutopilot_CleanupStaleRaftServer(t *testing.T) {
} }
} }
testutil.WaitForLeader(t, s1.RPC, "dc1")
// Add s4 to peers directly // Add s4 to peers directly
s4addr := fmt.Sprintf("127.0.0.1:%d", s4addr := fmt.Sprintf("127.0.0.1:%d",
s4.config.SerfLANConfig.MemberlistConfig.BindPort) s4.config.SerfLANConfig.MemberlistConfig.BindPort)

View File

@ -153,10 +153,9 @@ func (s *Server) establishLeadership() error {
return err return err
} }
// Setup autopilot config if we are the leader and need to // Setup autopilot config if we need to
if err := s.initializeAutopilot(); err != nil { if err := s.initializeAutopilot(); err != nil {
s.logger.Printf("[ERR] consul: Autopilot initialization failed: %v", err) s.logger.Printf("[ERR] autopilot: %v", err)
return err
} }
s.startAutopilot() s.startAutopilot()
@ -252,6 +251,12 @@ func (s *Server) initializeACL() error {
// initializeAutopilot is used to setup the autopilot config if we are // initializeAutopilot is used to setup the autopilot config if we are
// the leader and need to do this // the leader and need to do this
func (s *Server) initializeAutopilot() error { func (s *Server) initializeAutopilot() error {
lowestVersion := s.lowestServerVersion()
if !lowestVersion.Equal(minAutopilotVersion) && !lowestVersion.GreaterThan(minAutopilotVersion) {
return fmt.Errorf("can't initialize autopilot until all servers are >= %s", minAutopilotVersion.String())
}
// Bail if the config has already been initialized // Bail if the config has already been initialized
state := s.fsm.State() state := s.fsm.State()
_, config, err := state.AutopilotConfig() _, config, err := state.AutopilotConfig()