diff --git a/pkg/services/ngalert/notifier/channels/telegram.go b/pkg/services/ngalert/notifier/channels/telegram.go index 948bf5f5ce4..8afc091ebae 100644 --- a/pkg/services/ngalert/notifier/channels/telegram.go +++ b/pkg/services/ngalert/notifier/channels/telegram.go @@ -8,6 +8,7 @@ import ( "io" "mime/multipart" "os" + "strings" "github.com/prometheus/alertmanager/notify" "github.com/prometheus/alertmanager/template" @@ -21,6 +22,11 @@ import ( var ( TelegramAPIURL = "https://api.telegram.org/bot%s/%s" + + DefaultParseMode = "HTML" + // SupportedParseMode is a map of all supported values for field `parse_mode`. https://core.telegram.org/bots/api#formatting-options. + // Keys are options accepted by Grafana API, values are options accepted by Telegram API + SupportedParseMode = map[string]string{"Markdown": "Markdown", "MarkdownV2": "MarkdownV2", DefaultParseMode: "HTML", "None": ""} ) // Telegram supports 4096 chars max - from https://limits.tginfo.me/en. @@ -38,9 +44,11 @@ type TelegramNotifier struct { } type telegramSettings struct { - BotToken string `json:"bottoken,omitempty" yaml:"bottoken,omitempty"` - ChatID string `json:"chatid,omitempty" yaml:"chatid,omitempty"` - Message string `json:"message,omitempty" yaml:"message,omitempty"` + BotToken string `json:"bottoken,omitempty" yaml:"bottoken,omitempty"` + ChatID string `json:"chatid,omitempty" yaml:"chatid,omitempty"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + ParseMode string `json:"parse_mode,omitempty" yaml:"parse_mode,omitempty"` + DisableNotifications bool `json:"disable_notifications,omitempty" yaml:"disable_notifications,omitempty"` } func buildTelegramSettings(fc FactoryConfig) (telegramSettings, error) { @@ -59,6 +67,21 @@ func buildTelegramSettings(fc FactoryConfig) (telegramSettings, error) { if settings.Message == "" { settings.Message = DefaultMessageEmbed } + // if field is missing, then we fall back to the previous default: HTML + if settings.ParseMode == "" { + settings.ParseMode = DefaultParseMode + } + found := false + for parseMode, value := range SupportedParseMode { + if strings.EqualFold(settings.ParseMode, parseMode) { + settings.ParseMode = value + found = true + break + } + } + if !found { + return settings, fmt.Errorf("unknown parse_mode, must be Markdown, MarkdownV2, HTML or None") + } return settings, nil } @@ -175,7 +198,12 @@ func (tn *TelegramNotifier) buildTelegramMessage(ctx context.Context, as []*type m := make(map[string]string) m["text"] = messageText - m["parse_mode"] = "html" + if tn.settings.ParseMode != "" { + m["parse_mode"] = tn.settings.ParseMode + } + if tn.settings.DisableNotifications { + m["disable_notification"] = "true" + } return m, nil } diff --git a/pkg/services/ngalert/notifier/channels/telegram_test.go b/pkg/services/ngalert/notifier/channels/telegram_test.go index b306f6816aa..98ed3f8a296 100644 --- a/pkg/services/ngalert/notifier/channels/telegram_test.go +++ b/pkg/services/ngalert/notifier/channels/telegram_test.go @@ -35,7 +35,9 @@ func TestTelegramNotifier(t *testing.T) { name: "A single alert with default template", settings: `{ "bottoken": "abcdefgh0123456789", - "chatid": "someid" + "chatid": "someid", + "parse_mode": "markdown", + "disable_notifications": true }`, alerts: []*types.Alert{ { @@ -47,8 +49,9 @@ func TestTelegramNotifier(t *testing.T) { }, }, expMsg: map[string]string{ - "parse_mode": "html", - "text": "**Firing**\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val1\nAnnotations:\n - ann1 = annv1\nSource: a URL\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", + "parse_mode": "Markdown", + "text": "**Firing**\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val1\nAnnotations:\n - ann1 = annv1\nSource: a URL\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", + "disable_notification": "true", }, expMsgError: nil, }, { @@ -73,7 +76,7 @@ func TestTelegramNotifier(t *testing.T) { }, }, expMsg: map[string]string{ - "parse_mode": "html", + "parse_mode": "HTML", "text": "__Custom Firing__\n2 Firing\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val1\nAnnotations:\n - ann1 = annv1\nSource: a URL\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=lbl1%3Dval1\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val2\nAnnotations:\n - ann1 = annv2\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=lbl1%3Dval2\n", }, expMsgError: nil, @@ -92,7 +95,7 @@ func TestTelegramNotifier(t *testing.T) { }, }, expMsg: map[string]string{ - "parse_mode": "html", + "parse_mode": "HTML", "text": strings.Repeat("1", 4096-1) + "…", }, expMsgError: nil, @@ -100,6 +103,14 @@ func TestTelegramNotifier(t *testing.T) { name: "Error in initing", settings: `{}`, expInitError: `could not find Bot Token in settings`, + }, { + name: "Invalid parse mode", + settings: `{ + "bottoken": "abcdefgh0123456789", + "chatid": "someid", + "parse_mode": "test" + }`, + expInitError: "unknown parse_mode, must be Markdown, MarkdownV2, HTML or None", }, } diff --git a/pkg/services/ngalert/notifier/channels_config/available_channels.go b/pkg/services/ngalert/notifier/channels_config/available_channels.go index 400b8f202ff..64458d2df09 100644 --- a/pkg/services/ngalert/notifier/channels_config/available_channels.go +++ b/pkg/services/ngalert/notifier/channels_config/available_channels.go @@ -682,6 +682,36 @@ func GetAvailableNotifiers() []*NotifierPlugin { Placeholder: channels.DefaultMessageEmbed, PropertyName: "message", }, + { + Label: "Parse Mode", + Element: ElementTypeSelect, + SelectOptions: []SelectOption{ + { + Value: "None", + Label: "None", + }, + { + Value: "HTML", + Label: "HTML", + }, + { + Value: "Markdown", + Label: "Markdown", + }, + { + Value: "MarkdownV2", + Label: "Markdown V2", + }, + }, + Description: `Mode for parsing entities in the message text. Default is 'HTML'`, + PropertyName: "parse_mode", + }, + { + Label: "Disable Notification", + Description: "Sends the message silently. Users will receive a notification with no sound.", + Element: ElementTypeCheckbox, + PropertyName: "disable_notification", + }, }, }, { diff --git a/pkg/tests/api/alerting/api_notification_channel_test.go b/pkg/tests/api/alerting/api_notification_channel_test.go index 8321680e67c..20937761e66 100644 --- a/pkg/tests/api/alerting/api_notification_channel_test.go +++ b/pkg/tests/api/alerting/api_notification_channel_test.go @@ -2532,7 +2532,7 @@ var expNonEmailNotifications = map[string][]string{ "--abcd\r\nContent-Disposition: form-data; name=\"user\"\r\n\r\nmysecretkey\r\n--abcd\r\nContent-Disposition: form-data; name=\"token\"\r\n\r\nmysecrettoken\r\n--abcd\r\nContent-Disposition: form-data; name=\"priority\"\r\n\r\n0\r\n--abcd\r\nContent-Disposition: form-data; name=\"sound\"\r\n\r\n\r\n--abcd\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\n[FIRING:1] PushoverAlert (default)\r\n--abcd\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\nhttp://localhost:3000/alerting/list\r\n--abcd\r\nContent-Disposition: form-data; name=\"url_title\"\r\n\r\nShow alert rule\r\n--abcd\r\nContent-Disposition: form-data; name=\"message\"\r\n\r\n**Firing**\n\nValue: A=1\nLabels:\n - alertname = PushoverAlert\n - grafana_folder = default\nAnnotations:\nSource: http://localhost:3000/alerting/grafana/UID_PushoverAlert/view\nSilence: http://localhost:3000/alerting/silence/new?alertmanager=grafana&matcher=alertname%3DPushoverAlert&matcher=grafana_folder%3Ddefault\r\n--abcd\r\nContent-Disposition: form-data; name=\"html\"\r\n\r\n1\r\n--abcd--\r\n", }, "telegram_recv/bot6sh027hs034h": { - "--abcd\r\nContent-Disposition: form-data; name=\"chat_id\"\r\n\r\ntelegram_chat_id\r\n--abcd\r\nContent-Disposition: form-data; name=\"parse_mode\"\r\n\r\nhtml\r\n--abcd\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\n**Firing**\n\nValue: A=1\nLabels:\n - alertname = TelegramAlert\n - grafana_folder = default\nAnnotations:\nSource: http://localhost:3000/alerting/grafana/UID_TelegramAlert/view\nSilence: http://localhost:3000/alerting/silence/new?alertmanager=grafana&matcher=alertname%3DTelegramAlert&matcher=grafana_folder%3Ddefault\n\r\n--abcd--\r\n", + "--abcd\r\nContent-Disposition: form-data; name=\"chat_id\"\r\n\r\ntelegram_chat_id\r\n--abcd\r\nContent-Disposition: form-data; name=\"parse_mode\"\r\n\r\nHTML\r\n--abcd\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\n**Firing**\n\nValue: A=1\nLabels:\n - alertname = TelegramAlert\n - grafana_folder = default\nAnnotations:\nSource: http://localhost:3000/alerting/grafana/UID_TelegramAlert/view\nSilence: http://localhost:3000/alerting/silence/new?alertmanager=grafana&matcher=alertname%3DTelegramAlert&matcher=grafana_folder%3Ddefault\n\r\n--abcd--\r\n", }, "googlechat_recv/googlechat_test": { `{