diff --git a/pkg/client/leaderelection/leaderelection.go b/pkg/client/leaderelection/leaderelection.go index 190cf86d83d..d7031fb8514 100644 --- a/pkg/client/leaderelection/leaderelection.go +++ b/pkg/client/leaderelection/leaderelection.go @@ -150,6 +150,7 @@ type LeaderElectionRecord struct { LeaseDurationSeconds int `json:"leaseDurationSeconds"` AcquireTime unversioned.Time `json:"acquireTime"` RenewTime unversioned.Time `json:"renewTime"` + LeaderTransitions int `json:"leaderTransitions"` } // Run starts the leader election loop @@ -242,8 +243,9 @@ func (le *LeaderElector) tryAcquireOrRenew() bool { e.Annotations = make(map[string]string) } + var oldLeaderElectionRecord LeaderElectionRecord + if oldLeaderElectionRecordBytes, found := e.Annotations[LeaderElectionRecordAnnotationKey]; found { - var oldLeaderElectionRecord LeaderElectionRecord if err := json.Unmarshal([]byte(oldLeaderElectionRecordBytes), &oldLeaderElectionRecord); err != nil { glog.Errorf("error unmarshaling leader election record: %v", err) return false @@ -252,9 +254,6 @@ func (le *LeaderElector) tryAcquireOrRenew() bool { le.observedRecord = oldLeaderElectionRecord le.observedTime = time.Now() } - if oldLeaderElectionRecord.HolderIdentity == le.config.Identity { - leaderElectionRecord.AcquireTime = oldLeaderElectionRecord.AcquireTime - } if le.observedTime.Add(le.config.LeaseDuration).After(now.Time) && oldLeaderElectionRecord.HolderIdentity != le.config.Identity { glog.Infof("lock is held by %v and has not yet expired", oldLeaderElectionRecord.HolderIdentity) @@ -262,6 +261,14 @@ func (le *LeaderElector) tryAcquireOrRenew() bool { } } + // We're going to try to update. The leaderElectionRecord is set to it's default + // here. Let's correct it before updating. + if oldLeaderElectionRecord.HolderIdentity == le.config.Identity { + leaderElectionRecord.AcquireTime = oldLeaderElectionRecord.AcquireTime + } else { + leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions + 1 + } + leaderElectionRecordBytes, err := json.Marshal(leaderElectionRecord) if err != nil { glog.Errorf("err marshaling leader election record: %v", err) diff --git a/pkg/client/leaderelection/leaderelection_test.go b/pkg/client/leaderelection/leaderelection_test.go index 608c56e0084..486b80c17dd 100644 --- a/pkg/client/leaderelection/leaderelection_test.go +++ b/pkg/client/leaderelection/leaderelection_test.go @@ -45,8 +45,9 @@ func TestTryAcquireOrRenew(t *testing.T) { reaction testclient.ReactionFunc } - expectSuccess bool - outHolder string + expectSuccess bool + transitionLeader bool + outHolder string }{ // acquire from no endpoints { @@ -94,8 +95,10 @@ func TestTryAcquireOrRenew(t *testing.T) { }, }, }, - expectSuccess: true, - outHolder: "baz", + + expectSuccess: true, + transitionLeader: true, + outHolder: "baz", }, // acquire from led, unacked endpoints { @@ -127,8 +130,9 @@ func TestTryAcquireOrRenew(t *testing.T) { observedRecord: LeaderElectionRecord{HolderIdentity: "bing"}, observedTime: past, - expectSuccess: true, - outHolder: "baz", + expectSuccess: true, + transitionLeader: true, + outHolder: "baz", }, // don't acquire from led, acked endpoints { @@ -225,7 +229,13 @@ func TestTryAcquireOrRenew(t *testing.T) { t.Errorf("[%v]expected holder:\n\t%+v\ngot:\n\t%+v", i, test.outHolder, le.observedRecord.HolderIdentity) } if len(test.reactors) != len(c.Actions()) { - t.Errorf("[%v]wrong number of api interactions") + t.Errorf("[%v]wrong number of api interactions", i) + } + if test.transitionLeader && le.observedRecord.LeaderTransitions != 1 { + t.Errorf("[%v]leader should have transitioned but did not", i) + } + if !test.transitionLeader && le.observedRecord.LeaderTransitions != 0 { + t.Errorf("[%v]leader should not have transitioned but did", i) } } }