@@ -24,6 +24,7 @@ import (
24
24
"net/http"
25
25
"net/url"
26
26
"regexp"
27
+ "slices"
27
28
"strings"
28
29
"time"
29
30
@@ -256,7 +257,7 @@ func (s *EventServer) getNotificationParams(ctx context.Context, event *eventv1.
256
257
}
257
258
258
259
notification := * event .DeepCopy ()
259
- s .enhanceEventWithAlertMetadata (ctx , & notification , alert )
260
+ s .combineEventMetadata (ctx , & notification , alert )
260
261
261
262
return sender , & notification , token , provider .GetTimeout (), nil
262
263
}
@@ -418,30 +419,90 @@ func (s *EventServer) eventMatchesAlertSource(ctx context.Context, event *eventv
418
419
return sel .Matches (labels .Set (obj .GetLabels ()))
419
420
}
420
421
421
- // enhanceEventWithAlertMetadata enhances the event with Alert metadata.
422
- func (s * EventServer ) enhanceEventWithAlertMetadata (ctx context.Context , event * eventv1.Event , alert * apiv1beta3.Alert ) {
423
- meta := event .Metadata
424
- if meta == nil {
425
- meta = make (map [string ]string )
422
+ // combineEventMetadata combines all the sources of metadata for the event
423
+ // according to the precedence order defined in RFC 0008. From lowest to
424
+ // highest precedence, the sources are:
425
+ //
426
+ // 1) Event metadata keys prefixed with the Event API Group stripped of the prefix.
427
+ //
428
+ // 2) Alert .spec.eventMetadata with the keys as they are.
429
+ //
430
+ // 3) Alert .spec.summary with the key "summary".
431
+ //
432
+ // 4) Event metadata keys prefixed with the involved object's API Group stripped of the prefix.
433
+ //
434
+ // At the end of the process key conflicts are detected and a single
435
+ // info-level log is emitted to warn users about all the conflicts,
436
+ // but only if at least one conflict is found.
437
+ func (s * EventServer ) combineEventMetadata (ctx context.Context , event * eventv1.Event , alert * apiv1beta3.Alert ) {
438
+ const (
439
+ sourceEventGroup = "involved object annotations"
440
+ sourceAlertEventMetadata = "Alert object .spec.eventMetadata"
441
+ sourceAlertSummary = "Alert object .spec.summary"
442
+ sourceObjectGroup = "involved object controller metadata"
443
+
444
+ summaryKey = "summary"
445
+ )
446
+
447
+ l := log .FromContext (ctx )
448
+ metadata := make (map [string ]string )
449
+ metadataSources := make (map [string ][]string )
450
+
451
+ // 1) Event metadata keys prefixed with the Event API Group stripped of the prefix.
452
+ eventGroupPrefix := "event.toolkit.fluxcd.io/" // TODO: use constant from github.com/fluxcd/pkg/apis/event when available
453
+ for k , v := range event .Metadata {
454
+ if strings .HasPrefix (k , eventGroupPrefix ) {
455
+ key := strings .TrimPrefix (k , eventGroupPrefix )
456
+ metadata [key ] = v
457
+ metadataSources [key ] = append (metadataSources [key ], sourceEventGroup )
458
+ }
426
459
}
427
460
428
- for key , value := range alert .Spec .EventMetadata {
429
- if _ , alreadyPresent := meta [key ]; ! alreadyPresent {
430
- meta [key ] = value
431
- } else {
432
- log .FromContext (ctx ).
433
- Info ("metadata key found in the existing set of metadata" , "key" , key )
434
- s .Eventf (alert , corev1 .EventTypeWarning , "MetadataAppendFailed" ,
435
- "metadata key found in the existing set of metadata for '%s' in %s" , key , involvedObjectString (event .InvolvedObject ))
436
- }
461
+ // 2) Alert .spec.eventMetadata with the keys as they are.
462
+ for k , v := range alert .Spec .EventMetadata {
463
+ metadata [k ] = v
464
+ metadataSources [k ] = append (metadataSources [k ], sourceAlertEventMetadata )
437
465
}
438
466
467
+ // 3) Alert .spec.summary with the key "summary".
439
468
if alert .Spec .Summary != "" {
440
- meta ["summary" ] = alert .Spec .Summary
469
+ metadata [summaryKey ] = alert .Spec .Summary
470
+ metadataSources [summaryKey ] = append (metadataSources [summaryKey ], sourceAlertSummary )
471
+ l .Info ("warning: specifying alert summary cert via '.spec.summary' is deprecated, please use '.spec.eventMetadata.summary' instead" )
472
+ }
473
+
474
+ // 4) Event metadata keys prefixed with the involved object's API Group stripped of the prefix.
475
+ objectGroupPrefix := event .InvolvedObject .GroupVersionKind ().Group + "/"
476
+ for k , v := range event .Metadata {
477
+ if strings .HasPrefix (k , objectGroupPrefix ) {
478
+ key := strings .TrimPrefix (k , objectGroupPrefix )
479
+ metadata [key ] = v
480
+ metadataSources [key ] = append (metadataSources [key ], sourceObjectGroup )
481
+ }
482
+ }
483
+
484
+ // Detect key conflicts and emit warnings if any.
485
+ type keyConflict struct {
486
+ Key string `json:"key"`
487
+ Sources []string `json:"sources"`
488
+ }
489
+ var conflictingKeys []* keyConflict
490
+ conflictEventAnnotations := make (map [string ]string )
491
+ for key , sources := range metadataSources {
492
+ if len (sources ) > 1 {
493
+ conflictingKeys = append (conflictingKeys , & keyConflict {key , sources })
494
+ conflictEventAnnotations [key ] = strings .Join (sources , ", " )
495
+ }
496
+ }
497
+ if len (conflictingKeys ) > 0 {
498
+ const msg = "metadata key conflicts detected (please refer to the Alert API docs and Flux RFC 0008 for more information)"
499
+ slices .SortFunc (conflictingKeys , func (a , b * keyConflict ) int { return strings .Compare (a .Key , b .Key ) })
500
+ l .Info ("warning: " + msg , "conflictingKeys" , conflictingKeys )
501
+ s .AnnotatedEventf (alert , conflictEventAnnotations , corev1 .EventTypeWarning , "MetadataAppendFailed" , "%s" , msg )
441
502
}
442
503
443
- if len (meta ) > 0 {
444
- event .Metadata = meta
504
+ if len (metadata ) > 0 {
505
+ event .Metadata = metadata
445
506
}
446
507
}
447
508
@@ -450,7 +511,9 @@ func excludeInternalMetadata(event *eventv1.Event) {
450
511
if len (event .Metadata ) == 0 {
451
512
return
452
513
}
453
- excludeList := []string {eventv1 .MetaTokenKey }
514
+ objectGroup := event .InvolvedObject .GetObjectKind ().GroupVersionKind ().Group
515
+ tokenKey := fmt .Sprintf ("%s/%s" , objectGroup , eventv1 .MetaTokenKey )
516
+ excludeList := []string {tokenKey }
454
517
for _ , key := range excludeList {
455
518
delete (event .Metadata , key )
456
519
}
0 commit comments