Skip to content

Commit 2d26140

Browse files
committed
✨Builder: Do not require For
Requiring For does not make sense for all controllers as it is possible that their primary event triggering is not an object in the current cluster but for example an object in a different cluster or a source.Channel.
1 parent 222fb66 commit 2d26140

File tree

2 files changed

+61
-17
lines changed

2 files changed

+61
-17
lines changed

pkg/builder/controller.go

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package builder
1818

1919
import (
20+
"errors"
2021
"fmt"
2122
"strings"
2223

@@ -182,10 +183,6 @@ func (blder *Builder) Build(r reconcile.Reconciler) (controller.Controller, erro
182183
if blder.forInput.err != nil {
183184
return nil, blder.forInput.err
184185
}
185-
// Checking the reconcile type exist or not
186-
if blder.forInput.object == nil {
187-
return nil, fmt.Errorf("must provide an object for reconciliation")
188-
}
189186

190187
// Set the ControllerManagedBy
191188
if err := blder.doController(r); err != nil {
@@ -231,6 +228,9 @@ func (blder *Builder) doWatch() error {
231228
}
232229

233230
// Watches the managed types
231+
if len(blder.ownsInput) > 0 && blder.forInput.object == nil {
232+
return errors.New("Owns() can only be used together with For()")
233+
}
234234
for _, own := range blder.ownsInput {
235235
typeForSrc, err := blder.project(own.object, own.objectProjection)
236236
if err != nil {
@@ -269,11 +269,14 @@ func (blder *Builder) doWatch() error {
269269
return nil
270270
}
271271

272-
func (blder *Builder) getControllerName(gvk schema.GroupVersionKind) string {
272+
func (blder *Builder) getControllerName(gvk schema.GroupVersionKind, hasGVK bool) (string, error) {
273273
if blder.name != "" {
274-
return blder.name
274+
return blder.name, nil
275+
}
276+
if !hasGVK {
277+
return "", errors.New("one of For() or Named() must be called")
275278
}
276-
return strings.ToLower(gvk.Kind)
279+
return strings.ToLower(gvk.Kind), nil
277280
}
278281

279282
func (blder *Builder) doController(r reconcile.Reconciler) error {
@@ -286,13 +289,18 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
286289

287290
// Retrieve the GVK from the object we're reconciling
288291
// to prepopulate logger information, and to optionally generate a default name.
289-
gvk, err := getGvk(blder.forInput.object, blder.mgr.GetScheme())
290-
if err != nil {
291-
return err
292+
var gvk schema.GroupVersionKind
293+
hasGVK := blder.forInput.object != nil
294+
if hasGVK {
295+
var err error
296+
gvk, err = getGvk(blder.forInput.object, blder.mgr.GetScheme())
297+
if err != nil {
298+
return err
299+
}
292300
}
293301

294302
// Setup concurrency.
295-
if ctrlOptions.MaxConcurrentReconciles == 0 {
303+
if ctrlOptions.MaxConcurrentReconciles == 0 && hasGVK {
296304
groupKind := gvk.GroupKind().String()
297305

298306
if concurrency, ok := globalOpts.GroupKindConcurrency[groupKind]; ok && concurrency > 0 {
@@ -305,21 +313,30 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
305313
ctrlOptions.CacheSyncTimeout = *globalOpts.CacheSyncTimeout
306314
}
307315

308-
controllerName := blder.getControllerName(gvk)
316+
controllerName, err := blder.getControllerName(gvk, hasGVK)
317+
if err != nil {
318+
return err
319+
}
309320

310321
// Setup the logger.
311322
if ctrlOptions.LogConstructor == nil {
312323
log := blder.mgr.GetLogger().WithValues(
313324
"controller", controllerName,
314-
"controllerGroup", gvk.Group,
315-
"controllerKind", gvk.Kind,
316325
)
326+
if hasGVK {
327+
log = log.WithValues(
328+
"controllerGroup", gvk.Group,
329+
"controllerKind", gvk.Kind,
330+
)
331+
}
317332

318333
ctrlOptions.LogConstructor = func(req *reconcile.Request) logr.Logger {
319334
log := log
320335
if req != nil {
336+
if hasGVK {
337+
log = log.WithValues(gvk.Kind, klog.KRef(req.Namespace, req.Name))
338+
}
321339
log = log.WithValues(
322-
gvk.Kind, klog.KRef(req.Namespace, req.Name),
323340
"namespace", req.Namespace, "name", req.Name,
324341
)
325342
}

pkg/builder/controller_test.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,43 @@ var _ = Describe("application", func() {
112112
Expect(instance).To(BeNil())
113113
})
114114

115-
It("should return an error if For function is not called", func() {
115+
It("should return an error if For and Named function are not called", func() {
116116
By("creating a controller manager")
117117
m, err := manager.New(cfg, manager.Options{})
118118
Expect(err).NotTo(HaveOccurred())
119119

120120
instance, err := ControllerManagedBy(m).
121+
Watches(&source.Kind{Type: &appsv1.ReplicaSet{}}, &handler.EnqueueRequestForObject{}).
122+
Build(noop)
123+
Expect(err).To(MatchError(ContainSubstring("one of For() or Named() must be called")))
124+
Expect(instance).To(BeNil())
125+
})
126+
127+
It("should return an error when using Owns without For", func() {
128+
By("creating a controller manager")
129+
m, err := manager.New(cfg, manager.Options{})
130+
Expect(err).NotTo(HaveOccurred())
131+
132+
instance, err := ControllerManagedBy(m).
133+
Named("my_controller").
121134
Owns(&appsv1.ReplicaSet{}).
122135
Build(noop)
123-
Expect(err).To(MatchError(ContainSubstring("must provide an object for reconciliation")))
136+
Expect(err).To(MatchError(ContainSubstring("Owns() can only be used together with For()")))
124137
Expect(instance).To(BeNil())
138+
139+
})
140+
141+
It("should allow creating a controllerw without calling For", func() {
142+
By("creating a controller manager")
143+
m, err := manager.New(cfg, manager.Options{})
144+
Expect(err).NotTo(HaveOccurred())
145+
146+
instance, err := ControllerManagedBy(m).
147+
Named("my_controller").
148+
Watches(&source.Kind{Type: &appsv1.ReplicaSet{}}, &handler.EnqueueRequestForObject{}).
149+
Build(noop)
150+
Expect(err).NotTo(HaveOccurred())
151+
Expect(instance).NotTo(BeNil())
125152
})
126153

127154
It("should return an error if there is no GVK for an object, and thus we can't default the controller name", func() {

0 commit comments

Comments
 (0)