From a886e8e5619cf34ed99f02dc8ff3d9800383ee94 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Fri, 12 Dec 2014 21:42:24 -0800 Subject: [PATCH] consul: Setup ACLs and timers after initial barrier --- consul/leader.go | 52 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/consul/leader.go b/consul/leader.go index 8b9fe3f177..7c9484b8f3 100644 --- a/consul/leader.go +++ b/consul/leader.go @@ -56,19 +56,6 @@ func (s *Server) leaderLoop(stopCh chan struct{}) { s.logger.Printf("[WARN] consul: failed to broadcast new leader event: %v", err) } - // Setup ACLs if we are the leader and need to - if err := s.initializeACL(); err != nil { - s.logger.Printf("[ERR] consul: ACL initialization failed: %v", err) - } - - // Setup the session timers. This is done both when starting up or when - // a leader fail over happens. Since the timers are maintained by the leader - // node along, effectively this means all the timers are renewed at the - // time of failover. The TTL contract is that the session will not be expired - // before the TTL, so expiring it later is allowable. - if err := s.initializeSessionTimers(); err != nil { - s.logger.Printf("[ERR] consul: Session Timers initialization failed: %v", err) - } // Clear the session timers on either shutdown or step down, since we // are no longer responsible for session expirations. defer s.clearAllSessionTimers() @@ -76,6 +63,7 @@ func (s *Server) leaderLoop(stopCh chan struct{}) { // Reconcile channel is only used once initial reconcile // has succeeded var reconcileCh chan serf.Member + establishedLeader := false RECONCILE: // Setup a reconciliation timer @@ -91,6 +79,16 @@ RECONCILE: } metrics.MeasureSince([]string{"consul", "leader", "barrier"}, start) + // Check if we need to handle initial leadership actions + if !establishedLeader { + if err := s.establishLeadership(); err != nil { + s.logger.Printf("[ERR] consul: failed to establish leadership: %v", + err) + goto WAIT + } + establishedLeader = true + } + // Reconcile any missing data if err := s.reconcile(); err != nil { s.logger.Printf("[ERR] consul: failed to reconcile: %v", err) @@ -118,6 +116,34 @@ WAIT: } } +// establishLeadership is invoked once we become leader and are able +// to invoke an initial barrier. The barrier is used to ensure any +// previously inflight transactions have been commited and that our +// state is up-to-date. +func (s *Server) establishLeadership() error { + // Setup ACLs if we are the leader and need to + if err := s.initializeACL(); err != nil { + s.logger.Printf("[ERR] consul: ACL initialization failed: %v", err) + return err + } + + // Setup the session timers. This is done both when starting up or when + // a leader fail over happens. Since the timers are maintained by the leader + // node along, effectively this means all the timers are renewed at the + // time of failover. The TTL contract is that the session will not be expired + // before the TTL, so expiring it later is allowable. + // + // This MUST be done after the initial barrier to ensure the latest Sessions + // are available to be initialized. Otherwise initialization may use stale + // data. + if err := s.initializeSessionTimers(); err != nil { + s.logger.Printf("[ERR] consul: Session Timers initialization failed: %v", + err) + return err + } + return nil +} + // initializeACL is used to setup the ACLs if we are the leader // and need to do this. func (s *Server) initializeACL() error {