diff --git a/consul/server.go b/consul/server.go index 5a295ddfb..36f982e55 100644 --- a/consul/server.go +++ b/consul/server.go @@ -259,6 +259,57 @@ func (s *Server) Shutdown() error { return nil } +// Leave is used to prepare for a graceful shutdown of the server +func (s *Server) Leave() error { + s.logger.Printf("[INFO] Consul server starting leave") + + // Leave the WAN pool + if s.serfWAN != nil { + if err := s.serfWAN.Leave(); err != nil { + s.logger.Printf("[ERR] Failed to leave WAN Serf cluster: %v", err) + } + } + + // Leave the LAN pool + if s.serfLAN != nil { + if err := s.serfLAN.Leave(); err != nil { + s.logger.Printf("[ERR] Failed to leave LAN Serf cluster: %v", err) + } + } + + // Leave the Raft cluster + if s.raft != nil { + // Get the leader + leader := s.raft.Leader() + if leader == nil { + s.logger.Printf("[ERR] Failed to leave Raft cluster: no leader") + goto AFTER_LEAVE + } + + // Request that we are removed + // TODO: Properly forward to leader + future := s.raft.RemovePeer(s.raftTransport.LocalAddr()) + + // Wait for the future + ch := make(chan error, 1) + go func() { + ch <- future.Error() + }() + + // Wait for the commit + select { + case err := <-ch: + if err != nil { + s.logger.Printf("[ERR] Failed to leave Raft cluster: %v", err) + } + case <-time.After(3 * time.Second): + s.logger.Printf("[ERR] Timedout leaving Raft cluster") + } + } +AFTER_LEAVE: + return nil +} + // JoinLAN is used to have Consul join the inner-DC pool // The target address should be another node inside the DC // listening on the Serf LAN address