// Campaign handles leader election. Basically this just acquires a lock on the LeadershipKey and whoever gets the lock // is the leader. A re-election occurs when there are changes in the LeadershipKey. func (c *Candidate) campaign() { c.retrieveNode() c.retrieveSession() consul := c.consulClient() logrus.Debugf("%s is running for election with session %s.", c.node, c.session) kvpair := &consulapi.KVPair{ Key: c.LeadershipKey, Value: []byte(c.node), Session: c.session, } acquired, _, err := consul.KV().Acquire(kvpair, nil) if err != nil { logrus.Errorln("Failed to run Consul KV Acquire:", err) } if acquired { logrus.Infof("%s has become the leader.", c.node) } kv, _, _ := consul.KV().Get(c.LeadershipKey, nil) if kv != nil && kv.Session != "" { logrus.Debugf("%s is the current leader.", string(kv.Value)) logrus.Debugf("%s is waiting for changes in '%s'.", c.node, c.LeadershipKey) latestIndex := kv.ModifyIndex options := &consulapi.QueryOptions{ WaitIndex: latestIndex, } consul.KV().Get(c.LeadershipKey, options) } time.Sleep(15 * time.Second) c.campaign() }
// IsLeader returns true if the current agent is the leader. func (c *Candidate) IsLeader() bool { consul := c.consulClient() c.retrieveNode() c.retrieveSession() kv, _, err := consul.KV().Get(c.LeadershipKey, nil) if err != nil { logrus.Errorln("Unable to check for leadership:", err) return false } if kv == nil { logrus.Warnf("Leadership key '%s' is missing in Consuk KV.", c.LeadershipKey) return false } return c.node == string(kv.Value) && c.session == kv.Session }
// RetrieveSession retrieves the existing session needed to run leader election. If a session does not exist, a new // session is created with the LeadershipKey as the name. func (c *Candidate) retrieveSession() { consul := c.consulClient() if sessions, _, err := consul.Session().List(nil); err != nil { logrus.Warnln("Unable to retrieve list of sessions.") } else { for _, session := range sessions { if session.Name == c.LeadershipKey && session.Node == c.node { c.session = session.ID return } } } newSession := &consulapi.SessionEntry{ Name: c.LeadershipKey, } if sessionId, _, err := consul.Session().Create(newSession, nil); err != nil { logrus.Errorln("Unable to create new sessions:", err) } else { c.session = sessionId } }