Skip to content

Commit abb2d86

Browse files
authored
🐛 Prevent LeaderElector setup error from being swallowed (#2876)
* fix leader election bug * fix tests * fix * add function initLeaderElector * add test case for Start function bug * add comment for new leader elector code * fix comment * fix test
1 parent 7394f7b commit abb2d86

File tree

2 files changed

+46
-22
lines changed

2 files changed

+46
-22
lines changed

pkg/manager/internal.go

+29-22
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,16 @@ func (cm *controllerManager) Start(ctx context.Context) (err error) {
351351
// Initialize the internal context.
352352
cm.internalCtx, cm.internalCancel = context.WithCancel(ctx)
353353

354+
// Leader elector must be created before defer that contains engageStopProcedure function
355+
// https://github.com/kubernetes-sigs/controller-runtime/issues/2873
356+
var leaderElector *leaderelection.LeaderElector
357+
if cm.resourceLock != nil {
358+
leaderElector, err = cm.initLeaderElector()
359+
if err != nil {
360+
return fmt.Errorf("failed during initialization leader election process: %w", err)
361+
}
362+
}
363+
354364
// This chan indicates that stop is complete, in other words all runnables have returned or timeout on stop request
355365
stopComplete := make(chan struct{})
356366
defer close(stopComplete)
@@ -433,19 +443,22 @@ func (cm *controllerManager) Start(ctx context.Context) (err error) {
433443
{
434444
ctx, cancel := context.WithCancel(context.Background())
435445
cm.leaderElectionCancel = cancel
436-
go func() {
437-
if cm.resourceLock != nil {
438-
if err := cm.startLeaderElection(ctx); err != nil {
439-
cm.errChan <- err
440-
}
441-
} else {
446+
if leaderElector != nil {
447+
// Start the leader elector process
448+
go func() {
449+
leaderElector.Run(ctx)
450+
<-ctx.Done()
451+
close(cm.leaderElectionStopped)
452+
}()
453+
} else {
454+
go func() {
442455
// Treat not having leader election enabled the same as being elected.
443456
if err := cm.startLeaderElectionRunnables(); err != nil {
444457
cm.errChan <- err
445458
}
446459
close(cm.elected)
447-
}
448-
}()
460+
}()
461+
}
449462
}
450463

451464
ready = true
@@ -564,12 +577,8 @@ func (cm *controllerManager) engageStopProcedure(stopComplete <-chan struct{}) e
564577
return nil
565578
}
566579

567-
func (cm *controllerManager) startLeaderElectionRunnables() error {
568-
return cm.runnables.LeaderElection.Start(cm.internalCtx)
569-
}
570-
571-
func (cm *controllerManager) startLeaderElection(ctx context.Context) (err error) {
572-
l, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
580+
func (cm *controllerManager) initLeaderElector() (*leaderelection.LeaderElector, error) {
581+
leaderElector, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
573582
Lock: cm.resourceLock,
574583
LeaseDuration: cm.leaseDuration,
575584
RenewDeadline: cm.renewDeadline,
@@ -599,16 +608,14 @@ func (cm *controllerManager) startLeaderElection(ctx context.Context) (err error
599608
Name: cm.leaderElectionID,
600609
})
601610
if err != nil {
602-
return err
611+
return nil, err
603612
}
604613

605-
// Start the leader elector process
606-
go func() {
607-
l.Run(ctx)
608-
<-ctx.Done()
609-
close(cm.leaderElectionStopped)
610-
}()
611-
return nil
614+
return leaderElector, nil
615+
}
616+
617+
func (cm *controllerManager) startLeaderElectionRunnables() error {
618+
return cm.runnables.LeaderElection.Start(cm.internalCtx)
612619
}
613620

614621
func (cm *controllerManager) Elected() <-chan struct{} {

pkg/manager/manager_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,23 @@ var _ = Describe("manger.Manager", func() {
11651165
cm.onStoppedLeading = func() {}
11661166
},
11671167
)
1168+
1169+
It("should return an error if leader election param incorrect", func() {
1170+
renewDeadline := time.Second * 20
1171+
m, err := New(cfg, Options{
1172+
LeaderElection: true,
1173+
LeaderElectionID: "controller-runtime",
1174+
LeaderElectionNamespace: "default",
1175+
newResourceLock: fakeleaderelection.NewResourceLock,
1176+
RenewDeadline: &renewDeadline,
1177+
})
1178+
Expect(err).NotTo(HaveOccurred())
1179+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
1180+
defer cancel()
1181+
err = m.Start(ctx)
1182+
Expect(err).To(HaveOccurred())
1183+
Expect(errors.Is(err, context.DeadlineExceeded)).NotTo(BeTrue())
1184+
})
11681185
})
11691186

11701187
Context("should start serving metrics", func() {

0 commit comments

Comments
 (0)