diff --git a/pkg/services/ngalert/notifier/channels/pagerduty.go b/pkg/services/ngalert/notifier/channels/pagerduty.go index 55de0adc5d0..3dd574eb1ce 100644 --- a/pkg/services/ngalert/notifier/channels/pagerduty.go +++ b/pkg/services/ngalert/notifier/channels/pagerduty.go @@ -31,83 +31,68 @@ var ( // alert notifications to pagerduty type PagerdutyNotifier struct { *Base - Key string - Severity string - CustomDetails map[string]string - Class string - Component string - Group string - Summary string - tmpl *template.Template - log log.Logger - ns notifications.WebhookSender - images ImageStore + tmpl *template.Template + log log.Logger + ns notifications.WebhookSender + images ImageStore + settings pagerdutySettings } -type PagerdutyConfig struct { - *NotificationChannelConfig - Key string - Severity string - Class string - Component string - Group string - Summary string +type pagerdutySettings struct { + Key string `json:"integrationKey,omitempty" yaml:"integrationKey,omitempty"` + Severity string `json:"severity,omitempty" yaml:"severity,omitempty"` + customDetails map[string]string + Class string `json:"class,omitempty" yaml:"class,omitempty"` + Component string `json:"component,omitempty" yaml:"component,omitempty"` + Group string `json:"group,omitempty" yaml:"group,omitempty"` + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` } func PagerdutyFactory(fc FactoryConfig) (NotificationChannel, error) { - cfg, err := NewPagerdutyConfig(fc.Config, fc.DecryptFunc) + pdn, err := newPagerdutyNotifier(fc) if err != nil { return nil, receiverInitError{ Reason: err.Error(), Cfg: *fc.Config, } } - return NewPagerdutyNotifier(cfg, fc.NotificationService, fc.ImageStore, fc.Template), nil -} - -func NewPagerdutyConfig(config *NotificationChannelConfig, decryptFunc GetDecryptedValueFn) (*PagerdutyConfig, error) { - key := decryptFunc(context.Background(), config.SecureSettings, "integrationKey", config.Settings.Get("integrationKey").MustString()) - if key == "" { - return nil, errors.New("could not find integration key property in settings") - } - return &PagerdutyConfig{ - NotificationChannelConfig: config, - Key: key, - Severity: config.Settings.Get("severity").MustString("critical"), - Class: config.Settings.Get("class").MustString("default"), - Component: config.Settings.Get("component").MustString("Grafana"), - Group: config.Settings.Get("group").MustString("default"), - Summary: config.Settings.Get("summary").MustString(DefaultMessageTitleEmbed), - }, nil + return pdn, nil } // NewPagerdutyNotifier is the constructor for the PagerDuty notifier -func NewPagerdutyNotifier(config *PagerdutyConfig, ns notifications.WebhookSender, images ImageStore, t *template.Template) *PagerdutyNotifier { +func newPagerdutyNotifier(fc FactoryConfig) (*PagerdutyNotifier, error) { + key := fc.DecryptFunc(context.Background(), fc.Config.SecureSettings, "integrationKey", fc.Config.Settings.Get("integrationKey").MustString()) + if key == "" { + return nil, errors.New("could not find integration key property in settings") + } + return &PagerdutyNotifier{ Base: NewBase(&models.AlertNotification{ - Uid: config.UID, - Name: config.Name, - Type: config.Type, - DisableResolveMessage: config.DisableResolveMessage, - Settings: config.Settings, + Uid: fc.Config.UID, + Name: fc.Config.Name, + Type: fc.Config.Type, + DisableResolveMessage: fc.Config.DisableResolveMessage, + Settings: fc.Config.Settings, }), - Key: config.Key, - CustomDetails: map[string]string{ - "firing": `{{ template "__text_alert_list" .Alerts.Firing }}`, - "resolved": `{{ template "__text_alert_list" .Alerts.Resolved }}`, - "num_firing": `{{ .Alerts.Firing | len }}`, - "num_resolved": `{{ .Alerts.Resolved | len }}`, + tmpl: fc.Template, + log: log.New("alerting.notifier." + fc.Config.Name), + ns: fc.NotificationService, + images: fc.ImageStore, + settings: pagerdutySettings{ + Key: key, + Severity: fc.Config.Settings.Get("severity").MustString("critical"), + customDetails: map[string]string{ + "firing": `{{ template "__text_alert_list" .Alerts.Firing }}`, + "resolved": `{{ template "__text_alert_list" .Alerts.Resolved }}`, + "num_firing": `{{ .Alerts.Firing | len }}`, + "num_resolved": `{{ .Alerts.Resolved | len }}`, + }, + Class: fc.Config.Settings.Get("class").MustString("default"), + Component: fc.Config.Settings.Get("component").MustString("Grafana"), + Group: fc.Config.Settings.Get("group").MustString("default"), + Summary: fc.Config.Settings.Get("summary").MustString(DefaultMessageTitleEmbed), }, - Severity: config.Severity, - Class: config.Class, - Component: config.Component, - Group: config.Group, - Summary: config.Summary, - tmpl: t, - log: log.New("alerting.notifier." + config.Name), - ns: ns, - images: images, - } + }, nil } // Notify sends an alert notification to PagerDuty @@ -158,8 +143,8 @@ func (pn *PagerdutyNotifier) buildPagerdutyMessage(ctx context.Context, alerts m var tmplErr error tmpl, data := TmplText(ctx, pn.tmpl, as, pn.log, &tmplErr) - details := make(map[string]string, len(pn.CustomDetails)) - for k, v := range pn.CustomDetails { + details := make(map[string]string, len(pn.settings.customDetails)) + for k, v := range pn.settings.customDetails { detail, err := pn.tmpl.ExecuteTextString(v, data) if err != nil { return nil, "", fmt.Errorf("%q: failed to template %q: %w", k, v, err) @@ -170,21 +155,20 @@ func (pn *PagerdutyNotifier) buildPagerdutyMessage(ctx context.Context, alerts m msg := &pagerDutyMessage{ Client: "Grafana", ClientURL: pn.tmpl.ExternalURL.String(), - RoutingKey: pn.Key, + RoutingKey: pn.settings.Key, EventAction: eventType, DedupKey: key.Hash(), Links: []pagerDutyLink{{ HRef: pn.tmpl.ExternalURL.String(), Text: "External URL", }}, - Description: tmpl(DefaultMessageTitleEmbed), // TODO: this can be configurable template. Payload: pagerDutyPayload{ - Component: tmpl(pn.Component), - Summary: tmpl(pn.Summary), - Severity: tmpl(pn.Severity), + Component: tmpl(pn.settings.Component), + Summary: tmpl(pn.settings.Summary), + Severity: tmpl(pn.settings.Severity), CustomDetails: details, - Class: tmpl(pn.Class), - Group: tmpl(pn.Group), + Class: tmpl(pn.settings.Class), + Group: tmpl(pn.settings.Group), }, } @@ -223,7 +207,6 @@ type pagerDutyMessage struct { RoutingKey string `json:"routing_key,omitempty"` ServiceKey string `json:"service_key,omitempty"` DedupKey string `json:"dedup_key,omitempty"` - Description string `json:"description,omitempty"` EventAction string `json:"event_action"` Payload pagerDutyPayload `json:"payload"` Client string `json:"client,omitempty"` diff --git a/pkg/services/ngalert/notifier/channels/pagerduty_test.go b/pkg/services/ngalert/notifier/channels/pagerduty_test.go index 560fef137a4..7e86b040f5b 100644 --- a/pkg/services/ngalert/notifier/channels/pagerduty_test.go +++ b/pkg/services/ngalert/notifier/channels/pagerduty_test.go @@ -49,7 +49,6 @@ func TestPagerdutyNotifier(t *testing.T) { expMsg: &pagerDutyMessage{ RoutingKey: "abcdefgh0123456789", DedupKey: "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733", - Description: "[FIRING:1] (val1)", EventAction: "trigger", Payload: pagerDutyPayload{ Summary: "[FIRING:1] (val1)", @@ -70,6 +69,40 @@ func TestPagerdutyNotifier(t *testing.T) { Links: []pagerDutyLink{{HRef: "http://localhost", Text: "External URL"}}, }, expMsgError: nil, + }, { + name: "Default config with one alert and custom summary", + settings: `{"integrationKey": "abcdefgh0123456789", "summary": "Alerts firing: {{ len .Alerts.Firing }}"}`, + alerts: []*types.Alert{ + { + Alert: model.Alert{ + Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"}, + Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh"}, + }, + }, + }, + expMsg: &pagerDutyMessage{ + RoutingKey: "abcdefgh0123456789", + DedupKey: "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733", + EventAction: "trigger", + Payload: pagerDutyPayload{ + Summary: "Alerts firing: 1", + Source: hostname, + Severity: "critical", + Class: "default", + Component: "Grafana", + Group: "default", + CustomDetails: map[string]string{ + "firing": "\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val1\nAnnotations:\n - ann1 = annv1\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=lbl1%3Dval1\nDashboard: http://localhost/d/abcd\nPanel: http://localhost/d/abcd?viewPanel=efgh\n", + "num_firing": "1", + "num_resolved": "0", + "resolved": "", + }, + }, + Client: "Grafana", + ClientURL: "http://localhost", + Links: []pagerDutyLink{{HRef: "http://localhost", Text: "External URL"}}, + }, + expMsgError: nil, }, { name: "Custom config with multiple alerts", settings: `{ @@ -95,7 +128,6 @@ func TestPagerdutyNotifier(t *testing.T) { expMsg: &pagerDutyMessage{ RoutingKey: "abcdefgh0123456789", DedupKey: "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733", - Description: "[FIRING:2] ", EventAction: "trigger", Payload: pagerDutyPayload{ Summary: "[FIRING:2] ", @@ -128,18 +160,22 @@ func TestPagerdutyNotifier(t *testing.T) { settingsJSON, err := simplejson.NewJson([]byte(c.settings)) require.NoError(t, err) secureSettings := make(map[string][]byte) - - m := &NotificationChannelConfig{ - Name: "pageduty_testing", - Type: "pagerduty", - Settings: settingsJSON, - SecureSettings: secureSettings, - } - webhookSender := mockNotificationService() secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) decryptFn := secretsService.GetDecryptedValue - cfg, err := NewPagerdutyConfig(m, decryptFn) + + fc := FactoryConfig{ + Config: &NotificationChannelConfig{ + Name: "pageduty_testing", + Type: "pagerduty", + Settings: settingsJSON, + SecureSettings: secureSettings, + }, + NotificationService: webhookSender, + DecryptFunc: decryptFn, + Template: tmpl, + } + pn, err := newPagerdutyNotifier(fc) if c.expInitError != "" { require.Error(t, err) require.Equal(t, c.expInitError, err.Error()) @@ -149,7 +185,6 @@ func TestPagerdutyNotifier(t *testing.T) { ctx := notify.WithGroupKey(context.Background(), "alertname") ctx = notify.WithGroupLabels(ctx, model.LabelSet{"alertname": ""}) - pn := NewPagerdutyNotifier(cfg, webhookSender, &UnavailableImageStore{}, tmpl) ok, err := pn.Notify(ctx, c.alerts...) if c.expMsgError != nil { require.False(t, ok) diff --git a/pkg/services/ngalert/notifier/channels_config/available_channels.go b/pkg/services/ngalert/notifier/channels_config/available_channels.go index 18d798c2205..8c6b8c12187 100644 --- a/pkg/services/ngalert/notifier/channels_config/available_channels.go +++ b/pkg/services/ngalert/notifier/channels_config/available_channels.go @@ -286,8 +286,9 @@ func GetAvailableNotifiers() []*NotifierPlugin { { // New in 8.0. Label: "Summary", Description: "You can use templates for summary", - Element: ElementTypeTextArea, - Placeholder: channels.DefaultMessageEmbed, + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: channels.DefaultMessageTitleEmbed, PropertyName: "summary", }, }, diff --git a/pkg/tests/api/alerting/api_notification_channel_test.go b/pkg/tests/api/alerting/api_notification_channel_test.go index 523fe8441a5..efafd6c60d1 100644 --- a/pkg/tests/api/alerting/api_notification_channel_test.go +++ b/pkg/tests/api/alerting/api_notification_channel_test.go @@ -1612,7 +1612,7 @@ const alertmanagerConfig = ` } } ] - }, + }, { "name": "slack_recv2", "grafana_managed_receiver_configs": [ @@ -2356,7 +2356,6 @@ var expNonEmailNotifications = map[string][]string{ `{ "routing_key": "pagerduty_recv/pagerduty_test", "dedup_key": "234edb34441f942f713f3c2ccf58b1d719d921b4cbe34e57a1630f1dee847e3b", - "description": "[FIRING:1] PagerdutyAlert (default)", "event_action": "trigger", "payload": { "summary": "Integration Test [FIRING:1] PagerdutyAlert (default)",