@@ -19,6 +19,7 @@ package builder
19
19
import (
20
20
"errors"
21
21
"fmt"
22
+ "reflect"
22
23
"strings"
23
24
24
25
"github.com/go-logr/logr"
@@ -37,7 +38,6 @@ import (
37
38
)
38
39
39
40
// Supporting mocking out functions for testing.
40
- var newController = controller .New
41
41
var getGvk = apiutil .GVKForObject
42
42
43
43
// project represents other forms that we can use to
@@ -52,21 +52,27 @@ const (
52
52
)
53
53
54
54
// Builder builds a Controller.
55
- type Builder struct {
55
+ type Builder [ request comparable ] struct {
56
56
forInput ForInput
57
57
ownsInput []OwnsInput
58
- rawSources []source.Source
59
- watchesInput []WatchesInput
58
+ rawSources []source.TypedSource [ request ]
59
+ watchesInput []WatchesInput [ request ]
60
60
mgr manager.Manager
61
61
globalPredicates []predicate.Predicate
62
- ctrl controller.Controller
63
- ctrlOptions controller.Options
62
+ ctrl controller.TypedController [ request ]
63
+ ctrlOptions controller.TypedOptions [ request ]
64
64
name string
65
+ newController func (name string , mgr manager.Manager , options controller.TypedOptions [request ]) (controller.TypedController [request ], error )
65
66
}
66
67
67
68
// ControllerManagedBy returns a new controller builder that will be started by the provided Manager.
68
- func ControllerManagedBy (m manager.Manager ) * Builder {
69
- return & Builder {mgr : m }
69
+ func ControllerManagedBy (m manager.Manager ) * Builder [reconcile.Request ] {
70
+ return TypedControllerManagedBy [reconcile.Request ](m )
71
+ }
72
+
73
+ // TypedControllerManagedBy returns a new tyepd controller builder that will be started by the provided Manager.
74
+ func TypedControllerManagedBy [request comparable ](m manager.Manager ) * Builder [request ] {
75
+ return & Builder [request ]{mgr : m }
70
76
}
71
77
72
78
// ForInput represents the information set by the For method.
@@ -81,7 +87,7 @@ type ForInput struct {
81
87
// update events by *reconciling the object*.
82
88
// This is the equivalent of calling
83
89
// Watches(&source.Kind{Type: apiType}, &handler.EnqueueRequestForObject{}).
84
- func (blder * Builder ) For (object client.Object , opts ... ForOption ) * Builder {
90
+ func (blder * Builder [ request ] ) For (object client.Object , opts ... ForOption ) * Builder [ request ] {
85
91
if blder .forInput .object != nil {
86
92
blder .forInput .err = fmt .Errorf ("For(...) should only be called once, could not assign multiple objects for reconciliation" )
87
93
return blder
@@ -111,7 +117,7 @@ type OwnsInput struct {
111
117
//
112
118
// By default, this is the equivalent of calling
113
119
// Watches(object, handler.EnqueueRequestForOwner([...], ownerType, OnlyControllerOwner())).
114
- func (blder * Builder ) Owns (object client.Object , opts ... OwnsOption ) * Builder {
120
+ func (blder * Builder [ request ] ) Owns (object client.Object , opts ... OwnsOption ) * Builder [ request ] {
115
121
input := OwnsInput {object : object }
116
122
for _ , opt := range opts {
117
123
opt .ApplyToOwns (& input )
@@ -122,9 +128,9 @@ func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder {
122
128
}
123
129
124
130
// WatchesInput represents the information set by Watches method.
125
- type WatchesInput struct {
131
+ type WatchesInput [ request comparable ] struct {
126
132
obj client.Object
127
- handler handler.EventHandler
133
+ handler handler.TypedEventHandler [client. Object , request ]
128
134
predicates []predicate.Predicate
129
135
objectProjection objectProjection
130
136
}
@@ -134,8 +140,12 @@ type WatchesInput struct {
134
140
//
135
141
// This is the equivalent of calling
136
142
// WatchesRawSource(source.Kind(cache, object, eventHandler, predicates...)).
137
- func (blder * Builder ) Watches (object client.Object , eventHandler handler.EventHandler , opts ... WatchesOption ) * Builder {
138
- input := WatchesInput {
143
+ func (blder * Builder [request ]) Watches (
144
+ object client.Object ,
145
+ eventHandler handler.TypedEventHandler [client.Object , request ],
146
+ opts ... WatchesOption [request ],
147
+ ) * Builder [request ] {
148
+ input := WatchesInput [request ]{
139
149
obj : object ,
140
150
handler : eventHandler ,
141
151
}
@@ -175,8 +185,12 @@ func (blder *Builder) Watches(object client.Object, eventHandler handler.EventHa
175
185
// In the first case, controller-runtime will create another cache for the
176
186
// concrete type on top of the metadata cache; this increases memory
177
187
// consumption and leads to race conditions as caches are not in sync.
178
- func (blder * Builder ) WatchesMetadata (object client.Object , eventHandler handler.EventHandler , opts ... WatchesOption ) * Builder {
179
- opts = append (opts , OnlyMetadata )
188
+ func (blder * Builder [request ]) WatchesMetadata (
189
+ object client.Object ,
190
+ eventHandler handler.TypedEventHandler [client.Object , request ],
191
+ opts ... WatchesOption [request ],
192
+ ) * Builder [request ] {
193
+ opts = append (opts , projectAs [request ](projectAsMetadata ))
180
194
return blder .Watches (object , eventHandler , opts ... )
181
195
}
182
196
@@ -187,7 +201,7 @@ func (blder *Builder) WatchesMetadata(object client.Object, eventHandler handler
187
201
// This method is only exposed for more advanced use cases, most users should use one of the higher level functions.
188
202
//
189
203
// WatchesRawSource does not respect predicates configured through WithEventFilter.
190
- func (blder * Builder ) WatchesRawSource (src source.Source ) * Builder {
204
+ func (blder * Builder [ request ] ) WatchesRawSource (src source.TypedSource [ request ] ) * Builder [ request ] {
191
205
blder .rawSources = append (blder .rawSources , src )
192
206
193
207
return blder
@@ -197,19 +211,19 @@ func (blder *Builder) WatchesRawSource(src source.Source) *Builder {
197
211
// trigger reconciliations. For example, filtering on whether the resource version has changed.
198
212
// Given predicate is added for all watched objects.
199
213
// Defaults to the empty list.
200
- func (blder * Builder ) WithEventFilter (p predicate.Predicate ) * Builder {
214
+ func (blder * Builder [ request ] ) WithEventFilter (p predicate.Predicate ) * Builder [ request ] {
201
215
blder .globalPredicates = append (blder .globalPredicates , p )
202
216
return blder
203
217
}
204
218
205
219
// WithOptions overrides the controller options used in doController. Defaults to empty.
206
- func (blder * Builder ) WithOptions (options controller.Options ) * Builder {
220
+ func (blder * Builder [ request ] ) WithOptions (options controller.TypedOptions [ request ] ) * Builder [ request ] {
207
221
blder .ctrlOptions = options
208
222
return blder
209
223
}
210
224
211
225
// WithLogConstructor overrides the controller options's LogConstructor.
212
- func (blder * Builder ) WithLogConstructor (logConstructor func (* reconcile. Request ) logr.Logger ) * Builder {
226
+ func (blder * Builder [ request ] ) WithLogConstructor (logConstructor func (* request ) logr.Logger ) * Builder [ request ] {
213
227
blder .ctrlOptions .LogConstructor = logConstructor
214
228
return blder
215
229
}
@@ -219,19 +233,19 @@ func (blder *Builder) WithLogConstructor(logConstructor func(*reconcile.Request)
219
233
// (underscores and alphanumeric characters only).
220
234
//
221
235
// By default, controllers are named using the lowercase version of their kind.
222
- func (blder * Builder ) Named (name string ) * Builder {
236
+ func (blder * Builder [ request ] ) Named (name string ) * Builder [ request ] {
223
237
blder .name = name
224
238
return blder
225
239
}
226
240
227
241
// Complete builds the Application Controller.
228
- func (blder * Builder ) Complete (r reconcile.Reconciler ) error {
242
+ func (blder * Builder [ request ] ) Complete (r reconcile.TypedReconciler [ request ] ) error {
229
243
_ , err := blder .Build (r )
230
244
return err
231
245
}
232
246
233
247
// Build builds the Application Controller and returns the Controller it created.
234
- func (blder * Builder ) Build (r reconcile.Reconciler ) (controller.Controller , error ) {
248
+ func (blder * Builder [ request ] ) Build (r reconcile.TypedReconciler [ request ] ) (controller.TypedController [ request ] , error ) {
235
249
if r == nil {
236
250
return nil , fmt .Errorf ("must provide a non-nil Reconciler" )
237
251
}
@@ -255,7 +269,7 @@ func (blder *Builder) Build(r reconcile.Reconciler) (controller.Controller, erro
255
269
return blder .ctrl , nil
256
270
}
257
271
258
- func (blder * Builder ) project (obj client.Object , proj objectProjection ) (client.Object , error ) {
272
+ func (blder * Builder [ request ] ) project (obj client.Object , proj objectProjection ) (client.Object , error ) {
259
273
switch proj {
260
274
case projectAsNormal :
261
275
return obj , nil
@@ -272,17 +286,23 @@ func (blder *Builder) project(obj client.Object, proj objectProjection) (client.
272
286
}
273
287
}
274
288
275
- func (blder * Builder ) doWatch () error {
289
+ func (blder * Builder [ request ] ) doWatch () error {
276
290
// Reconcile type
277
291
if blder .forInput .object != nil {
278
292
obj , err := blder .project (blder .forInput .object , blder .forInput .objectProjection )
279
293
if err != nil {
280
294
return err
281
295
}
282
- hdler := & handler.EnqueueRequestForObject {}
296
+
297
+ var hdler handler.TypedEventHandler [client.Object , request ]
298
+ if reflect .TypeFor [request ]() != reflect .TypeOf (reconcile.Request {}) {
299
+ return errors .New ("For() is not supported for TypedBuilder" )
300
+ }
301
+
302
+ reflect .ValueOf (& hdler ).Elem ().Set (reflect .ValueOf (& handler.EnqueueRequestForObject {}))
283
303
allPredicates := append ([]predicate.Predicate (nil ), blder .globalPredicates ... )
284
304
allPredicates = append (allPredicates , blder .forInput .predicates ... )
285
- src := source .Kind (blder .mgr .GetCache (), obj , hdler , allPredicates ... )
305
+ src := source .TypedKind (blder .mgr .GetCache (), obj , hdler , allPredicates ... )
286
306
if err := blder .ctrl .Watch (src ); err != nil {
287
307
return err
288
308
}
@@ -301,14 +321,18 @@ func (blder *Builder) doWatch() error {
301
321
if ! own .matchEveryOwner {
302
322
opts = append (opts , handler .OnlyControllerOwner ())
303
323
}
304
- hdler := handler .EnqueueRequestForOwner (
324
+ var hdler handler.TypedEventHandler [client.Object , request ]
325
+ if reflect .TypeFor [request ]() != reflect .TypeOf (reconcile.Request {}) {
326
+ return errors .New ("Owns() is not supported for TypedBuilder" )
327
+ }
328
+ reflect .ValueOf (& hdler ).Elem ().Set (reflect .ValueOf (handler .EnqueueRequestForOwner (
305
329
blder .mgr .GetScheme (), blder .mgr .GetRESTMapper (),
306
330
blder .forInput .object ,
307
331
opts ... ,
308
- )
332
+ )))
309
333
allPredicates := append ([]predicate.Predicate (nil ), blder .globalPredicates ... )
310
334
allPredicates = append (allPredicates , own .predicates ... )
311
- src := source .Kind (blder .mgr .GetCache (), obj , hdler , allPredicates ... )
335
+ src := source .TypedKind (blder .mgr .GetCache (), obj , hdler , allPredicates ... )
312
336
if err := blder .ctrl .Watch (src ); err != nil {
313
337
return err
314
338
}
@@ -325,7 +349,7 @@ func (blder *Builder) doWatch() error {
325
349
}
326
350
allPredicates := append ([]predicate.Predicate (nil ), blder .globalPredicates ... )
327
351
allPredicates = append (allPredicates , w .predicates ... )
328
- if err := blder .ctrl .Watch (source .Kind (blder .mgr .GetCache (), projected , w .handler , allPredicates ... )); err != nil {
352
+ if err := blder .ctrl .Watch (source .TypedKind [client. Object , request ] (blder .mgr .GetCache (), projected , w .handler , allPredicates ... )); err != nil {
329
353
return err
330
354
}
331
355
}
@@ -337,7 +361,7 @@ func (blder *Builder) doWatch() error {
337
361
return nil
338
362
}
339
363
340
- func (blder * Builder ) getControllerName (gvk schema.GroupVersionKind , hasGVK bool ) (string , error ) {
364
+ func (blder * Builder [ request ] ) getControllerName (gvk schema.GroupVersionKind , hasGVK bool ) (string , error ) {
341
365
if blder .name != "" {
342
366
return blder .name , nil
343
367
}
@@ -347,7 +371,7 @@ func (blder *Builder) getControllerName(gvk schema.GroupVersionKind, hasGVK bool
347
371
return strings .ToLower (gvk .Kind ), nil
348
372
}
349
373
350
- func (blder * Builder ) doController (r reconcile.Reconciler ) error {
374
+ func (blder * Builder [ request ] ) doController (r reconcile.TypedReconciler [ request ] ) error {
351
375
globalOpts := blder .mgr .GetControllerOptions ()
352
376
353
377
ctrlOptions := blder .ctrlOptions
@@ -401,9 +425,10 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
401
425
)
402
426
}
403
427
404
- ctrlOptions .LogConstructor = func (req * reconcile. Request ) logr.Logger {
428
+ ctrlOptions .LogConstructor = func (in * request ) logr.Logger {
405
429
log := log
406
- if req != nil {
430
+
431
+ if req , ok := any (in ).(* reconcile.Request ); ok && req != nil {
407
432
if hasGVK {
408
433
log = log .WithValues (gvk .Kind , klog .KRef (req .Namespace , req .Name ))
409
434
}
@@ -415,7 +440,11 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
415
440
}
416
441
}
417
442
443
+ if blder .newController == nil {
444
+ blder .newController = controller .NewTyped [request ]
445
+ }
446
+
418
447
// Build the controller and return.
419
- blder .ctrl , err = newController (controllerName , blder .mgr , ctrlOptions )
448
+ blder .ctrl , err = blder . newController (controllerName , blder .mgr , ctrlOptions )
420
449
return err
421
450
}
0 commit comments