-
Notifications
You must be signed in to change notification settings - Fork 43
/
finishable.go
84 lines (66 loc) · 2.21 KB
/
finishable.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package finishable
import (
"context"
ctrl "sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)
// Reconciler interface extends reconcile.Reconciler interface
// with the option to stop the reconciliation.
type Reconciler interface {
Reconcile(context.Context, reconcile.Request) (Result, error)
}
type Controller interface {
manager.Runnable
Watch(src source.Source, eventhandler handler.EventHandler, predicates ...predicate.Predicate) error
}
type Result struct {
reconcile.Result
Finished bool
}
type wrapper struct {
reconciler Reconciler
stopFunc func()
}
var _ reconcile.Reconciler = &wrapper{}
func (w *wrapper) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
res, err := w.reconciler.Reconcile(ctx, request)
if res.Finished {
w.stopFunc()
}
return res.Result, err
}
type controller struct {
reconcilerWrapper *wrapper
innerController ctrl.Controller
}
var _ Controller = &controller{}
func (c *controller) Watch(src source.Source, eventhandler handler.EventHandler, predicates ...predicate.Predicate) error {
return c.innerController.Watch(src, eventhandler, predicates...)
}
func (c *controller) Start(ctx context.Context) error {
innerCtx, innerCtxCancel := context.WithCancel(ctx)
// Using defer here in case the fllowing innerController.Start()
// will end with an error. In that case the context would not be closed.
// Closing a context multiple times is supported.
defer innerCtxCancel()
c.reconcilerWrapper.stopFunc = innerCtxCancel
return c.innerController.Start(innerCtx)
}
// NewController returns a controller that can be stopped from the Reconciler implementation.
func NewController(name string, mgr manager.Manager, reconciler Reconciler) (Controller, error) {
wrap := &wrapper{reconciler: reconciler}
innerController, err := ctrl.NewUnmanaged(name, mgr, ctrl.Options{
Reconciler: wrap,
})
if err != nil {
return nil, err
}
return &controller{
reconcilerWrapper: wrap,
innerController: innerController,
}, nil
}