Skip to content

Commit

Permalink
✨ Allow user to define how create managed objects
Browse files Browse the repository at this point in the history
* Allow the user to specify in the options how to create the client,
cache, and how to construct the delegating client.

fixes kubernetes-sigs#226
  • Loading branch information
Shawn Hurley committed Nov 29, 2018
1 parent 8991a78 commit c71ff3f
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 18 deletions.
52 changes: 36 additions & 16 deletions pkg/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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
Expand Down
18 changes: 16 additions & 2 deletions pkg/manager/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
},
})
Expand All @@ -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")
},
})
Expand All @@ -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) {
Expand Down

0 comments on commit c71ff3f

Please sign in to comment.