@@ -59,6 +59,8 @@ const (
59
59
)
60
60
61
61
var _ Runnable = & controllerManager {}
62
+ var _ cluster.Aware = & controllerManager {}
63
+ var _ Manager = & controllerManager {}
62
64
63
65
type controllerManager struct {
64
66
sync.Mutex
@@ -68,8 +70,14 @@ type controllerManager struct {
68
70
errChan chan error
69
71
runnables * runnables
70
72
71
- // cluster holds a variety of methods to interact with a cluster. Required.
72
- cluster cluster.Cluster
73
+ // defaultCluster holds a variety of methods to interact with a defaultCluster. Required.
74
+ defaultCluster cluster.Cluster
75
+ defaultClusterOptions cluster.Option
76
+
77
+ // engagedCluster is a map of engaged clusters. The can come and go as the manager is running.
78
+ engagedClustersLock sync.RWMutex
79
+ engagedClusters map [string ]cluster.Cluster
80
+ clusterAwareRunnables []cluster.Aware
73
81
74
82
// recorderProvider is used to generate event recorders that will be injected into Controllers
75
83
// (and EventHandlers, Sources and Predicates).
@@ -161,6 +169,9 @@ type controllerManager struct {
161
169
// internalProceduresStop channel is used internally to the manager when coordinating
162
170
// the proper shutdown of servers. This channel is also used for dependency injection.
163
171
internalProceduresStop chan struct {}
172
+
173
+ // clusterProvider is used to get clusters by name, beyond the default cluster.
174
+ clusterProvider cluster.Provider
164
175
}
165
176
166
177
type hasCache interface {
@@ -176,7 +187,40 @@ func (cm *controllerManager) Add(r Runnable) error {
176
187
}
177
188
178
189
func (cm * controllerManager ) add (r Runnable ) error {
179
- return cm .runnables .Add (r )
190
+ var engaged []cluster.Aware
191
+ var errs []error
192
+ disengage := func () {
193
+ for _ , aware := range engaged {
194
+ if err := aware .Disengage (cm .internalCtx , cm .defaultCluster ); err != nil {
195
+ errs = append (errs , err )
196
+ }
197
+ }
198
+ }
199
+
200
+ // engage with existing clusters (this is reversible)
201
+ if aware , ok := r .(cluster.Aware ); ok {
202
+ cm .engagedClustersLock .RLock ()
203
+ defer cm .engagedClustersLock .RUnlock ()
204
+ for _ , cl := range cm .engagedClusters {
205
+ if err := aware .Engage (cm .internalCtx , cl ); err != nil {
206
+ errs = append (errs , err )
207
+ break
208
+ }
209
+ engaged = append (engaged , aware )
210
+ }
211
+ if len (errs ) > 0 {
212
+ disengage ()
213
+ return kerrors .NewAggregate (errs )
214
+ }
215
+ cm .clusterAwareRunnables = append (cm .clusterAwareRunnables , aware )
216
+ } else {
217
+ if err := cm .runnables .Add (r ); err != nil {
218
+ disengage ()
219
+ return err
220
+ }
221
+ }
222
+
223
+ return nil
180
224
}
181
225
182
226
// AddMetricsServerExtraHandler adds extra handler served on path to the http server that serves metrics.
@@ -231,40 +275,58 @@ func (cm *controllerManager) AddReadyzCheck(name string, check healthz.Checker)
231
275
return nil
232
276
}
233
277
278
+ func (cm * controllerManager ) Name () string {
279
+ return cm .defaultCluster .Name ()
280
+ }
281
+
282
+ func (cm * controllerManager ) GetCluster (ctx context.Context , clusterName string ) (cluster.Cluster , error ) {
283
+ if clusterName == "" || clusterName == cm .defaultCluster .Name () {
284
+ return cm .defaultCluster , nil
285
+ }
286
+
287
+ if cm .clusterProvider == nil {
288
+ return nil , fmt .Errorf ("cluster %q not found, cluster provider is not set" , clusterName )
289
+ }
290
+
291
+ // intentionally not returning from engaged clusters. This can be used
292
+ // without engaging clusters.
293
+ return cm .clusterProvider .Get (ctx , clusterName )
294
+ }
295
+
234
296
func (cm * controllerManager ) GetHTTPClient () * http.Client {
235
- return cm .cluster .GetHTTPClient ()
297
+ return cm .defaultCluster .GetHTTPClient ()
236
298
}
237
299
238
300
func (cm * controllerManager ) GetConfig () * rest.Config {
239
- return cm .cluster .GetConfig ()
301
+ return cm .defaultCluster .GetConfig ()
240
302
}
241
303
242
304
func (cm * controllerManager ) GetClient () client.Client {
243
- return cm .cluster .GetClient ()
305
+ return cm .defaultCluster .GetClient ()
244
306
}
245
307
246
308
func (cm * controllerManager ) GetScheme () * runtime.Scheme {
247
- return cm .cluster .GetScheme ()
309
+ return cm .defaultCluster .GetScheme ()
248
310
}
249
311
250
312
func (cm * controllerManager ) GetFieldIndexer () client.FieldIndexer {
251
- return cm .cluster .GetFieldIndexer ()
313
+ return cm .defaultCluster .GetFieldIndexer ()
252
314
}
253
315
254
316
func (cm * controllerManager ) GetCache () cache.Cache {
255
- return cm .cluster .GetCache ()
317
+ return cm .defaultCluster .GetCache ()
256
318
}
257
319
258
320
func (cm * controllerManager ) GetEventRecorderFor (name string ) record.EventRecorder {
259
- return cm .cluster .GetEventRecorderFor (name )
321
+ return cm .defaultCluster .GetEventRecorderFor (name )
260
322
}
261
323
262
324
func (cm * controllerManager ) GetRESTMapper () meta.RESTMapper {
263
- return cm .cluster .GetRESTMapper ()
325
+ return cm .defaultCluster .GetRESTMapper ()
264
326
}
265
327
266
328
func (cm * controllerManager ) GetAPIReader () client.Reader {
267
- return cm .cluster .GetAPIReader ()
329
+ return cm .defaultCluster .GetAPIReader ()
268
330
}
269
331
270
332
func (cm * controllerManager ) GetWebhookServer () webhook.Server {
@@ -381,7 +443,7 @@ func (cm *controllerManager) Start(ctx context.Context) (err error) {
381
443
}()
382
444
383
445
// Add the cluster runnable.
384
- if err := cm .add (cm .cluster ); err != nil {
446
+ if err := cm .add (cm .defaultCluster ); err != nil {
385
447
return fmt .Errorf ("failed to add cluster to runnables: %w" , err )
386
448
}
387
449
@@ -614,6 +676,70 @@ func (cm *controllerManager) initLeaderElector() (*leaderelection.LeaderElector,
614
676
return leaderElector , nil
615
677
}
616
678
679
+ func (cm * controllerManager ) Engage (ctx context.Context , cl cluster.Cluster ) error {
680
+ cm .Lock ()
681
+ defer cm .Unlock ()
682
+
683
+ // be reentrant via noop
684
+ cm .engagedClustersLock .RLock ()
685
+ if _ , ok := cm .engagedClusters [cl .Name ()]; ok {
686
+ cm .engagedClustersLock .RUnlock ()
687
+ return nil
688
+ }
689
+ cm .engagedClustersLock .RUnlock ()
690
+
691
+ // add early because any engaged runnable could access it
692
+ cm .engagedClustersLock .Lock ()
693
+ cm .engagedClusters [cl .Name ()] = cl
694
+ cm .engagedClustersLock .Unlock ()
695
+
696
+ // engage known runnables
697
+ var errs []error
698
+ engaged := []cluster.Aware {}
699
+ for _ , r := range cm .clusterAwareRunnables {
700
+ if err := r .Engage (ctx , cl ); err != nil {
701
+ errs = append (errs , err )
702
+ break
703
+ }
704
+ engaged = append (engaged , r )
705
+ }
706
+
707
+ // clean-up
708
+ if len (errs ) > 0 {
709
+ for _ , aware := range engaged {
710
+ if err := aware .Disengage (ctx , cl ); err != nil {
711
+ errs = append (errs , err )
712
+ }
713
+ }
714
+
715
+ cm .engagedClustersLock .Lock ()
716
+ delete (cm .engagedClusters , cl .Name ())
717
+ cm .engagedClustersLock .Unlock ()
718
+
719
+ return kerrors .NewAggregate (errs )
720
+ }
721
+
722
+ return nil
723
+ }
724
+
725
+ func (cm * controllerManager ) Disengage (ctx context.Context , cl cluster.Cluster ) error {
726
+ cm .Lock ()
727
+ defer cm .Unlock ()
728
+
729
+ var errs []error
730
+ for _ , r := range cm .clusterAwareRunnables {
731
+ if err := r .Disengage (ctx , cl ); err != nil {
732
+ errs = append (errs , err )
733
+ }
734
+ }
735
+
736
+ cm .engagedClustersLock .Lock ()
737
+ delete (cm .engagedClusters , cl .Name ())
738
+ cm .engagedClustersLock .Unlock ()
739
+
740
+ return kerrors .NewAggregate (errs )
741
+ }
742
+
617
743
func (cm * controllerManager ) startLeaderElectionRunnables () error {
618
744
return cm .runnables .LeaderElection .Start (cm .internalCtx )
619
745
}
0 commit comments