Skip to content

Commit 5b25228

Browse files
committed
Separate controllers factory
Use a dedicated controllers factory interface, rather than creating controllers inline as needed. This will make unit tests much easier to plug in, and move all controllers creation code in the correct package.
1 parent e615eb3 commit 5b25228

File tree

3 files changed

+52
-26
lines changed

3 files changed

+52
-26
lines changed

pkg/controller/controller.go

+17-3
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,22 @@ import (
2626

2727
const maxProcessRetry = 6
2828

29+
// Interface describe a standard kubernetes controller
30+
type Interface interface {
31+
Start()
32+
Stop()
33+
}
34+
35+
// Factory generate controllers
36+
type Factory struct{}
37+
2938
// Controller is a generic kubernetes controller
3039
type Controller struct {
40+
name string
3141
stopCh chan struct{}
3242
doneCh chan struct{}
3343
notifier event.Notifier
3444
config *config.KfConfig
35-
name string
3645
queue workqueue.RateLimitingInterface
3746
informer cache.SharedIndexInformer
3847
}
@@ -99,7 +108,7 @@ func (c *Controller) Start() {
99108
go c.informer.Run(c.stopCh)
100109

101110
if !cache.WaitForCacheSync(c.stopCh, c.informer.HasSynced) {
102-
utilruntime.HandleError(fmt.Errorf("Timed out waiting for caches to sync"))
111+
utilruntime.HandleError(fmt.Errorf("Timed out waiting for cache sync"))
103112
return
104113
}
105114

@@ -149,7 +158,7 @@ func (c *Controller) processItem(key string) error {
149158
rawobj, exists, err := c.informer.GetIndexer().GetByKey(key)
150159

151160
if err != nil {
152-
return fmt.Errorf("error fetching object with key %s from store: %v", key, err)
161+
return fmt.Errorf("error fetching %s from store: %v", key, err)
153162
}
154163

155164
if !exists {
@@ -183,3 +192,8 @@ func (c *Controller) processItem(key string) error {
183192
func (c *Controller) enqueue(notif *event.Notification) {
184193
c.notifier.Send(notif)
185194
}
195+
196+
// NewController create a controller.Controller
197+
func (f *Factory) NewController(client cache.ListerWatcher, notifier event.Notifier, name string, config *config.KfConfig) Interface {
198+
return New(client, notifier, name, config)
199+
}

pkg/observer/observer.go

+33-22
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,29 @@ import (
1717
"k8s.io/apimachinery/pkg/runtime/schema"
1818
"k8s.io/client-go/discovery"
1919
"k8s.io/client-go/dynamic"
20+
"k8s.io/client-go/tools/cache"
2021
)
2122

2223
const discoveryInterval = 60 * time.Second
2324

24-
// Observer watch api-server and manage kubernetes controllers
25+
// ControllerFactory make controllers generation interchangeable
26+
type ControllerFactory interface {
27+
NewController(client cache.ListerWatcher, notifier event.Notifier,
28+
name string, config *config.KfConfig) controller.Interface
29+
}
30+
31+
type controllerCollection map[string]controller.Interface
32+
33+
// Observer watch api-server and manage kubernetes controllers lifecyles
2534
type Observer struct {
26-
stop chan struct{}
27-
done chan struct{}
28-
notif event.Notifier
29-
disc discovery.DiscoveryInterface
30-
cpool dynamic.ClientPool
31-
ctrls map[string]*controller.Controller
32-
config *config.KfConfig
35+
config *config.KfConfig
36+
stopCh chan struct{}
37+
doneCh chan struct{}
38+
notifier event.Notifier
39+
discovery discovery.DiscoveryInterface
40+
cpool dynamic.ClientPool
41+
ctrls controllerCollection
42+
factory ControllerFactory
3343
}
3444

3545
type gvk struct {
@@ -40,27 +50,28 @@ type gvk struct {
4050
type resources map[string]*gvk
4151

4252
// New returns a new observer, that will watch API resources and create controllers
43-
func New(config *config.KfConfig, notif event.Notifier) *Observer {
53+
func New(config *config.KfConfig, notif event.Notifier, factory ControllerFactory) *Observer {
4454
return &Observer{
45-
config: config,
46-
notif: notif,
47-
disc: discovery.NewDiscoveryClientForConfigOrDie(config.Client),
48-
cpool: dynamic.NewDynamicClientPool(config.Client),
49-
ctrls: make(map[string]*controller.Controller),
55+
config: config,
56+
notifier: notif,
57+
discovery: discovery.NewDiscoveryClientForConfigOrDie(config.Client),
58+
cpool: dynamic.NewDynamicClientPool(config.Client),
59+
ctrls: make(controllerCollection),
60+
factory: factory,
5061
}
5162
}
5263

5364
// Start starts the observer in a detached goroutine
5465
func (c *Observer) Start() *Observer {
5566
c.config.Logger.Info("Starting all kubernetes controllers")
5667

57-
c.stop = make(chan struct{})
58-
c.done = make(chan struct{})
68+
c.stopCh = make(chan struct{})
69+
c.doneCh = make(chan struct{})
5970

6071
go func() {
6172
ticker := time.NewTicker(discoveryInterval)
6273
defer ticker.Stop()
63-
defer close(c.done)
74+
defer close(c.doneCh)
6475

6576
for {
6677
err := c.refresh()
@@ -69,7 +80,7 @@ func (c *Observer) Start() *Observer {
6980
}
7081

7182
select {
72-
case <-c.stop:
83+
case <-c.stopCh:
7384
return
7485
case <-ticker.C:
7586
}
@@ -83,17 +94,17 @@ func (c *Observer) Start() *Observer {
8394
func (c *Observer) Stop() {
8495
c.config.Logger.Info("Stopping all kubernetes controllers")
8596

86-
close(c.stop)
97+
close(c.stopCh)
8798

8899
for _, ct := range c.ctrls {
89100
ct.Stop()
90101
}
91102

92-
<-c.done
103+
<-c.doneCh
93104
}
94105

95106
func (c *Observer) refresh() error {
96-
groups, err := c.disc.ServerResources()
107+
groups, err := c.discovery.ServerResources()
97108
if err != nil {
98109
return fmt.Errorf("failed to collect server resources: %v", err)
99110
}
@@ -114,7 +125,7 @@ func (c *Observer) refresh() error {
114125

115126
client := cl.Resource(res.apiResource.DeepCopy(), metav1.NamespaceAll)
116127

117-
c.ctrls[name] = controller.New(client, c.notif, cname, c.config)
128+
c.ctrls[name] = c.factory.NewController(client, c.notifier, cname, c.config)
118129
go c.ctrls[name].Start()
119130
}
120131

pkg/run/run.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"syscall"
99

1010
"github.com/bpineau/katafygio/config"
11+
"github.com/bpineau/katafygio/pkg/controller"
1112
"github.com/bpineau/katafygio/pkg/event"
1213
"github.com/bpineau/katafygio/pkg/health"
1314
"github.com/bpineau/katafygio/pkg/observer"
@@ -24,7 +25,7 @@ func Run(config *config.KfConfig) {
2425

2526
evts := event.New()
2627
reco := recorder.New(config, evts).Start()
27-
obsv := observer.New(config, evts).Start()
28+
obsv := observer.New(config, evts, &controller.Factory{}).Start()
2829

2930
http, err := health.New(config).Start()
3031
if err != nil {

0 commit comments

Comments
 (0)