Skip to content

Commit f432261

Browse files
committed
Allow controllers to be started without adding them to the manager
As far as I can tell the main reason we add controllers to the manager is to ensure that we've been elected leader before we start any controllers. The downside of this design is that it's not possible to stop individual controllers, or remove controllers from the manager. I believe this commit is the minimum possible change necessary to allow controllers to be started and stopped on-demand. It allows a controller to be created, started, and stopped without ever being added to the manager. Any controller that is started separately from the manager must handle its own leader election. #730 Signed-off-by: Nic Cope <[email protected]>
1 parent edf7177 commit f432261

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

pkg/controller/controller.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ type Controller interface {
6767
// New returns a new Controller registered with the Manager. The Manager will ensure that shared Caches have
6868
// been synced before the Controller is Started.
6969
func New(name string, mgr manager.Manager, options Options) (Controller, error) {
70+
c, err := Configure(name, mgr, options)
71+
if err != nil {
72+
return nil, err
73+
}
74+
75+
// Add the controller as a Manager components
76+
return c, mgr.Add(c)
77+
}
78+
79+
// Configure a new controller without starting it or adding it to the manager.
80+
func Configure(name string, mgr manager.Manager, options Options) (Controller, error) {
7081
if options.Reconciler == nil {
7182
return nil, fmt.Errorf("must specify Reconciler")
7283
}
@@ -103,6 +114,5 @@ func New(name string, mgr manager.Manager, options Options) (Controller, error)
103114
Name: name,
104115
}
105116

106-
// Add the controller as a Manager components
107-
return c, mgr.Add(c)
117+
return c, nil
108118
}

pkg/manager/internal.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ type controllerManager struct {
130130
// It and `internalStop` should point to the same channel.
131131
internalStopper chan<- struct{}
132132

133+
elected chan struct{}
134+
133135
startCache func(stop <-chan struct{}) error
134136

135137
// port is the port that the webhook server serves at.
@@ -423,6 +425,8 @@ func (cm *controllerManager) Start(stop <-chan struct{}) error {
423425
return err
424426
}
425427
} else {
428+
// Treat not having an election the same as being elected.
429+
close(cm.elected)
426430
go cm.startLeaderElectionRunnables()
427431
}
428432

@@ -511,6 +515,7 @@ func (cm *controllerManager) startLeaderElection() (err error) {
511515
RetryPeriod: cm.retryPeriod,
512516
Callbacks: leaderelection.LeaderCallbacks{
513517
OnStartedLeading: func(_ context.Context) {
518+
close(cm.elected)
514519
cm.startLeaderElectionRunnables()
515520
},
516521
OnStoppedLeading: func() {
@@ -538,3 +543,7 @@ func (cm *controllerManager) startLeaderElection() (err error) {
538543
go l.Run(ctx)
539544
return nil
540545
}
546+
547+
func (cm *controllerManager) Elected() <-chan struct{} {
548+
return cm.elected
549+
}

pkg/manager/manager.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ type Manager interface {
5050
// non-leaderelection mode (always running) or leader election mode (managed by leader election if enabled).
5151
Add(Runnable) error
5252

53+
// Elected is closed when this manager is elected the leader, or when no
54+
// election is configured.
55+
Elected() <-chan struct{}
56+
5357
// SetFields will set any dependencies on an object for which the object has implemented the inject
5458
// interface - e.g. inject.Client.
5559
SetFields(interface{}) error
@@ -304,6 +308,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
304308
metricsListener: metricsListener,
305309
internalStop: stop,
306310
internalStopper: stop,
311+
elected: make(chan struct{}),
307312
port: options.Port,
308313
host: options.Host,
309314
certDir: options.CertDir,

0 commit comments

Comments
 (0)