diff --git a/api/v1beta1/alert_types.go b/api/v1beta1/alert_types.go
index 58d2e1bc3..3adf54d42 100644
--- a/api/v1beta1/alert_types.go
+++ b/api/v1beta1/alert_types.go
@@ -38,6 +38,10 @@ type AlertSpec struct {
// +required
EventSources []CrossNamespaceObjectReference `json:"eventSources"`
+ // Short description of the impact and affected cluster.
+ // +optional
+ Summary string `json:"summary,omitempty"`
+
// This flag tells the controller to suspend subsequent events dispatching.
// Defaults to false.
// +optional
diff --git a/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml b/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml
index d15a57eac..be432235a 100644
--- a/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml
+++ b/config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml
@@ -96,6 +96,9 @@ spec:
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
type: object
+ summary:
+ description: Short description of the impact and affected cluster.
+ type: string
suspend:
description: This flag tells the controller to suspend subsequent
events dispatching. Defaults to false.
diff --git a/docs/api/notification.md b/docs/api/notification.md
index 11348f5ba..8a0f45271 100644
--- a/docs/api/notification.md
+++ b/docs/api/notification.md
@@ -113,6 +113,18 @@ If set to ‘info’ no events will be filtered.
+
suspend
bool
diff --git a/docs/spec/v1beta1/alert.md b/docs/spec/v1beta1/alert.md
index cbc3f6cd9..8c4024655 100644
--- a/docs/spec/v1beta1/alert.md
+++ b/docs/spec/v1beta1/alert.md
@@ -21,6 +21,10 @@ type AlertSpec struct {
// +required
EventSources []CrossNamespaceObjectReference `json:"eventSources"`
+ // Short description of the impact and affected cluster.
+ // +optional
+ Summary string `json:"summary,omitempty"`
+
// This flag tells the controller to suspend subsequent events dispatching.
// Defaults to false.
// +optional
@@ -93,3 +97,21 @@ spec:
```
If you don't specify an event source namespace, the alert namespace will be used.
+
+You can add a summary to describe the impact of an event:
+
+```yaml
+apiVersion: notification.toolkit.fluxcd.io/v1beta1
+kind: Alert
+metadata:
+ name: ingress
+ namespace: nginx
+spec:
+ summary: "Ingress traffic affected in production (us-west-2)"
+ providerRef:
+ name: on-call-slack
+ eventSeverity: error
+ eventSources:
+ - kind: HelmRelease
+ name: nginx-ingress
+```
diff --git a/internal/server/event_handlers.go b/internal/server/event_handlers.go
index 77dc62ba8..03a01c73a 100644
--- a/internal/server/event_handlers.go
+++ b/internal/server/event_handlers.go
@@ -88,8 +88,6 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request)
}
}
- // find providers
- alertProviders := make([]notifier.Interface, 0)
if len(alerts) == 0 {
s.logger.Info("Discarding event, no alerts found for the involved object",
"object", event.InvolvedObject.Namespace+"/"+event.InvolvedObject.Name,
@@ -98,7 +96,12 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request)
return
}
- // find providers
+ s.logger.Info("Dispatching event",
+ "object", event.InvolvedObject.Namespace+"/"+event.InvolvedObject.Name,
+ "kind", event.InvolvedObject.Kind,
+ "message", event.Message)
+
+ // dispatch notifications
for _, alert := range alerts {
var provider v1beta1.Provider
providerName := types.NamespacedName{Namespace: alert.Namespace, Name: alert.Spec.ProviderRef.Name}
@@ -107,8 +110,7 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request)
if err != nil {
s.logger.Error(err, "failed to read provider",
"provider", providerName)
- w.WriteHeader(http.StatusBadRequest)
- return
+ continue
}
webhook := provider.Spec.Address
@@ -122,8 +124,7 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request)
s.logger.Error(err, "failed to read secret",
"provider", providerName,
"secret", secretName.Name)
- w.WriteHeader(http.StatusBadRequest)
- return
+ continue
}
if address, ok := secret.Data["address"]; ok {
@@ -138,8 +139,7 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request)
if webhook == "" {
s.logger.Error(nil, "provider has no address",
"provider", providerName)
- w.WriteHeader(http.StatusBadRequest)
- return
+ continue
}
factory := notifier.NewFactory(webhook, provider.Spec.Proxy, provider.Spec.Username, provider.Spec.Channel, token)
@@ -148,27 +148,27 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request)
s.logger.Error(err, "failed to initialise provider",
"provider", providerName,
"type", provider.Spec.Type)
- w.WriteHeader(http.StatusBadRequest)
- return
+ continue
}
- alertProviders = append(alertProviders, sender)
- }
-
- s.logger.Info("Dispatching event",
- "object", event.InvolvedObject.Namespace+"/"+event.InvolvedObject.Name,
- "kind", event.InvolvedObject.Kind,
- "message", event.Message)
+ notification := *event
+ if alert.Spec.Summary != "" {
+ if notification.Metadata == nil {
+ notification.Metadata = map[string]string{
+ "summary": alert.Spec.Summary,
+ }
+ } else {
+ notification.Metadata["summary"] = alert.Spec.Summary
+ }
+ }
- // send notifications in the background
- for _, provider := range alertProviders {
- go func(p notifier.Interface, e recorder.Event) {
- if err := p.Post(e); err != nil {
+ go func(n notifier.Interface, e recorder.Event) {
+ if err := n.Post(e); err != nil {
s.logger.Error(err, "failed to send notification",
"object", e.InvolvedObject.Namespace+"/"+e.InvolvedObject.Name,
- "kind", event.InvolvedObject.Kind)
+ "kind", e.InvolvedObject.Kind)
}
- }(provider, *event)
+ }(sender, notification)
}
w.WriteHeader(http.StatusAccepted)
|