Skip to content

Commit bfd1cf9

Browse files
[release-0.19] ✨ Add EnableWatchBookmarks option to cache informers (#3018)
* Ensure all WatchFunc enable watch and boomarks AllowWatchBookmarks is generally pretty safe to enable as it has been available in Kuberentes for a long while, and the server ignores the flag if it doesn't implement it (per docs). Signed-off-by: Vince Prignano <[email protected]> * Defaults to false for 0.19 Signed-off-by: Vince Prignano <[email protected]> --------- Signed-off-by: Vince Prignano <[email protected]> Co-authored-by: Vince Prignano <[email protected]>
1 parent 013f46f commit bfd1cf9

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

pkg/cache/cache.go

+37-1
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,18 @@ type Options struct {
222222
// DefaultNamespaces.
223223
DefaultUnsafeDisableDeepCopy *bool
224224

225+
// DefaultEnableWatchBookmarks requests watch events with type "BOOKMARK".
226+
// Servers that do not implement bookmarks may ignore this flag and
227+
// bookmarks are sent at the server's discretion. Clients should not
228+
// assume bookmarks are returned at any specific interval, nor may they
229+
// assume the server will send any BOOKMARK event during a session.
230+
//
231+
// This will be used for all object types, unless it is set in ByObject or
232+
// DefaultNamespaces.
233+
//
234+
// Defaults to false.
235+
DefaultEnableWatchBookmarks *bool
236+
225237
// ByObject restricts the cache's ListWatch to the desired fields per GVK at the specified object.
226238
// If unset, this will fall through to the Default* settings.
227239
ByObject map[client.Object]ByObject
@@ -272,6 +284,15 @@ type ByObject struct {
272284
// Be very careful with this, when enabled you must DeepCopy any object before mutating it,
273285
// otherwise you will mutate the object in the cache.
274286
UnsafeDisableDeepCopy *bool
287+
288+
// EnableWatchBookmarks requests watch events with type "BOOKMARK".
289+
// Servers that do not implement bookmarks may ignore this flag and
290+
// bookmarks are sent at the server's discretion. Clients should not
291+
// assume bookmarks are returned at any specific interval, nor may they
292+
// assume the server will send any BOOKMARK event during a session.
293+
//
294+
// Defaults to false.
295+
EnableWatchBookmarks *bool
275296
}
276297

277298
// Config describes all potential options for a given watch.
@@ -298,6 +319,15 @@ type Config struct {
298319
// UnsafeDisableDeepCopy specifies if List and Get requests against the
299320
// cache should not DeepCopy. A nil value allows to default this.
300321
UnsafeDisableDeepCopy *bool
322+
323+
// EnableWatchBookmarks requests watch events with type "BOOKMARK".
324+
// Servers that do not implement bookmarks may ignore this flag and
325+
// bookmarks are sent at the server's discretion. Clients should not
326+
// assume bookmarks are returned at any specific interval, nor may they
327+
// assume the server will send any BOOKMARK event during a session.
328+
//
329+
// Defaults to false.
330+
EnableWatchBookmarks *bool
301331
}
302332

303333
// NewCacheFunc - Function for creating a new cache from the options and a rest config.
@@ -367,6 +397,7 @@ func optionDefaultsToConfig(opts *Options) Config {
367397
FieldSelector: opts.DefaultFieldSelector,
368398
Transform: opts.DefaultTransform,
369399
UnsafeDisableDeepCopy: opts.DefaultUnsafeDisableDeepCopy,
400+
EnableWatchBookmarks: opts.DefaultEnableWatchBookmarks,
370401
}
371402
}
372403

@@ -376,6 +407,7 @@ func byObjectToConfig(byObject ByObject) Config {
376407
FieldSelector: byObject.Field,
377408
Transform: byObject.Transform,
378409
UnsafeDisableDeepCopy: byObject.UnsafeDisableDeepCopy,
410+
EnableWatchBookmarks: byObject.EnableWatchBookmarks,
379411
}
380412
}
381413

@@ -398,6 +430,7 @@ func newCache(restConfig *rest.Config, opts Options) newCacheFunc {
398430
Transform: config.Transform,
399431
WatchErrorHandler: opts.DefaultWatchErrorHandler,
400432
UnsafeDisableDeepCopy: ptr.Deref(config.UnsafeDisableDeepCopy, false),
433+
EnableWatchBookmarks: ptr.Deref(config.EnableWatchBookmarks, false),
401434
NewInformer: opts.newInformer,
402435
}),
403436
readerFailOnMissingInformer: opts.ReaderFailOnMissingInformer,
@@ -482,6 +515,7 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
482515
byObject.Field = defaultedConfig.FieldSelector
483516
byObject.Transform = defaultedConfig.Transform
484517
byObject.UnsafeDisableDeepCopy = defaultedConfig.UnsafeDisableDeepCopy
518+
byObject.EnableWatchBookmarks = defaultedConfig.EnableWatchBookmarks
485519
}
486520

