/
objecttemplate_controller.go
160 lines (139 loc) · 4.53 KB
/
objecttemplate_controller.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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package objecttemplate
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/api/meta"
"package-operator.run/package-operator/internal/preflight"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/source"
"package-operator.run/package-operator/internal/controllers"
"package-operator.run/package-operator/internal/dynamiccache"
)
type dynamicCache interface {
client.Reader
Source() source.Source
Free(ctx context.Context, obj client.Object) error
Watch(ctx context.Context, owner client.Object, obj runtime.Object) error
OwnersForGKV(gvk schema.GroupVersionKind) []dynamiccache.OwnerReference
}
type reconciler interface {
Reconcile(ctx context.Context, pkg genericObjectTemplate) (ctrl.Result, error)
}
type preflightChecker interface {
Check(
ctx context.Context, owner, obj client.Object,
) (violations []preflight.Violation, err error)
}
type GenericObjectTemplateController struct {
newObjectTemplate genericObjectTemplateFactory
log logr.Logger
scheme *runtime.Scheme
client client.Client
uncachedClient client.Client
dynamicCache dynamicCache
reconciler []reconciler
}
func NewObjectTemplateController(
client, uncachedClient client.Client,
log logr.Logger,
dynamicCache dynamicCache,
scheme *runtime.Scheme,
restMapper meta.RESTMapper,
) *GenericObjectTemplateController {
return newGenericObjectTemplateController(
client, uncachedClient, log, dynamicCache, scheme,
restMapper, newGenericObjectTemplate)
}
func NewClusterObjectTemplateController(
client, uncachedClient client.Client,
log logr.Logger,
dynamicCache dynamicCache,
scheme *runtime.Scheme,
restMapper meta.RESTMapper,
) *GenericObjectTemplateController {
return newGenericObjectTemplateController(
client, uncachedClient, log, dynamicCache, scheme,
restMapper, newGenericClusterObjectTemplate)
}
func newGenericObjectTemplateController(
client, uncachedClient client.Client,
log logr.Logger,
dynamicCache dynamicCache,
scheme *runtime.Scheme,
restMapper meta.RESTMapper,
newObjectTemplate genericObjectTemplateFactory,
) *GenericObjectTemplateController {
return &GenericObjectTemplateController{
newObjectTemplate: newObjectTemplate,
log: log,
scheme: scheme,
client: client,
uncachedClient: uncachedClient,
dynamicCache: dynamicCache,
reconciler: []reconciler{
newTemplateReconciler(scheme, client, uncachedClient, dynamicCache, preflight.List{
preflight.NewAPIExistence(restMapper),
preflight.NewEmptyNamespaceNoDefault(restMapper),
preflight.NewNamespaceEscalation(restMapper),
}),
},
}
}
func (c *GenericObjectTemplateController) Reconcile(
ctx context.Context, req ctrl.Request,
) (ctrl.Result, error) {
log := c.log.WithValues("ObjectTemplate", req.String())
defer log.Info("reconciled")
ctx = logr.NewContext(ctx, log)
objectTemplate := c.newObjectTemplate(c.scheme)
if err := c.client.Get(
ctx, req.NamespacedName, objectTemplate.ClientObject()); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
if !objectTemplate.ClientObject().GetDeletionTimestamp().IsZero() {
if err := controllers.FreeCacheAndRemoveFinalizer(
ctx, c.client, objectTemplate.ClientObject(), c.dynamicCache); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
if err := controllers.EnsureCachedFinalizer(ctx, c.client, objectTemplate.ClientObject()); err != nil {
return ctrl.Result{}, err
}
var (
res ctrl.Result
err error
)
for _, r := range c.reconciler {
res, err = r.Reconcile(ctx, objectTemplate)
if err != nil || !res.IsZero() {
break
}
}
if err != nil {
return res, err
}
return res, c.updateStatus(ctx, objectTemplate)
}
func (c *GenericObjectTemplateController) updateStatus(ctx context.Context, objectTemplate genericObjectTemplate) error {
objectTemplate.UpdatePhase()
if err := c.client.Status().Update(ctx, objectTemplate.ClientObject()); err != nil {
return fmt.Errorf("updating ObjectTemplate status: %w", err)
}
return nil
}
func (c *GenericObjectTemplateController) SetupWithManager(
mgr ctrl.Manager,
) error {
objectTemplate := c.newObjectTemplate(c.scheme).ClientObject()
return ctrl.NewControllerManagedBy(mgr).
For(objectTemplate).
Watches(c.dynamicCache.Source(), &dynamiccache.EnqueueWatchingObjects{
WatcherRefGetter: c.dynamicCache,
WatcherType: objectTemplate,
}).Complete(c)
}