@@ -21,100 +21,58 @@ import (
2121 "fmt"
2222 "slices"
2323 "sort"
24+ "strings"
2425
2526 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
26- "k8s.io/apimachinery/pkg/util/sets"
2727 "sigs.k8s.io/controller-runtime/pkg/client"
2828 "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
29- "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3029)
3130
32- // AddFinalizers adds one or more finalizers to the object using server-side apply.
33- // If all finalizers already exist, this is a no-op and returns (false, nil).
34- // Returns (true, nil) if any finalizers were added.
31+ const (
32+ FinalizerPrefix = "olm.operatorframework.io/"
33+ )
34+
35+ // UpdateFinalizers sets the finalizers on an object to exactly the provided list using server-side apply.
36+ // If no finalizers are supplied, all finalizers will be removed from the object.
37+ // If one finalizer is supplied, all other finalizers will be removed and only the supplied one will remain.
38+ // Returns (true, nil) if the finalizers were changed, (false, nil) if they were already set to the desired value.
3539// Note: This function will update the passed object with the server response.
36- func AddFinalizers (ctx context.Context , owner string , c client.Client , obj client.Object , finalizers ... string ) (bool , error ) {
37- if len (finalizers ) == 0 {
38- return false , nil
40+ func UpdateFinalizers (ctx context.Context , owner string , c client.Client , obj client.Object , finalizers ... string ) (bool , error ) {
41+ // Sort the desired finalizers for consistent ordering
42+ newFinalizers := slices .Clone (finalizers )
43+ if newFinalizers == nil {
44+ newFinalizers = []string {}
3945 }
40-
41- // Determine which finalizers need to be added
42- var toAdd []string
43- for _ , finalizer := range finalizers {
44- if ! controllerutil .ContainsFinalizer (obj , finalizer ) {
45- toAdd = append (toAdd , finalizer )
46+ // Possibly overkill, but it will ensure our finalizers use the proper prefix
47+ for _ , s := range newFinalizers {
48+ if ! strings .HasPrefix (s , FinalizerPrefix ) {
49+ panic (fmt .Sprintf ("finalizer does not have %q prefix: %q" , FinalizerPrefix , s ))
4650 }
4751 }
52+ sort .Strings (newFinalizers )
4853
49- if len (toAdd ) == 0 {
50- return false , nil
51- }
52-
53- // Sort the finalizers to add for consistent ordering
54- sort .Strings (toAdd )
55-
56- // Create a copy of the finalizers list to avoid mutating the object
54+ // Check if the current finalizers already match the desired state
55+ // Remove any non-"olm.operatorframework.io" finalizers (ones we don't manage) from the list
5756 currentFinalizers := obj .GetFinalizers ()
58- newFinalizers := make ([]string , len (currentFinalizers ), len (currentFinalizers )+ len (toAdd ))
59- copy (newFinalizers , currentFinalizers )
60- newFinalizers = append (newFinalizers , toAdd ... )
61-
62- // Get the GVK for this object type
63- gvk , err := apiutil .GVKForObject (obj , c .Scheme ())
64- if err != nil {
65- return false , fmt .Errorf ("getting object kind: %w" , err )
66- }
67-
68- // Create an unstructured object for server-side apply
69- u := & unstructured.Unstructured {}
70- u .SetGroupVersionKind (gvk )
71- u .SetName (obj .GetName ())
72- u .SetNamespace (obj .GetNamespace ())
73- u .SetFinalizers (newFinalizers )
74-
75- // Use server-side apply to update finalizers
76- if err := c .Patch (ctx , u , client .Apply , client .ForceOwnership , client .FieldOwner (owner )); err != nil {
77- return false , fmt .Errorf ("adding finalizer: %w" , err )
78- }
79-
80- // Update the passed object with the new finalizers
81- obj .SetFinalizers (u .GetFinalizers ())
82- obj .SetResourceVersion (u .GetResourceVersion ())
83-
84- return true , nil
85- }
86-
87- // RemoveFinalizers removes one or more finalizers from the object using server-side apply.
88- // If none of the finalizers exist, this is a no-op.
89- func RemoveFinalizers (ctx context.Context , owner string , c client.Client , obj client.Object , finalizers ... string ) error {
90- if len (finalizers ) == 0 {
91- return nil
92- }
93-
94- // Create a set of finalizers to remove for efficient lookup
95- toRemove := sets .New (finalizers ... )
96- hasAny := false
97- for _ , finalizer := range finalizers {
98- if controllerutil .ContainsFinalizer (obj , finalizer ) {
99- hasAny = true
100- }
57+ currentSorted := slices .Clone (currentFinalizers )
58+ currentSorted = slices .DeleteFunc (currentSorted , func (f string ) bool {
59+ return ! strings .HasPrefix (f , FinalizerPrefix )
60+ })
61+ if currentSorted == nil {
62+ currentSorted = []string {}
10163 }
64+ sort .Strings (currentSorted )
10265
103- if ! hasAny {
104- return nil
66+ // With only "olm.operatorframework.io" finalizers, other controller's finalizers
67+ // won't interfere in this check
68+ if slices .Equal (currentSorted , newFinalizers ) {
69+ return false , nil
10570 }
10671
107- // Create a copy of the finalizers list and remove the specified finalizers
108- currentFinalizers := obj .GetFinalizers ()
109- newFinalizers := slices .Clone (currentFinalizers )
110- newFinalizers = slices .DeleteFunc (newFinalizers , func (f string ) bool {
111- return toRemove .Has (f )
112- })
113-
11472 // Get the GVK for this object type
11573 gvk , err := apiutil .GVKForObject (obj , c .Scheme ())
11674 if err != nil {
117- return fmt .Errorf ("getting object kind: %w" , err )
75+ return false , fmt .Errorf ("getting object kind: %w" , err )
11876 }
11977
12078 // Create an unstructured object for server-side apply
@@ -126,12 +84,12 @@ func RemoveFinalizers(ctx context.Context, owner string, c client.Client, obj cl
12684
12785 // Use server-side apply to update finalizers
12886 if err := c .Patch (ctx , u , client .Apply , client .ForceOwnership , client .FieldOwner (owner )); err != nil {
129- return fmt .Errorf ("removing finalizer : %w" , err )
87+ return false , fmt .Errorf ("updating finalizers : %w" , err )
13088 }
13189
13290 // Update the passed object with the new finalizers
13391 obj .SetFinalizers (u .GetFinalizers ())
13492 obj .SetResourceVersion (u .GetResourceVersion ())
13593
136- return nil
94+ return true , nil
13795}
0 commit comments