Fix Discord notifications not being sent due to templating issues (#48208)

* empty URLs fixed

* move comment

* test cases
This commit is contained in:
Santiago 2022-04-28 15:58:07 -03:00 committed by GitHub
parent 735822e48a
commit d9de621d20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 147 additions and 13 deletions

View File

@ -50,7 +50,7 @@ func NewDiscordConfig(config *NotificationChannelConfig) (*DiscordConfig, error)
}, nil
}
func DiscrodFactory(fc FactoryConfig) (NotificationChannel, error) {
func DiscordFactory(fc FactoryConfig) (NotificationChannel, error) {
cfg, err := NewDiscordConfig(fc.Config)
if err != nil {
return nil, receiverInitError{
@ -95,10 +95,20 @@ func (d DiscordNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool,
if d.Content != "" {
bodyJSON.Set("content", tmpl(d.Content))
if tmplErr != nil {
d.log.Warn("failed to template Discord notification content", "err", tmplErr.Error())
// Reset tmplErr for templating other fields.
tmplErr = nil
}
}
if d.AvatarURL != "" {
bodyJSON.Set("avatar_url", tmpl(d.AvatarURL))
if tmplErr != nil {
d.log.Warn("failed to template Discord Avatar URL", "err", tmplErr.Error(), "fallback", d.AvatarURL)
bodyJSON.Set("avatar_url", d.AvatarURL)
tmplErr = nil
}
}
footer := map[string]interface{}{
@ -119,10 +129,15 @@ func (d DiscordNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool,
bodyJSON.Set("embeds", []interface{}{embed})
u := tmpl(d.WebhookURL)
if tmplErr != nil {
d.log.Warn("failed to template Discord message", "err", tmplErr.Error())
return false, tmplErr
tmplErr = nil
}
u := tmpl(d.WebhookURL)
if tmplErr != nil {
d.log.Warn("failed to template Discord URL", "err", tmplErr.Error(), "fallback", d.WebhookURL)
u = d.WebhookURL
}
body, err := json.Marshal(bodyJSON)

View File

@ -3,7 +3,6 @@ package channels
import (
"context"
"encoding/json"
"errors"
"net/url"
"testing"
@ -58,6 +57,134 @@ func TestDiscordNotifier(t *testing.T) {
},
expMsgError: nil,
},
{
name: "Missing field in template",
settings: `{
"avatar_url": "https://grafana.com/assets/img/fav32.png",
"url": "http://localhost",
"message": "I'm a custom template {{ .NotAField }} bad template"
}`,
alerts: []*types.Alert{
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
Annotations: model.LabelSet{"ann1": "annv1"},
},
},
},
expMsg: map[string]interface{}{
"avatar_url": "https://grafana.com/assets/img/fav32.png",
"content": "I'm a custom template ",
"embeds": []interface{}{map[string]interface{}{
"color": 1.4037554e+07,
"footer": map[string]interface{}{
"icon_url": "https://grafana.com/assets/img/fav32.png",
"text": "Grafana v" + setting.BuildVersion,
},
"title": "[FIRING:1] (val1)",
"url": "http://localhost/alerting/list",
"type": "rich",
}},
"username": "Grafana",
},
expMsgError: nil,
},
{
name: "Invalid message template",
settings: `{
"avatar_url": "https://grafana.com/assets/img/fav32.png",
"url": "http://localhost",
"message": "{{ template \"invalid.template\" }}"
}`,
alerts: []*types.Alert{
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
Annotations: model.LabelSet{"ann1": "annv1"},
},
},
},
expMsg: map[string]interface{}{
"avatar_url": "https://grafana.com/assets/img/fav32.png",
"content": "",
"embeds": []interface{}{map[string]interface{}{
"color": 1.4037554e+07,
"footer": map[string]interface{}{
"icon_url": "https://grafana.com/assets/img/fav32.png",
"text": "Grafana v" + setting.BuildVersion,
},
"title": "[FIRING:1] (val1)",
"url": "http://localhost/alerting/list",
"type": "rich",
}},
"username": "Grafana",
},
expMsgError: nil,
},
{
name: "Invalid avatar URL template",
settings: `{
"avatar_url": "{{ invalid } }}",
"url": "http://localhost",
"message": "valid message"
}`,
alerts: []*types.Alert{
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
Annotations: model.LabelSet{"ann1": "annv1"},
},
},
},
expMsg: map[string]interface{}{
"avatar_url": "{{ invalid } }}",
"content": "valid message",
"embeds": []interface{}{map[string]interface{}{
"color": 1.4037554e+07,
"footer": map[string]interface{}{
"icon_url": "https://grafana.com/assets/img/fav32.png",
"text": "Grafana v" + setting.BuildVersion,
},
"title": "[FIRING:1] (val1)",
"url": "http://localhost/alerting/list",
"type": "rich",
}},
"username": "Grafana",
},
expMsgError: nil,
},
{
name: "Invalid URL template",
settings: `{
"avatar_url": "https://grafana.com/assets/img/fav32.png",
"url": "http://localhost?q={{invalid }}}",
"message": "valid message"
}`,
alerts: []*types.Alert{
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
Annotations: model.LabelSet{"ann1": "annv1"},
},
},
},
expMsg: map[string]interface{}{
"avatar_url": "https://grafana.com/assets/img/fav32.png",
"content": "valid message",
"embeds": []interface{}{map[string]interface{}{
"color": 1.4037554e+07,
"footer": map[string]interface{}{
"icon_url": "https://grafana.com/assets/img/fav32.png",
"text": "Grafana v" + setting.BuildVersion,
},
"title": "[FIRING:1] (val1)",
"url": "http://localhost/alerting/list",
"type": "rich",
}},
"username": "Grafana",
},
expMsgError: nil,
},
{
name: "Custom config with multiple alerts",
settings: `{
@ -100,14 +227,6 @@ func TestDiscordNotifier(t *testing.T) {
settings: `{}`,
expInitError: `could not find webhook url property in settings`,
},
{
name: "Invalid template returns error",
settings: `{
"url": "http://localhost",
"message": "{{ template \"invalid.template\" }}"
}`,
expMsgError: errors.New("template: :1:12: executing \"\" at <{{template \"invalid.template\"}}>: template \"invalid.template\" not defined"),
},
{
name: "Default config with one alert, use default discord username",
settings: `{

View File

@ -36,7 +36,7 @@ func NewFactoryConfig(config *NotificationChannelConfig, notificationService not
var receiverFactories = map[string]func(FactoryConfig) (NotificationChannel, error){
"prometheus-alertmanager": AlertmanagerFactory,
"dingding": DingDingFactory,
"discord": DiscrodFactory,
"discord": DiscordFactory,
"email": EmailFactory,
"googlechat": GoogleChatFactory,
"kafka": KafkaFactory,