@@ -23,8 +23,6 @@ import (
23
23
24
24
"github.com/opdev/subreconciler"
25
25
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
26
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
27
- "k8s.io/apimachinery/pkg/runtime"
28
26
"k8s.io/apimachinery/pkg/runtime/schema"
29
27
"k8s.io/apimachinery/pkg/types"
30
28
ctrl "sigs.k8s.io/controller-runtime"
@@ -33,6 +31,11 @@ import (
33
31
logf "sigs.k8s.io/controller-runtime/pkg/log"
34
32
)
35
33
34
+ // Generator is an interface that wraps the Generate method.
35
+ //
36
+ // It takes a context assumed to be scoped to the current reconcile loop and a
37
+ // client.Object that is the recipient of the new object state. It returns an
38
+ // error if something goes wrong over the course of performing this operation.
36
39
type Generator interface {
37
40
Generate (context.Context , client.Object ) error
38
41
}
@@ -43,6 +46,20 @@ type Generator interface {
43
46
// controller logic.
44
47
type GenerateFn [T client.Object ] func (SecondaryReconciler , context.Context , T ) error
45
48
49
+ // Modifier is an interface that wraps the Modify method.
50
+ //
51
+ // It takes a context assumed to be scoped to the current reconcile loop and two
52
+ // client.Object arguments - the first should be the observed object that
53
+ // represents what is on the cluster currently, and the second is what the
54
+ // reconciler determines should be installed on the cluster instead.
55
+ //
56
+ // If there are relevant differences between the two objects, the first is
57
+ // updated with the values from the second so that they are now the same in
58
+ // those relevant ways.
59
+ //
60
+ // Returns an bool representing whether a change was made to the first
61
+ // client.Object as well as an error if something goes wrong over the course of
62
+ // performing this operation.
46
63
type Modifier interface {
47
64
Modify (context.Context , client.Object , client.Object ) (bool , error )
48
65
}
@@ -54,6 +71,12 @@ type Modifier interface {
54
71
// itself.
55
72
type ModifyFn [T client.Object ] func (SecondaryReconciler , context.Context , T , T ) (bool , error )
56
73
74
+ // WriteResponder is an interface that wraps the OnWrite method.
75
+ //
76
+ // It takes a context assumed to be scoped to the current reconcile loop and
77
+ // performs any work that needs to be done after a write is performed.
78
+ //
79
+ // Returns an error if something goes wrong.
57
80
type WriteResponder interface {
58
81
OnWrite (context.Context ) error
59
82
}
@@ -114,32 +137,42 @@ type secondaryReconciler[T client.Object] struct {
114
137
onWrite OnWriteFn [T ] // function that is run after a write is made to this secondary object
115
138
}
116
139
140
+ // GetName returns the name of the secondary object.
117
141
func (s * secondaryReconciler [T ]) GetName () string {
118
142
return s .name
119
143
}
120
144
145
+ // GetNamespace returns the namespace of the secondary object.
121
146
func (s * secondaryReconciler [T ]) GetNamespace () string {
122
147
return s .namespace
123
148
}
124
149
150
+ // GetEmptyObject returns an empty object of the same GVK as the secondary
151
+ // object.
125
152
func (s * secondaryReconciler [T ]) GetEmptyObject () client.Object {
126
153
rType := reflect .TypeFor [T ]().Elem ()
127
154
return reflect .New (rType ).Interface ().(T )
128
155
}
129
156
157
+ // GetKind returns the kind of the secondary object.
130
158
func (s * secondaryReconciler [T ]) GetKind () string {
131
159
gvk , _ := apiutil .GVKForObject (s .GetEmptyObject (), s .Scheme ())
132
160
return gvk .Kind
133
161
}
134
162
163
+ // GetPrimary returns the primary object that triggers this secondary object's
164
+ // reconciliation.
135
165
func (s * secondaryReconciler [T ]) GetPrimary () client.Object {
136
166
return s .primary
137
167
}
138
168
169
+ // GetClient returns the client used for reconciling the secondary object.
139
170
func (s * secondaryReconciler [T ]) GetClient () client.Client {
140
171
return s .Client
141
172
}
142
173
174
+ // Generate creates a new instance of the secondary object with values derived
175
+ // from the secondaryReconciler's settings.
143
176
func (s * secondaryReconciler [T ]) Generate (ctx context.Context , obj client.Object ) (err error ) {
144
177
objT , ok := obj .(T )
145
178
if ! ok {
@@ -151,6 +184,10 @@ func (s *secondaryReconciler[T]) Generate(ctx context.Context, obj client.Object
151
184
return s .generate (s , ctx , objT )
152
185
}
153
186
187
+ // Modify compares observed and generated, and, if there are relevant
188
+ // qualities that differ between them, observed is updated to match generated in
189
+ // those qualities. Returns a boolean for whether observed was updated and an
190
+ // error if an error was encountered while attempting this operation.
154
191
func (s * secondaryReconciler [T ]) Modify (ctx context.Context , observed , generated client.Object ) (modified bool , err error ) {
155
192
if s .modify == nil {
156
193
return
@@ -171,13 +208,17 @@ func (s *secondaryReconciler[T]) Modify(ctx context.Context, observed, generated
171
208
return s .modify (s , ctx , observedT , generatedT )
172
209
}
173
210
211
+ // OnWrite is a function that is executed when any write is made to the cluster,
212
+ // e.g. an object is created or updated.
174
213
func (s * secondaryReconciler [T ]) OnWrite (ctx context.Context ) (err error ) {
175
214
if s .onWrite == nil {
176
215
return
177
216
}
178
217
return s .onWrite (s , ctx )
179
218
}
180
219
220
+ // Reconcile performs reconciliation related to the creation or modification of
221
+ // the secondary object that the secondaryReconciler is targeted for.
181
222
func (s * secondaryReconciler [T ]) Reconcile (ctx context.Context ) (result * ctrl.Result , err error ) {
182
223
reqLogger := logf .FromContext (ctx , "Object.Namespace" , s .GetNamespace (), "Object.Kind" , s .GetKind (), "Object.Name" , s .GetName ())
183
224
debugLogger := logf .FromContext (ctx , "Object.Namespace" , s .GetNamespace (), "Object.Kind" , s .GetKind (), "Object.Name" , s .GetName ()).V (1 )
@@ -214,15 +255,8 @@ func (s *secondaryReconciler[T]) Reconcile(ctx context.Context) (result *ctrl.Re
214
255
return subreconciler .ContinueReconciling ()
215
256
}
216
257
217
- u := & unstructured.Unstructured {}
218
- u .Object , err = runtime .DefaultUnstructuredConverter .ToUnstructured (observed )
219
- if err != nil {
220
- reqLogger .Info ("Failed to convert Object to unstructured" , "reason" , err .Error ())
221
- return subreconciler .RequeueWithError (err )
222
- }
223
-
224
258
reqLogger .Info ("Updates found; updating the Object" )
225
- if err = s .Update (ctx , u ); err != nil {
259
+ if err = s .Update (ctx , observed ); err != nil {
226
260
reqLogger .Info ("Failed to update Object" , "msg" , err .Error ())
227
261
return subreconciler .RequeueWithDelay (DefaultLowerWait )
228
262
}
@@ -239,12 +273,16 @@ type SecondaryReconcilerBuilder[T client.Object] struct {
239
273
s * secondaryReconciler [T ]
240
274
}
241
275
276
+ // NewSecondaryReconcilerBuilder creates a new builder for a SecondaryReconciler.
242
277
func NewSecondaryReconcilerBuilder [T client.Object ]() * SecondaryReconcilerBuilder [T ] {
243
278
return & SecondaryReconcilerBuilder [T ]{
244
279
s : & secondaryReconciler [T ]{},
245
280
}
246
281
}
247
282
283
+ // Build creates a new SecondaryReconciler using the configurations supplied by
284
+ // other builder functions. Returns an error if no client or GVK is configured
285
+ // on the SecondaryReconciler.
248
286
func (b * SecondaryReconcilerBuilder [T ]) Build () (* secondaryReconciler [T ], error ) {
249
287
if b .s .Client == nil {
250
288
return nil , fmt .Errorf ("failed to build secondary reconciler: no client defined" )
@@ -257,6 +295,9 @@ func (b *SecondaryReconcilerBuilder[T]) Build() (*secondaryReconciler[T], error)
257
295
return b .s , nil
258
296
}
259
297
298
+ // MustBuild creates a new SecondaryReconciler using the configurations supplied
299
+ // by other builder functions. Panics if a client or GVK is not configured on
300
+ // the SecondaryReconciler.
260
301
func (b * SecondaryReconcilerBuilder [T ]) MustBuild () * secondaryReconciler [T ] {
261
302
if b .s .Client == nil {
262
303
panic ("failed to build secondary reconciler: no client defined" )
@@ -269,21 +310,29 @@ func (b *SecondaryReconcilerBuilder[T]) MustBuild() *secondaryReconciler[T] {
269
310
return b .s
270
311
}
271
312
313
+ // WithName sets the name of the secondary object that the
314
+ // SecondaryReconciler is targeting.
272
315
func (b * SecondaryReconcilerBuilder [T ]) WithName (name string ) * SecondaryReconcilerBuilder [T ] {
273
316
b .s .name = name
274
317
return b
275
318
}
276
319
320
+ // WithName sets the namespace of the secondary object that the
321
+ // SecondaryReconciler is targeting.
277
322
func (b * SecondaryReconcilerBuilder [T ]) WithNamespace (namespace string ) * SecondaryReconcilerBuilder [T ] {
278
323
b .s .namespace = namespace
279
324
return b
280
325
}
281
326
327
+ // WithPrimary sets the primary object for the secondary object that the
328
+ // SecondaryReconciler is targeting.
282
329
func (b * SecondaryReconcilerBuilder [T ]) WithPrimary (primary client.Object ) * SecondaryReconcilerBuilder [T ] {
283
330
b .s .primary = primary
284
331
return b
285
332
}
286
333
334
+ // WithClient sets the client to be used for interacting with the cluster while
335
+ // reconciling the secondary object.
287
336
func (b * SecondaryReconcilerBuilder [T ]) WithClient (cl client.Client ) * SecondaryReconcilerBuilder [T ] {
288
337
b .s .Client = cl
289
338
return b
@@ -343,10 +392,12 @@ type SecondaryReconcilerFn subreconciler.Fn
343
392
344
393
var _ Subreconciler = SecondaryReconcilerFn (func (ctx context.Context ) (result * ctrl.Result , err error ) { return })
345
394
395
+ // Reconcile implements Subreconciler.
346
396
func (f SecondaryReconcilerFn ) Reconcile (ctx context.Context ) (result * ctrl.Result , err error ) {
347
397
return f (ctx )
348
398
}
349
399
400
+ // NewSecondaryReconcilerFn creates a new SecondaryReconcilerFn from a subreconciler.FnWithRequest.
350
401
func NewSecondaryReconcilerFn (req ctrl.Request , fn subreconciler.FnWithRequest ) SecondaryReconcilerFn {
351
402
return func (ctx context.Context ) (result * ctrl.Result , err error ) {
352
403
return fn (ctx , req )
0 commit comments