@@ -29,24 +29,26 @@ import (
2929
3030 runtimev1 "sigs.k8s.io/cluster-api/api/runtime/v1beta2"
3131 runtimecatalog "sigs.k8s.io/cluster-api/exp/runtime/catalog"
32- "sigs.k8s.io/cluster-api/util/patch"
3332)
3433
3534// MarkAsPending adds to the object's PendingHooksAnnotation the intent to execute a hook after an operation completes.
3635// Usually this function is called when an operation is starting in order to track the intent to call an After<operation> hook later in the process.
37- func MarkAsPending (ctx context.Context , c client.Client , obj client.Object , hooks ... runtimecatalog.Hook ) error {
36+ func MarkAsPending (ctx context.Context , c client.Client , obj client.Object , updateResourceVersionOnObject bool , hooks ... runtimecatalog.Hook ) error {
3837 hookNames := []string {}
3938 for _ , hook := range hooks {
4039 hookNames = append (hookNames , runtimecatalog .HookName (hook ))
4140 }
4241
43- patchHelper , err := patch .NewHelper (obj , c )
44- if err != nil {
45- return errors .Wrapf (err , "failed to mark %q hook(s) as pending" , strings .Join (hookNames , "," ))
42+ orig := obj .DeepCopyObject ().(client.Object )
43+
44+ if changed := MarkObjectAsPending (obj , hooks ... ); ! changed {
45+ return nil
4646 }
4747
48- MarkObjectAsPending (obj , hooks ... )
49- if err := patchHelper .Patch (ctx , obj ); err != nil {
48+ if ! updateResourceVersionOnObject {
49+ obj = obj .DeepCopyObject ().(client.Object )
50+ }
51+ if err := c .Patch (ctx , obj , client .MergeFrom (orig )); err != nil {
5052 return errors .Wrapf (err , "failed to mark %q hook(s) as pending" , strings .Join (hookNames , "," ))
5153 }
5254
@@ -55,7 +57,7 @@ func MarkAsPending(ctx context.Context, c client.Client, obj client.Object, hook
5557
5658// MarkObjectAsPending adds to the object's PendingHooksAnnotation the intent to execute a hook after an operation completes.
5759// Usually this function is called when an operation is starting in order to track the intent to call an After<operation> hook later in the process.
58- func MarkObjectAsPending (obj client.Object , hooks ... runtimecatalog.Hook ) {
60+ func MarkObjectAsPending (obj client.Object , hooks ... runtimecatalog.Hook ) ( changed bool ) {
5961 hookNames := []string {}
6062 for _ , hook := range hooks {
6163 hookNames = append (hookNames , runtimecatalog .HookName (hook ))
@@ -66,8 +68,16 @@ func MarkObjectAsPending(obj client.Object, hooks ...runtimecatalog.Hook) {
6668 if annotations == nil {
6769 annotations = map [string ]string {}
6870 }
69- annotations [runtimev1 .PendingHooksAnnotation ] = addToCommaSeparatedList (annotations [runtimev1 .PendingHooksAnnotation ], hookNames ... )
71+
72+ newAnnotationValue := addToCommaSeparatedList (annotations [runtimev1 .PendingHooksAnnotation ], hookNames ... )
73+
74+ if annotations [runtimev1 .PendingHooksAnnotation ] == newAnnotationValue {
75+ return false
76+ }
77+
78+ annotations [runtimev1 .PendingHooksAnnotation ] = newAnnotationValue
7079 obj .SetAnnotations (annotations )
80+ return true
7181}
7282
7383// IsPending returns true if there is an intent to call a hook being tracked in the object's PendingHooksAnnotation.
@@ -83,30 +93,31 @@ func IsPending(hook runtimecatalog.Hook, obj client.Object) bool {
8393// MarkAsDone removes the intent to call a Hook from the object's PendingHooksAnnotation.
8494// Usually this func is called after all the registered extensions for the Hook returned an answer without requests
8595// to hold on to the object's lifecycle (retryAfterSeconds).
86- func MarkAsDone (ctx context.Context , c client.Client , obj client.Object , hooks ... runtimecatalog.Hook ) error {
87- hookNames := []string {}
88- for _ , hook := range hooks {
89- hookNames = append (hookNames , runtimecatalog .HookName (hook ))
96+ func MarkAsDone (ctx context.Context , c client.Client , obj client.Object , updateResourceVersionOnObject bool , hook runtimecatalog.Hook ) error {
97+ if ! IsPending (hook , obj ) {
98+ return nil
9099 }
91100
92- patchHelper , err := patch .NewHelper (obj , c )
93- if err != nil {
94- return errors .Wrapf (err , "failed to mark %q hook(s) as done" , strings .Join (hookNames , "," ))
95- }
101+ hookName := runtimecatalog .HookName (hook )
102+
103+ orig := obj .DeepCopyObject ().(client.Object )
96104
97105 // Read the annotation of the objects and add the hook to the comma separated list
98106 annotations := obj .GetAnnotations ()
99107 if annotations == nil {
100108 annotations = map [string ]string {}
101109 }
102- annotations [runtimev1 .PendingHooksAnnotation ] = removeFromCommaSeparatedList (annotations [runtimev1 .PendingHooksAnnotation ], hookNames ... )
110+ annotations [runtimev1 .PendingHooksAnnotation ] = removeFromCommaSeparatedList (annotations [runtimev1 .PendingHooksAnnotation ], hookName )
103111 if annotations [runtimev1 .PendingHooksAnnotation ] == "" {
104112 delete (annotations , runtimev1 .PendingHooksAnnotation )
105113 }
106114 obj .SetAnnotations (annotations )
107115
108- if err := patchHelper .Patch (ctx , obj ); err != nil {
109- return errors .Wrapf (err , "failed to mark %q hook(s) as done" , strings .Join (hookNames , "," ))
116+ if ! updateResourceVersionOnObject {
117+ obj = obj .DeepCopyObject ().(client.Object )
118+ }
119+ if err := c .Patch (ctx , obj , client .MergeFrom (orig )); err != nil {
120+ return errors .Wrapf (err , "failed to mark %q hook as done" , hookName )
110121 }
111122
112123 return nil
@@ -125,16 +136,17 @@ func IsOkToDelete(obj client.Object) bool {
125136}
126137
127138// MarkAsOkToDelete adds the OkToDeleteAnnotation annotation to the object and patches it.
128- func MarkAsOkToDelete (ctx context.Context , c client.Client , obj client.Object ) error {
139+ func MarkAsOkToDelete (ctx context.Context , c client.Client , obj client.Object , updateResourceVersionOnObject bool ) error {
140+ if _ , ok := obj .GetAnnotations ()[runtimev1 .OkToDeleteAnnotation ]; ok {
141+ return nil
142+ }
143+
129144 gvk , err := apiutil .GVKForObject (obj , c .Scheme ())
130145 if err != nil {
131146 return errors .Wrapf (err , "failed to mark %s as ok to delete: failed to get GVK for object" , klog .KObj (obj ))
132147 }
133148
134- patchHelper , err := patch .NewHelper (obj , c )
135- if err != nil {
136- return errors .Wrapf (err , "failed to mark %s %s as ok to delete" , gvk .Kind , klog .KObj (obj ))
137- }
149+ orig := obj .DeepCopyObject ().(client.Object )
138150
139151 annotations := obj .GetAnnotations ()
140152 if annotations == nil {
@@ -143,7 +155,10 @@ func MarkAsOkToDelete(ctx context.Context, c client.Client, obj client.Object) e
143155 annotations [runtimev1 .OkToDeleteAnnotation ] = ""
144156 obj .SetAnnotations (annotations )
145157
146- if err := patchHelper .Patch (ctx , obj ); err != nil {
158+ if ! updateResourceVersionOnObject {
159+ obj = obj .DeepCopyObject ().(client.Object )
160+ }
161+ if err := c .Patch (ctx , obj , client .MergeFrom (orig )); err != nil {
147162 return errors .Wrapf (err , "failed to mark %s %s as ok to delete" , gvk .Kind , klog .KObj (obj ))
148163 }
149164
0 commit comments