From c71ff3fd0e44beeff78fb5fee0ece7c274ca5290 Mon Sep 17 00:00:00 2001 From: Shawn Hurley Date: Thu, 29 Nov 2018 15:00:05 -0500 Subject: [PATCH] :sparkles: Allow user to define how create managed objects * Allow the user to specify in the options how to create the client, cache, and how to construct the delegating client. fixes #226 --- pkg/manager/manager.go | 52 +++++++++++++++++++++++++------------ pkg/manager/manager_test.go | 18 +++++++++++-- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 1230c74573..b91574b243 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -118,15 +118,27 @@ type Options struct { // for serving prometheus metrics MetricsBindAddress string + // Functions to all for a user to customize the values that will be injected. + NewCache NewCacheFunc + NewClient NewClientFunc + NewDelegatingClient NewDelegatingClientFunc + // Dependency injection for testing - newCache func(config *rest.Config, opts cache.Options) (cache.Cache, error) - newClient func(config *rest.Config, options client.Options) (client.Client, error) newRecorderProvider func(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger) (recorder.Provider, error) newResourceLock func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error) newAdmissionDecoder func(scheme *runtime.Scheme) (types.Decoder, error) newMetricsListener func(addr string) (net.Listener, error) } +// NewCacheFunc allows a user to define how to create a cache +type NewCacheFunc func(config *rest.Config, opts cache.Options) (cache.Cache, error) + +// NewClientFunc allows a user to define how to create a client +type NewClientFunc func(config *rest.Config, options client.Options) (client.Client, error) + +// NewDelegatingClientFunc allows a user to define how to create the delegating client +type NewDelegatingClientFunc func(cache cache.Cache, client client.Client) client.Client + // Runnable allows a component to be started. type Runnable interface { // Start starts running the component. The component will stop running when the channel is closed. @@ -160,13 +172,13 @@ func New(config *rest.Config, options Options) (Manager, error) { } // Create the Client for Write operations. - writeObj, err := options.newClient(config, client.Options{Scheme: options.Scheme, Mapper: mapper}) + writeObj, err := options.NewClient(config, client.Options{Scheme: options.Scheme, Mapper: mapper}) if err != nil { return nil, err } // Create the cache for the cached read client and registering informers - cache, err := options.newCache(config, cache.Options{Scheme: options.Scheme, Mapper: mapper, Resync: options.SyncPeriod, Namespace: options.Namespace}) + cache, err := options.NewCache(config, cache.Options{Scheme: options.Scheme, Mapper: mapper, Resync: options.SyncPeriod, Namespace: options.Namespace}) if err != nil { return nil, err } @@ -209,14 +221,7 @@ func New(config *rest.Config, options Options) (Manager, error) { errChan: make(chan error), cache: cache, fieldIndexes: cache, - client: client.DelegatingClient{ - Reader: &client.DelegatingReader{ - CacheReader: cache, - ClientReader: writeObj, - }, - Writer: writeObj, - StatusClient: writeObj, - }, + client: options.NewDelegatingClient(cache, writeObj), recorderProvider: recorderProvider, resourceLock: resourceLock, mapper: mapper, @@ -226,6 +231,17 @@ func New(config *rest.Config, options Options) (Manager, error) { }, nil } +func defaultDelagatingClient(cache cache.Cache, c client.Client) client.Client { + return &client.DelegatingClient{ + Reader: &client.DelegatingReader{ + CacheReader: cache, + ClientReader: c, + }, + Writer: c, + StatusClient: c, + } +} + // setOptionsDefaults set default values for Options fields func setOptionsDefaults(options Options) Options { // Use the Kubernetes client-go scheme if none is specified @@ -238,13 +254,17 @@ func setOptionsDefaults(options Options) Options { } // Allow newClient to be mocked - if options.newClient == nil { - options.newClient = client.New + if options.NewClient == nil { + options.NewClient = client.New } // Allow newCache to be mocked - if options.newCache == nil { - options.newCache = cache.New + if options.NewCache == nil { + options.NewCache = cache.New + } + + if options.NewDelegatingClient == nil { + options.NewDelegatingClient = defaultDelagatingClient } // Allow newRecorderProvider to be mocked diff --git a/pkg/manager/manager_test.go b/pkg/manager/manager_test.go index 759750708d..4980095a30 100644 --- a/pkg/manager/manager_test.go +++ b/pkg/manager/manager_test.go @@ -72,7 +72,7 @@ var _ = Describe("manger.Manager", func() { It("should return an error it can't create a client.Client", func(done Done) { m, err := New(cfg, Options{ - newClient: func(config *rest.Config, options client.Options) (client.Client, error) { + NewClient: func(config *rest.Config, options client.Options) (client.Client, error) { return nil, fmt.Errorf("expected error") }, }) @@ -85,7 +85,7 @@ var _ = Describe("manger.Manager", func() { It("should return an error it can't create a cache.Cache", func(done Done) { m, err := New(cfg, Options{ - newCache: func(config *rest.Config, opts cache.Options) (cache.Cache, error) { + NewCache: func(config *rest.Config, opts cache.Options) (cache.Cache, error) { return nil, fmt.Errorf("expected error") }, }) @@ -95,6 +95,20 @@ var _ = Describe("manger.Manager", func() { close(done) }) + + It("should create a client defined in by the new delegating client function", func(done Done) { + m, err := New(cfg, Options{ + NewDelegatingClient: func(cache cache.Cache, client client.Client) client.Client { + return nil + }, + }) + Expect(m).ToNot(BeNil()) + Expect(err).ToNot(HaveOccurred()) + Expect(m.GetClient()).To(BeNil()) + + close(done) + }) + It("should return an error it can't create a recorder.Provider", func(done Done) { m, err := New(cfg, Options{ newRecorderProvider: func(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger) (recorder.Provider, error) {