487521
opts.ByObject[obj] = byObject
@@ -523,7 +557,9 @@ func defaultConfig(toDefault, defaultFrom Config) Config {
523557
if toDefault.UnsafeDisableDeepCopy == nil {
524558
toDefault.UnsafeDisableDeepCopy = defaultFrom.UnsafeDisableDeepCopy
525559
}
526-
560+
if toDefault.EnableWatchBookmarks == nil {
561+
toDefault.EnableWatchBookmarks = defaultFrom.EnableWatchBookmarks
562+
}
527563
return toDefault
528564
}
529565

pkg/cache/defaulting_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,30 @@ func TestDefaultOpts(t *testing.T) {
224224
return cmp.Diff(expected, o.ByObject[pod].UnsafeDisableDeepCopy)
225225
},
226226
},
227+
{
228+
name: "ByObject.EnableWatchBookmarks gets defaulted from DefaultEnableWatchBookmarks",
229+
in: Options{
230+
ByObject: map[client.Object]ByObject{pod: {}},
231+
DefaultEnableWatchBookmarks: ptr.To(true),
232+
},
233+
234+
verification: func(o Options) string {
235+
expected := ptr.To(true)
236+
return cmp.Diff(expected, o.ByObject[pod].EnableWatchBookmarks)
237+
},
238+
},
239+
{
240+
name: "ByObject.EnableWatchBookmarks doesn't get defaulted when set",
241+
in: Options{
242+
ByObject: map[client.Object]ByObject{pod: {EnableWatchBookmarks: ptr.To(false)}},
243+
DefaultEnableWatchBookmarks: ptr.To(true),
244+
},
245+
246+
verification: func(o Options) string {
247+
expected := ptr.To(false)
248+
return cmp.Diff(expected, o.ByObject[pod].EnableWatchBookmarks)
249+
},
250+
},
227251
{
228252
name: "DefaultNamespace label selector gets defaulted from DefaultLabelSelector",
229253
in: Options{

pkg/cache/internal/informers.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type InformersOpts struct {
5151
Selector Selector
5252
Transform cache.TransformFunc
5353
UnsafeDisableDeepCopy bool
54+
EnableWatchBookmarks bool
5455
WatchErrorHandler cache.WatchErrorHandler
5556
}
5657

@@ -78,6 +79,7 @@ func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
7879
selector: options.Selector,
7980
transform: options.Transform,
8081
unsafeDisableDeepCopy: options.UnsafeDisableDeepCopy,
82+
enableWatchBookmarks: options.EnableWatchBookmarks,
8183
newInformer: newInformer,
8284
watchErrorHandler: options.WatchErrorHandler,
8385
}
@@ -174,6 +176,7 @@ type Informers struct {
174176
selector Selector
175177
transform cache.TransformFunc
176178
unsafeDisableDeepCopy bool
179+
enableWatchBookmarks bool
177180

178181
// NewInformer allows overriding of the shared index informer constructor for testing.
179182
newInformer func(cache.ListerWatcher, runtime.Object, time.Duration, cache.Indexers) cache.SharedIndexInformer
@@ -361,8 +364,10 @@ func (ip *Informers) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.O
361364
return listWatcher.ListFunc(opts)
362365
},
363366
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
364-
ip.selector.ApplyToList(&opts)
365367
opts.Watch = true // Watch needs to be set to true separately
368+
opts.AllowWatchBookmarks = ip.enableWatchBookmarks
369+
370+
ip.selector.ApplyToList(&opts)
366371
return listWatcher.WatchFunc(opts)
367372
},
368373
}, obj, calculateResyncPeriod(ip.resync), cache.Indexers{
@@ -444,6 +449,9 @@ func (ip *Informers) makeListWatcher(gvk schema.GroupVersionKind, obj runtime.Ob
444449
},
445450
// Setup the watch function
446451
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
452+
opts.Watch = true // Watch needs to be set to true separately
453+
opts.AllowWatchBookmarks = ip.enableWatchBookmarks
454+
447455
if namespace != "" {
448456
return resources.Namespace(namespace).Watch(ip.ctx, opts)
449457
}
@@ -486,6 +494,9 @@ func (ip *Informers) makeListWatcher(gvk schema.GroupVersionKind, obj runtime.Ob
486494
},
487495
// Setup the watch function
488496
WatchFunc: func(opts metav1.ListOptions) (watcher watch.Interface, err error) {
497+
opts.Watch = true // Watch needs to be set to true separately
498+
opts.AllowWatchBookmarks = ip.enableWatchBookmarks
499+
489500
if namespace != "" {
490501
watcher, err = resources.Namespace(namespace).Watch(ip.ctx, opts)
491502
} else {
@@ -527,6 +538,9 @@ func (ip *Informers) makeListWatcher(gvk schema.GroupVersionKind, obj runtime.Ob
527538
},
528539
// Setup the watch function
529540
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
541+
opts.Watch = true // Watch needs to be set to true separately
542+
opts.AllowWatchBookmarks = ip.enableWatchBookmarks
543+
530544
// Build the request.
531545
req := client.Get().Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec)
532546
if namespace != "" {

0 commit comments

Comments
 (0)