@@ -12,7 +12,6 @@ import (
1212 "k8s.io/apimachinery/pkg/types"
1313 "k8s.io/apimachinery/pkg/util/json"
1414 "sigs.k8s.io/controller-runtime/pkg/client"
15- "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1615 runtimeManager "sigs.k8s.io/controller-runtime/pkg/manager"
1716 runtimePredicate "sigs.k8s.io/controller-runtime/pkg/predicate"
1817 runtimeSource "sigs.k8s.io/controller-runtime/pkg/source"
@@ -232,7 +231,7 @@ func (t *target) update(ctx context.Context, delta cache.Delta) error {
232231
233232 //nolint:nolintlint
234233 switch delta .Type { //nolint:exhaustive
235- case cache .Added , cache .Upserted :
234+ case cache .Added , cache .Upserted , cache . Updated , cache . Replaced :
236235 t .log .V (2 ).Info ("add/upsert" , "event-type" , delta .Type , "object" , client .ObjectKeyFromObject (delta .Object ))
237236
238237 gvk , err := t .Resource .GetGVK ()
@@ -244,24 +243,53 @@ func (t *target) update(ctx context.Context, delta cache.Delta) error {
244243 obj .SetName (delta .Object .GetName ())
245244 obj .SetNamespace (delta .Object .GetNamespace ())
246245
247- if res , err := controllerutil .CreateOrUpdate (context .TODO (), c , obj , func () error {
248- obj .SetUnstructuredContent (delta .Object .UnstructuredContent ())
246+ // WARNING: the Update target cannot be used to delete labels and annotations, use
247+ // the Patcher target for that (this is because we don't want the user to remove
248+ // important labels/annotations accidentally and taking care of each in the
249+ // pipeline may be too difficult)
250+ //
251+ // Use our own CreateOrUpdate that will also update the status
252+ res , err := CreateOrUpdate (context .TODO (), c , obj , func () error {
253+ // remove stuff that's no longer there
254+ for k := range obj .UnstructuredContent () {
255+ if k == "metadata" {
256+ continue
257+ }
258+ if _ , ok , _ := unstructured .NestedFieldNoCopy (delta .Object .UnstructuredContent (), k ); ! ok {
259+ unstructured .RemoveNestedField (obj .UnstructuredContent (), k )
260+ }
261+ }
262+
263+ // then update the content with new keys: metadata and status will be handled separately
264+ for k , v := range delta .Object .UnstructuredContent () {
265+ if k == "metadata" {
266+ continue
267+ }
268+
269+ if err := unstructured .SetNestedField (obj .UnstructuredContent (), v , k ); err != nil {
270+ t .log .Error (err , "failed to update object field during update" ,
271+ "object" , client .ObjectKeyFromObject (obj ).String (), "key" , k )
272+ continue
273+ }
274+ }
275+
276+ mergeMetadata (obj , delta .Object )
277+
278+ // restore metadata
249279 obj .SetGroupVersionKind (gvk )
250280 obj .SetName (delta .Object .GetName ())
251281 obj .SetNamespace (delta .Object .GetNamespace ())
282+
252283 return nil
253- }); err != nil {
254- return fmt .Errorf ("create/update resource %s/%s failed with operation code %s: %w" ,
255- delta .Object .GetNamespace (), delta .Object .GetName (), res , err )
284+ })
285+
286+ if err != nil {
287+ return fmt .Errorf ("create/update resource %s failed with operation code %s: %w" ,
288+ client .ObjectKeyFromObject (delta .Object ).String (), res , err )
256289 }
257290
258291 return nil
259292
260- case cache .Updated , cache .Replaced :
261- t .log .V (2 ).Info ("update" , "event-type" , delta .Type , "object" , client .ObjectKeyFromObject (delta .Object ))
262-
263- return c .Update (ctx , delta .Object )
264-
265293 case cache .Deleted :
266294 t .log .V (2 ).Info ("delete" , "event-type" , delta .Type , "object" , client .ObjectKeyFromObject (delta .Object ))
267295
@@ -353,3 +381,29 @@ func removeNested(m map[string]any) map[string]any {
353381 }
354382 return result
355383}
384+
385+ func mergeMetadata (obj , new object.Object ) {
386+ labels := obj .GetLabels ()
387+ newLabels := new .GetLabels ()
388+ if newLabels != nil {
389+ if labels == nil {
390+ labels = map [string ]string {}
391+ }
392+ for k , v := range newLabels {
393+ labels [k ] = v
394+ }
395+ obj .SetLabels (labels )
396+ }
397+
398+ annotations := obj .GetAnnotations ()
399+ newAnnotations := new .GetAnnotations ()
400+ if newAnnotations != nil {
401+ if annotations == nil {
402+ annotations = map [string ]string {}
403+ }
404+ for k , v := range newAnnotations {
405+ annotations [k ] = v
406+ }
407+ obj .SetAnnotations (annotations )
408+ }
409+ }
0 commit comments