From 13bba740ff6ea05a09b91e7b625fbcbdfea93d2f Mon Sep 17 00:00:00 2001 From: John Howard Date: Fri, 3 Mar 2023 10:03:39 -0800 Subject: [PATCH] Add cross-version compatibility with client-go 1.27 --- pkg/cache/multi_namespace_cache.go | 33 +++++++++++++++---- pkg/controller/controllertest/util.go | 46 +++++++++++++++++++++++++-- pkg/internal/source/event_handler.go | 12 +++++-- pkg/internal/source/kind.go | 2 +- pkg/source/source.go | 2 +- 5 files changed, 83 insertions(+), 12 deletions(-) diff --git a/pkg/cache/multi_namespace_cache.go b/pkg/cache/multi_namespace_cache.go index ee33fb0dd5..b80b74ba08 100644 --- a/pkg/cache/multi_namespace_cache.go +++ b/pkg/cache/multi_namespace_cache.go @@ -305,42 +305,63 @@ type multiNamespaceInformer struct { namespaceToInformer map[string]Informer } +type handlerRegistration struct { + handles map[string]toolscache.ResourceEventHandlerRegistration +} + +type syncer interface { + HasSynced() bool +} + +// HasSynced asserts that the handler has been called for the full initial state of the informer. +// This uses syncer to be compatible between client-go 1.27+ and older versions when the interface changed. +func (h handlerRegistration) HasSynced() bool { + for _, reg := range h.handles { + if s, ok := reg.(syncer); ok { + if !s.HasSynced() { + return false + } + } + } + return true +} + var _ Informer = &multiNamespaceInformer{} // AddEventHandler adds the handler to each namespaced informer. func (i *multiNamespaceInformer) AddEventHandler(handler toolscache.ResourceEventHandler) (toolscache.ResourceEventHandlerRegistration, error) { - handles := make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer)) + handles := handlerRegistration{handles: make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer))} for ns, informer := range i.namespaceToInformer { registration, err := informer.AddEventHandler(handler) if err != nil { return nil, err } - handles[ns] = registration + handles.handles[ns] = registration } return handles, nil } // AddEventHandlerWithResyncPeriod adds the handler with a resync period to each namespaced informer. func (i *multiNamespaceInformer) AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration) (toolscache.ResourceEventHandlerRegistration, error) { - handles := make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer)) + handles := handlerRegistration{handles: make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer))} for ns, informer := range i.namespaceToInformer { registration, err := informer.AddEventHandlerWithResyncPeriod(handler, resyncPeriod) if err != nil { return nil, err } - handles[ns] = registration + handles.handles[ns] = registration } return handles, nil } // RemoveEventHandler removes a formerly added event handler given by its registration handle. func (i *multiNamespaceInformer) RemoveEventHandler(h toolscache.ResourceEventHandlerRegistration) error { - handles, ok := h.(map[string]toolscache.ResourceEventHandlerRegistration) + handles, ok := h.(handlerRegistration) if !ok { return fmt.Errorf("it is not the registration returned by multiNamespaceInformer") } for ns, informer := range i.namespaceToInformer { - registration, ok := handles[ns] + registration, ok := handles.handles[ns] if !ok { continue } diff --git a/pkg/controller/controllertest/util.go b/pkg/controller/controllertest/util.go index 17641e9c02..60ec61edec 100644 --- a/pkg/controller/controllertest/util.go +++ b/pkg/controller/controllertest/util.go @@ -33,7 +33,49 @@ type FakeInformer struct { // RunCount is incremented each time RunInformersAndControllers is called RunCount int - handlers []cache.ResourceEventHandler + handlers []eventHandlerWrapper +} + +type modernResourceEventHandler interface { + OnAdd(obj interface{}, isInInitialList bool) + OnUpdate(oldObj, newObj interface{}) + OnDelete(obj interface{}) +} + +type legacyResourceEventHandler interface { + OnAdd(obj interface{}) + OnUpdate(oldObj, newObj interface{}) + OnDelete(obj interface{}) +} + +// eventHandlerWrapper wraps a ResourceEventHandler in a manner that is compatible with client-go 1.27+ and older. +// The interface was changed in these versions. +type eventHandlerWrapper struct { + handler any +} + +func (e eventHandlerWrapper) OnAdd(obj interface{}) { + if m, ok := e.handler.(modernResourceEventHandler); ok { + m.OnAdd(obj, false) + return + } + e.handler.(legacyResourceEventHandler).OnAdd(obj) +} + +func (e eventHandlerWrapper) OnUpdate(oldObj, newObj interface{}) { + if m, ok := e.handler.(modernResourceEventHandler); ok { + m.OnUpdate(oldObj, newObj) + return + } + e.handler.(legacyResourceEventHandler).OnUpdate(oldObj, newObj) +} + +func (e eventHandlerWrapper) OnDelete(obj interface{}) { + if m, ok := e.handler.(modernResourceEventHandler); ok { + m.OnDelete(obj) + return + } + e.handler.(legacyResourceEventHandler).OnDelete(obj) } // AddIndexers does nothing. TODO(community): Implement this. @@ -58,7 +100,7 @@ func (f *FakeInformer) HasSynced() bool { // AddEventHandler implements the Informer interface. Adds an EventHandler to the fake Informers. TODO(community): Implement Registration. func (f *FakeInformer) AddEventHandler(handler cache.ResourceEventHandler) (cache.ResourceEventHandlerRegistration, error) { - f.handlers = append(f.handlers, handler) + f.handlers = append(f.handlers, eventHandlerWrapper{handler}) return nil, nil } diff --git a/pkg/internal/source/event_handler.go b/pkg/internal/source/event_handler.go index 7843135c08..ae8404a1fa 100644 --- a/pkg/internal/source/event_handler.go +++ b/pkg/internal/source/event_handler.go @@ -32,8 +32,6 @@ import ( var log = logf.RuntimeLog.WithName("source").WithName("EventHandler") -var _ cache.ResourceEventHandler = &EventHandler{} - // NewEventHandler creates a new EventHandler. func NewEventHandler(ctx context.Context, queue workqueue.RateLimitingInterface, handler handler.EventHandler, predicates []predicate.Predicate) *EventHandler { return &EventHandler{ @@ -55,6 +53,16 @@ type EventHandler struct { predicates []predicate.Predicate } +// HandlerFuncs converts EventHandler to a ResourceEventHandlerFuncs +// TODO: switch to ResourceEventHandlerDetailedFuncs with client-go 1.27 +func (e *EventHandler) HandlerFuncs() cache.ResourceEventHandlerFuncs { + return cache.ResourceEventHandlerFuncs{ + AddFunc: e.OnAdd, + UpdateFunc: e.OnUpdate, + DeleteFunc: e.OnDelete, + } +} + // OnAdd creates CreateEvent and calls Create on EventHandler. func (e *EventHandler) OnAdd(obj interface{}) { c := event.CreateEvent{} diff --git a/pkg/internal/source/kind.go b/pkg/internal/source/kind.go index 2e765acce8..7ba183a74d 100644 --- a/pkg/internal/source/kind.go +++ b/pkg/internal/source/kind.go @@ -79,7 +79,7 @@ func (ks *Kind) Start(ctx context.Context, handler handler.EventHandler, queue w return } - _, err := i.AddEventHandler(NewEventHandler(ctx, queue, handler, prct)) + _, err := i.AddEventHandler(NewEventHandler(ctx, queue, handler, prct).HandlerFuncs()) if err != nil { ks.started <- err return diff --git a/pkg/source/source.go b/pkg/source/source.go index 5fb7c439b6..17c4ec015c 100644 --- a/pkg/source/source.go +++ b/pkg/source/source.go @@ -204,7 +204,7 @@ func (is *Informer) Start(ctx context.Context, handler handler.EventHandler, que return fmt.Errorf("must specify Informer.Informer") } - _, err := is.Informer.AddEventHandler(internal.NewEventHandler(ctx, queue, handler, prct)) + _, err := is.Informer.AddEventHandler(internal.NewEventHandler(ctx, queue, handler, prct).HandlerFuncs()) if err != nil { return err }