Skip to content

Commit df54dc5

Browse files
committed
✨ Allow to use builder.OnlyMetadata option with Watches
This change allows builders to use builder.OnlyMetadata when creating extra watches with .Watches(...). The code inspects the passed source.Source, and if it's of type *source.Kind, it calls the internal project method that allows to use metav1.PartialObjectMetadata in mapping functions. Signed-off-by: Vince Prignano <[email protected]>
1 parent 9975e29 commit df54dc5

File tree

3 files changed

+71
-8
lines changed

3 files changed

+71
-8
lines changed

pkg/builder/controller.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,10 @@ func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder {
116116

117117
// WatchesInput represents the information set by Watches method.
118118
type WatchesInput struct {
119-
src source.Source
120-
eventhandler handler.EventHandler
121-
predicates []predicate.Predicate
119+
src source.Source
120+
eventhandler handler.EventHandler
121+
predicates []predicate.Predicate
122+
objectProjection objectProjection
122123
}
123124

124125
// Watches exposes the lower-level ControllerManagedBy Watches functions through the builder. Consider using
@@ -255,10 +256,19 @@ func (blder *Builder) doWatch() error {
255256
for _, w := range blder.watchesInput {
256257
allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
257258
allPredicates = append(allPredicates, w.predicates...)
259+
260+
// If the source of this watch is of type *source.Kind, project it.
261+
if srckind, ok := w.src.(*source.Kind); ok {
262+
typeForSrc, err := blder.project(srckind.Type, w.objectProjection)
263+
if err != nil {
264+
return err
265+
}
266+
srckind.Type = typeForSrc
267+
}
268+
258269
if err := blder.ctrl.Watch(w.src, w.eventhandler, allPredicates...); err != nil {
259270
return err
260271
}
261-
262272
}
263273
return nil
264274
}

pkg/builder/controller_test.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,14 +371,61 @@ var _ = Describe("application", func() {
371371
Expect(err).NotTo(HaveOccurred())
372372
})
373373

374-
It("should support watching For & Owns as metadata", func() {
374+
It("should support watching For, Owns, and Watch as metadata", func() {
375+
statefulSetMaps := make(chan *metav1.PartialObjectMetadata)
376+
375377
bldr := ControllerManagedBy(mgr).
376378
For(&appsv1.Deployment{}, OnlyMetadata).
377-
Owns(&appsv1.ReplicaSet{}, OnlyMetadata)
379+
Owns(&appsv1.ReplicaSet{}, OnlyMetadata).
380+
Watches(&source.Kind{Type: &appsv1.StatefulSet{}},
381+
handler.EnqueueRequestsFromMapFunc(func(o client.Object) []reconcile.Request {
382+
ometa := o.(*metav1.PartialObjectMetadata)
383+
statefulSetMaps <- ometa
384+
return nil
385+
}),
386+
OnlyMetadata)
378387

379388
ctx, cancel := context.WithCancel(context.Background())
380389
defer cancel()
381390
doReconcileTest(ctx, "8", bldr, mgr, true)
391+
392+
By("Creating a new stateful set")
393+
set := &appsv1.StatefulSet{
394+
ObjectMeta: metav1.ObjectMeta{
395+
Namespace: "default",
396+
Name: "test1",
397+
Labels: map[string]string{
398+
"foo": "bar",
399+
},
400+
},
401+
Spec: appsv1.StatefulSetSpec{
402+
Selector: &metav1.LabelSelector{
403+
MatchLabels: map[string]string{"foo": "bar"},
404+
},
405+
Template: corev1.PodTemplateSpec{
406+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
407+
Spec: corev1.PodSpec{
408+
Containers: []corev1.Container{
409+
{
410+
Name: "nginx",
411+
Image: "nginx",
412+
},
413+
},
414+
},
415+
},
416+
},
417+
}
418+
err := mgr.GetClient().Create(context.TODO(), set)
419+
Expect(err).NotTo(HaveOccurred())
420+
421+
By("Checking that the mapping function has been called")
422+
Eventually(func() bool {
423+
metaSet := <-statefulSetMaps
424+
Expect(metaSet.Name).To(Equal(set.Name))
425+
Expect(metaSet.Namespace).To(Equal(set.Namespace))
426+
Expect(metaSet.Labels).To(Equal(set.Labels))
427+
return true
428+
}).Should(BeTrue())
382429
})
383430
})
384431
})

pkg/builder/options.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ func (p projectAs) ApplyToOwns(opts *OwnsInput) {
9494
opts.objectProjection = objectProjection(p)
9595
}
9696

97+
// ApplyToWatches applies this configuration to the given WatchesInput options.
98+
func (p projectAs) ApplyToWatches(opts *WatchesInput) {
99+
opts.objectProjection = objectProjection(p)
100+
}
101+
97102
var (
98103
// OnlyMetadata tells the controller to *only* cache metadata, and to watch
99104
// the the API server in metadata-only form. This is useful when watching
@@ -104,8 +109,9 @@ var (
104109
// unstructured cache.
105110
OnlyMetadata = projectAs(projectAsMetadata)
106111

107-
_ ForOption = OnlyMetadata
108-
_ OwnsOption = OnlyMetadata
112+
_ ForOption = OnlyMetadata
113+
_ OwnsOption = OnlyMetadata
114+
_ WatchesOption = OnlyMetadata
109115
)
110116

111117
// }}}

0 commit comments

Comments
 (0)