Skip to content

Commit 10497ed

Browse files
committed
Add option to use ConditionalSources in controller builder
1 parent f11b1a9 commit 10497ed

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

pkg/builder/controller.go

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/go-logr/logr"
2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2525
"k8s.io/apimachinery/pkg/runtime/schema"
26+
"k8s.io/client-go/discovery"
2627

2728
"sigs.k8s.io/controller-runtime/pkg/client"
2829
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
@@ -72,6 +73,7 @@ type ForInput struct {
7273
predicates []predicate.Predicate
7374
objectProjection objectProjection
7475
err error
76+
conditional bool
7577
}
7678

7779
// For defines the type of Object being *reconciled*, and configures the ControllerManagedBy to respond to create / delete /
@@ -97,6 +99,7 @@ type OwnsInput struct {
9799
object client.Object
98100
predicates []predicate.Predicate
99101
objectProjection objectProjection
102+
conditional bool
100103
}
101104

102105
// Owns defines types of Objects being *generated* by the ControllerManagedBy, and configures the ControllerManagedBy to respond to
@@ -118,6 +121,7 @@ type WatchesInput struct {
118121
eventhandler handler.EventHandler
119122
predicates []predicate.Predicate
120123
objectProjection objectProjection
124+
conditional bool
121125
}
122126

123127
// Watches exposes the lower-level ControllerManagedBy Watches functions through the builder. Consider using
@@ -216,13 +220,48 @@ func (blder *Builder) project(obj client.Object, proj objectProjection) (client.
216220
}
217221
}
218222

223+
func (blder *Builder) generateConditionalSource(typeForSrc client.Object) (source.Source, error) {
224+
gvk, err := getGvk(blder.forInput.object, blder.mgr.GetScheme())
225+
if err != nil {
226+
return nil, err
227+
}
228+
dc, err := discovery.NewDiscoveryClientForConfig(blder.mgr.GetConfig())
229+
if err != nil {
230+
return nil, err
231+
}
232+
existsInDiscovery := func() bool {
233+
resources, err := dc.ServerResourcesForGroupVersion(gvk.GroupVersion().String())
234+
if err != nil {
235+
return false
236+
}
237+
for _, res := range resources.APIResources {
238+
if res.Kind == gvk.Kind {
239+
return true
240+
}
241+
}
242+
return false
243+
}
244+
return &source.ConditionalKind{Kind: source.Kind{Type: typeForSrc}, DiscoveryCheck: existsInDiscovery}, nil
245+
246+
}
247+
219248
func (blder *Builder) doWatch() error {
220249
// Reconcile type
221250
typeForSrc, err := blder.project(blder.forInput.object, blder.forInput.objectProjection)
222251
if err != nil {
223252
return err
224253
}
225-
src := &source.Kind{Type: typeForSrc}
254+
255+
var src source.Source
256+
if blder.forInput.conditional {
257+
var err error
258+
src, err = blder.generateConditionalSource(typeForSrc)
259+
if err != nil {
260+
return err
261+
}
262+
} else {
263+
src = &source.Kind{Type: typeForSrc}
264+
}
226265
hdler := &handler.EnqueueRequestForObject{}
227266
allPredicates := append(blder.globalPredicates, blder.forInput.predicates...)
228267
if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
@@ -235,7 +274,17 @@ func (blder *Builder) doWatch() error {
235274
if err != nil {
236275
return err
237276
}
238-
src := &source.Kind{Type: typeForSrc}
277+
278+
var src source.Source
279+
if own.conditional {
280+
var err error
281+
src, err = blder.generateConditionalSource(typeForSrc)
282+
if err != nil {
283+
return err
284+
}
285+
} else {
286+
src = &source.Kind{Type: typeForSrc}
287+
}
239288
hdler := &handler.EnqueueRequestForOwner{
240289
OwnerType: blder.forInput.object,
241290
IsController: true,

pkg/builder/options.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ func (p projectAs) ApplyToWatches(opts *WatchesInput) {
9999
opts.objectProjection = objectProjection(p)
100100
}
101101

102+
// Conditional confirms that it should configure a ConditionalSource
103+
// that can be started/stopped/restarted based on the existence of
104+
// the input's type in discovery.
105+
type Conditional struct{}
106+
107+
func (s Conditional) ApplyToFor(opts *ForInput) {
108+
opts.conditional = true
109+
}
110+
111+
func (s Conditional) ApplyToOwns(opts *OwnsInput) {
112+
opts.conditional = true
113+
}
114+
102115
var (
103116
// OnlyMetadata tells the controller to *only* cache metadata, and to watch
104117
// the the API server in metadata-only form. This is useful when watching

0 commit comments

Comments
 (0)