Skip to content

Commit 7398417

Browse files
authored
fix(GrafanaNotificationPolicy): use patch instead of update when applying the notification policy annotation to avoid Grafana CR drift (#1898)
* fix: Use patch not update to add/remove applied NotificationPolicy annotation * chore: Make comments consistent and clearer
1 parent 541b8bb commit 7398417

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

controllers/controller_shared.go

+36
Original file line numberDiff line numberDiff line change
@@ -344,3 +344,39 @@ func patchFinalizers(ctx context.Context, cl client.Client, cr client.Object) er
344344
}
345345
return cl.Patch(ctx, cr, client.RawPatch(types.MergePatchType, patch))
346346
}
347+
348+
func addAnnotation(ctx context.Context, cl client.Client, cr client.Object, key string, value string) error {
349+
crAnnotations := cr.GetAnnotations()
350+
351+
if crAnnotations[key] == value {
352+
return nil
353+
}
354+
355+
// Add key to map and create patch
356+
crAnnotations[key] = value
357+
patch, err := json.Marshal(map[string]interface{}{"metadata": map[string]interface{}{"annotations": crAnnotations}})
358+
if err != nil {
359+
return err
360+
}
361+
362+
return cl.Patch(ctx, cr, client.RawPatch(types.MergePatchType, patch))
363+
}
364+
365+
func removeAnnotation(ctx context.Context, cl client.Client, cr client.Object, key string) error {
366+
crAnnotations := cr.GetAnnotations()
367+
if crAnnotations[key] == "" {
368+
return nil
369+
}
370+
371+
// Escape slash '/' according to RFC6901
372+
// We could also escape tilde '~', but that is not a valid character in annotation keys.
373+
key = strings.ReplaceAll(key, "/", "~1")
374+
patch, err := json.Marshal([]interface{}{map[string]interface{}{"op": "remove", "path": "/metadata/annotations/" + key}})
375+
if err != nil {
376+
return err
377+
}
378+
379+
// MergePatchType only removes map keys when the value is null. JSONPatchType allows removing anything under a path.
380+
// Differs from removeFinalizer where we overwrite an array.
381+
return cl.Patch(ctx, cr, client.RawPatch(types.JSONPatchType, patch))
382+
}

controllers/notificationpolicy_controller.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,10 @@ func (r *GrafanaNotificationPolicyReconciler) reconcileWithInstance(ctx context.
285285
if instance.Annotations == nil {
286286
instance.Annotations = make(map[string]string)
287287
}
288-
instance.Annotations[annotationAppliedNotificationPolicy] = notificationPolicy.NamespacedResource()
289-
if err := r.Client.Update(ctx, instance); err != nil {
290-
return fmt.Errorf("saving applied policy to instance CR: %w", err)
288+
289+
err = addAnnotation(ctx, r.Client, instance, annotationAppliedNotificationPolicy, notificationPolicy.NamespacedResource())
290+
if err != nil {
291+
return fmt.Errorf("saving applied notification policy to Grafana CR: %w", err)
291292
}
292293
return nil
293294
}
@@ -313,9 +314,9 @@ func (r *GrafanaNotificationPolicyReconciler) finalize(ctx context.Context, noti
313314
return fmt.Errorf("resetting policy tree")
314315
}
315316

316-
delete(grafana.Annotations, annotationAppliedNotificationPolicy)
317-
if err := r.Client.Update(ctx, &grafana); err != nil {
318-
return fmt.Errorf("removing applied notification policy from Grafana cr: %w", err)
317+
err = removeAnnotation(ctx, r.Client, &grafana, annotationAppliedNotificationPolicy)
318+
if err != nil {
319+
return fmt.Errorf("removing applied notification policy from Grafana CR: %w", err)
319320
}
320321
}
321322

0 commit comments

Comments
 (0)