Skip to content

Commit 90b23e9

Browse files
negzkevindelgado
authored andcommitted
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. kubernetes-sigs#730 Signed-off-by: Nic Cope <[email protected]>
1 parent 17e7232 commit 90b23e9

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
@@ -134,6 +134,8 @@ type controllerManager struct {
134134
// It and `internalStop` should point to the same channel.
135135
internalStopper chan<- struct{}
136136

137+
elected chan struct{}
138+
137139
startCache func(stop <-chan struct{}) error
138140

139141
// port is the port that the webhook server serves at.
@@ -457,6 +459,8 @@ func (cm *controllerManager) Start(stop <-chan struct{}) error {
457459
return err
458460
}
459461
} else {
462+
// Treat not having an election the same as being elected.
463+
close(cm.elected)
460464
go cm.startLeaderElectionRunnables()
461465
}
462466

@@ -545,6 +549,7 @@ func (cm *controllerManager) startLeaderElection() (err error) {
545549
RetryPeriod: cm.retryPeriod,
546550
Callbacks: leaderelection.LeaderCallbacks{
547551
OnStartedLeading: func(_ context.Context) {
552+
close(cm.elected)
548553
cm.startLeaderElectionRunnables()
549554
},
550555
OnStoppedLeading: func() {
@@ -572,3 +577,7 @@ func (cm *controllerManager) startLeaderElection() (err error) {
572577
go l.Run(ctx)
573578
return nil
574579
}
580+
581+
func (cm *controllerManager) Elected() <-chan struct{} {
582+
return cm.elected
583+
}

pkg/manager/manager.go

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

54+
// Elected is closed when this manager is elected the leader, or when no
55+
// election is configured.
56+
Elected() <-chan struct{}
57+
5458
// SetFields will set any dependencies on an object for which the object has implemented the inject
5559
// interface - e.g. inject.Client.
5660
SetFields(interface{}) error
@@ -325,6 +329,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
325329
metricsExtraHandlers: metricsExtraHandlers,
326330
internalStop: stop,
327331
internalStopper: stop,
332+
elected: make(chan struct{}),
328333
port: options.Port,
329334
host: options.Host,
330335
certDir: options.CertDir,

0 commit comments

Comments
 (0)