1
16
17 package controllerutil
18
19 import (
20 "context"
21 "fmt"
22 "reflect"
23
24 "k8s.io/apimachinery/pkg/api/equality"
25 apierrors "k8s.io/apimachinery/pkg/api/errors"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/runtime/schema"
30 "k8s.io/utils/ptr"
31
32 "sigs.k8s.io/controller-runtime/pkg/client"
33 "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
34 )
35
36
37
38
39 type AlreadyOwnedError struct {
40 Object metav1.Object
41 Owner metav1.OwnerReference
42 }
43
44 func (e *AlreadyOwnedError) Error() string {
45 return fmt.Sprintf("Object %s/%s is already owned by another %s controller %s", e.Object.GetNamespace(), e.Object.GetName(), e.Owner.Kind, e.Owner.Name)
46 }
47
48 func newAlreadyOwnedError(obj metav1.Object, owner metav1.OwnerReference) *AlreadyOwnedError {
49 return &AlreadyOwnedError{
50 Object: obj,
51 Owner: owner,
52 }
53 }
54
55
56
57
58
59
60 func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Scheme) error {
61
62 ro, ok := owner.(runtime.Object)
63 if !ok {
64 return fmt.Errorf("%T is not a runtime.Object, cannot call SetControllerReference", owner)
65 }
66 if err := validateOwner(owner, controlled); err != nil {
67 return err
68 }
69
70
71 gvk, err := apiutil.GVKForObject(ro, scheme)
72 if err != nil {
73 return err
74 }
75 ref := metav1.OwnerReference{
76 APIVersion: gvk.GroupVersion().String(),
77 Kind: gvk.Kind,
78 Name: owner.GetName(),
79 UID: owner.GetUID(),
80 BlockOwnerDeletion: ptr.To(true),
81 Controller: ptr.To(true),
82 }
83
84
85 if existing := metav1.GetControllerOf(controlled); existing != nil && !referSameObject(*existing, ref) {
86 return newAlreadyOwnedError(controlled, *existing)
87 }
88
89
90 upsertOwnerRef(ref, controlled)
91 return nil
92 }
93
94
95
96
97 func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) error {
98
99 ro, ok := owner.(runtime.Object)
100 if !ok {
101 return fmt.Errorf("%T is not a runtime.Object, cannot call SetOwnerReference", owner)
102 }
103 if err := validateOwner(owner, object); err != nil {
104 return err
105 }
106
107
108 gvk, err := apiutil.GVKForObject(ro, scheme)
109 if err != nil {
110 return err
111 }
112 ref := metav1.OwnerReference{
113 APIVersion: gvk.GroupVersion().String(),
114 Kind: gvk.Kind,
115 UID: owner.GetUID(),
116 Name: owner.GetName(),
117 }
118
119
120 upsertOwnerRef(ref, object)
121 return nil
122 }
123
124
125
126 func RemoveOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) error {
127 owners := object.GetOwnerReferences()
128 length := len(owners)
129 if length < 1 {
130 return fmt.Errorf("%T does not have any owner references", object)
131 }
132 ro, ok := owner.(runtime.Object)
133 if !ok {
134 return fmt.Errorf("%T is not a runtime.Object, cannot call RemoveOwnerReference", owner)
135 }
136 gvk, err := apiutil.GVKForObject(ro, scheme)
137 if err != nil {
138 return err
139 }
140
141 index := indexOwnerRef(owners, metav1.OwnerReference{
142 APIVersion: gvk.GroupVersion().String(),
143 Name: owner.GetName(),
144 Kind: gvk.Kind,
145 })
146 if index == -1 {
147 return fmt.Errorf("%T does not have an owner reference for %T", object, owner)
148 }
149
150 owners = append(owners[:index], owners[index+1:]...)
151 object.SetOwnerReferences(owners)
152 return nil
153 }
154
155
156
157 func HasControllerReference(object metav1.Object) bool {
158 owners := object.GetOwnerReferences()
159 for _, owner := range owners {
160 isTrue := owner.Controller
161 if owner.Controller != nil && *isTrue {
162 return true
163 }
164 }
165 return false
166 }
167
168
169
170 func RemoveControllerReference(owner, object metav1.Object, scheme *runtime.Scheme) error {
171 if ok := HasControllerReference(object); !ok {
172 return fmt.Errorf("%T does not have a owner reference with controller equals true", object)
173 }
174 ro, ok := owner.(runtime.Object)
175 if !ok {
176 return fmt.Errorf("%T is not a runtime.Object, cannot call RemoveControllerReference", owner)
177 }
178 gvk, err := apiutil.GVKForObject(ro, scheme)
179 if err != nil {
180 return err
181 }
182 ownerRefs := object.GetOwnerReferences()
183 index := indexOwnerRef(ownerRefs, metav1.OwnerReference{
184 APIVersion: gvk.GroupVersion().String(),
185 Name: owner.GetName(),
186 Kind: gvk.Kind,
187 })
188
189 if index == -1 {
190 return fmt.Errorf("%T does not have an controller reference for %T", object, owner)
191 }
192
193 if ownerRefs[index].Controller == nil || !*ownerRefs[index].Controller {
194 return fmt.Errorf("%T owner is not the controller reference for %T", owner, object)
195 }
196
197 ownerRefs = append(ownerRefs[:index], ownerRefs[index+1:]...)
198 object.SetOwnerReferences(ownerRefs)
199 return nil
200 }
201
202 func upsertOwnerRef(ref metav1.OwnerReference, object metav1.Object) {
203 owners := object.GetOwnerReferences()
204 if idx := indexOwnerRef(owners, ref); idx == -1 {
205 owners = append(owners, ref)
206 } else {
207 owners[idx] = ref
208 }
209 object.SetOwnerReferences(owners)
210 }
211
212
213 func indexOwnerRef(ownerReferences []metav1.OwnerReference, ref metav1.OwnerReference) int {
214 for index, r := range ownerReferences {
215 if referSameObject(r, ref) {
216 return index
217 }
218 }
219 return -1
220 }
221
222 func validateOwner(owner, object metav1.Object) error {
223 ownerNs := owner.GetNamespace()
224 if ownerNs != "" {
225 objNs := object.GetNamespace()
226 if objNs == "" {
227 return fmt.Errorf("cluster-scoped resource must not have a namespace-scoped owner, owner's namespace %s", ownerNs)
228 }
229 if ownerNs != objNs {
230 return fmt.Errorf("cross-namespace owner references are disallowed, owner's namespace %s, obj's namespace %s", owner.GetNamespace(), object.GetNamespace())
231 }
232 }
233 return nil
234 }
235
236
237 func referSameObject(a, b metav1.OwnerReference) bool {
238 aGV, err := schema.ParseGroupVersion(a.APIVersion)
239 if err != nil {
240 return false
241 }
242
243 bGV, err := schema.ParseGroupVersion(b.APIVersion)
244 if err != nil {
245 return false
246 }
247 return aGV.Group == bGV.Group && a.Kind == b.Kind && a.Name == b.Name
248 }
249
250
251 type OperationResult string
252
253 const (
254
255 OperationResultNone OperationResult = "unchanged"
256
257 OperationResultCreated OperationResult = "created"
258
259 OperationResultUpdated OperationResult = "updated"
260
261 OperationResultUpdatedStatus OperationResult = "updatedStatus"
262
263 OperationResultUpdatedStatusOnly OperationResult = "updatedStatusOnly"
264 )
265
266
267
268
269
270
271
272
273
274
275
276 func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f MutateFn) (OperationResult, error) {
277 key := client.ObjectKeyFromObject(obj)
278 if err := c.Get(ctx, key, obj); err != nil {
279 if !apierrors.IsNotFound(err) {
280 return OperationResultNone, err
281 }
282 if err := mutate(f, key, obj); err != nil {
283 return OperationResultNone, err
284 }
285 if err := c.Create(ctx, obj); err != nil {
286 return OperationResultNone, err
287 }
288 return OperationResultCreated, nil
289 }
290
291 existing := obj.DeepCopyObject()
292 if err := mutate(f, key, obj); err != nil {
293 return OperationResultNone, err
294 }
295
296 if equality.Semantic.DeepEqual(existing, obj) {
297 return OperationResultNone, nil
298 }
299
300 if err := c.Update(ctx, obj); err != nil {
301 return OperationResultNone, err
302 }
303 return OperationResultUpdated, nil
304 }
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319 func CreateOrPatch(ctx context.Context, c client.Client, obj client.Object, f MutateFn) (OperationResult, error) {
320 key := client.ObjectKeyFromObject(obj)
321 if err := c.Get(ctx, key, obj); err != nil {
322 if !apierrors.IsNotFound(err) {
323 return OperationResultNone, err
324 }
325 if f != nil {
326 if err := mutate(f, key, obj); err != nil {
327 return OperationResultNone, err
328 }
329 }
330 if err := c.Create(ctx, obj); err != nil {
331 return OperationResultNone, err
332 }
333 return OperationResultCreated, nil
334 }
335
336
337 objPatch := client.MergeFrom(obj.DeepCopyObject().(client.Object))
338 statusPatch := client.MergeFrom(obj.DeepCopyObject().(client.Object))
339
340
341
342 before, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj.DeepCopyObject())
343 if err != nil {
344 return OperationResultNone, err
345 }
346
347
348 beforeStatus, hasBeforeStatus, err := unstructured.NestedFieldCopy(before, "status")
349 if err != nil {
350 return OperationResultNone, err
351 }
352
353
354
355 if hasBeforeStatus {
356 unstructured.RemoveNestedField(before, "status")
357 }
358
359
360 if f != nil {
361 if err := mutate(f, key, obj); err != nil {
362 return OperationResultNone, err
363 }
364 }
365
366
367 after, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
368 if err != nil {
369 return OperationResultNone, err
370 }
371
372
373 afterStatus, hasAfterStatus, err := unstructured.NestedFieldCopy(after, "status")
374 if err != nil {
375 return OperationResultNone, err
376 }
377
378
379
380 if hasAfterStatus {
381 unstructured.RemoveNestedField(after, "status")
382 }
383
384 result := OperationResultNone
385
386 if !reflect.DeepEqual(before, after) {
387
388 if err := c.Patch(ctx, obj, objPatch); err != nil {
389 return result, err
390 }
391 result = OperationResultUpdated
392 }
393
394 if (hasBeforeStatus || hasAfterStatus) && !reflect.DeepEqual(beforeStatus, afterStatus) {
395
396
397 if result == OperationResultUpdated {
398
399 objectAfterPatch, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
400 if err != nil {
401 return result, err
402 }
403 if err = unstructured.SetNestedField(objectAfterPatch, afterStatus, "status"); err != nil {
404 return result, err
405 }
406
407 if err = runtime.DefaultUnstructuredConverter.FromUnstructured(objectAfterPatch, obj); err != nil {
408 return result, err
409 }
410 }
411 if err := c.Status().Patch(ctx, obj, statusPatch); err != nil {
412 return result, err
413 }
414 if result == OperationResultUpdated {
415 result = OperationResultUpdatedStatus
416 } else {
417 result = OperationResultUpdatedStatusOnly
418 }
419 }
420
421 return result, nil
422 }
423
424
425 func mutate(f MutateFn, key client.ObjectKey, obj client.Object) error {
426 if err := f(); err != nil {
427 return err
428 }
429 if newKey := client.ObjectKeyFromObject(obj); key != newKey {
430 return fmt.Errorf("MutateFn cannot mutate object name and/or object namespace")
431 }
432 return nil
433 }
434
435
436 type MutateFn func() error
437
438
439
440 func AddFinalizer(o client.Object, finalizer string) (finalizersUpdated bool) {
441 f := o.GetFinalizers()
442 for _, e := range f {
443 if e == finalizer {
444 return false
445 }
446 }
447 o.SetFinalizers(append(f, finalizer))
448 return true
449 }
450
451
452
453 func RemoveFinalizer(o client.Object, finalizer string) (finalizersUpdated bool) {
454 f := o.GetFinalizers()
455 length := len(f)
456
457 index := 0
458 for i := 0; i < length; i++ {
459 if f[i] == finalizer {
460 continue
461 }
462 f[index] = f[i]
463 index++
464 }
465 o.SetFinalizers(f[:index])
466 return length != index
467 }
468
469
470 func ContainsFinalizer(o client.Object, finalizer string) bool {
471 f := o.GetFinalizers()
472 for _, e := range f {
473 if e == finalizer {
474 return true
475 }
476 }
477 return false
478 }
479
View as plain text