mirror of
https://github.com/grafana/grafana.git
synced 2024-12-29 10:21:41 -06:00
Alerting: update dingding, discord, googlechat, kafka, line notifiers to use encoding/json to parse settings (#60542)
also, rename Content to Message to match JSON name for Discord and GoogleChat
This commit is contained in:
parent
76e23a9fef
commit
ec45c9c990
@ -10,34 +10,36 @@ import (
|
||||
"github.com/grafana/alerting/alerting/notifier/channels"
|
||||
"github.com/prometheus/alertmanager/template"
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
)
|
||||
|
||||
const defaultDingdingMsgType = "link"
|
||||
|
||||
type dingDingSettings struct {
|
||||
URL string
|
||||
MessageType string
|
||||
Title string
|
||||
Message string
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
MessageType string `json:"msgType,omitempty" yaml:"msgType,omitempty"`
|
||||
Title string `json:"title,omitempty" yaml:"title,omitempty"`
|
||||
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
||||
}
|
||||
|
||||
func buildDingDingSettings(fc channels.FactoryConfig) (*dingDingSettings, error) {
|
||||
settings, err := simplejson.NewJson(fc.Config.Settings)
|
||||
var settings dingDingSettings
|
||||
err := json.Unmarshal(fc.Config.Settings, &settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to unmarshal settings: %w", err)
|
||||
}
|
||||
URL := settings.Get("url").MustString()
|
||||
if URL == "" {
|
||||
if settings.URL == "" {
|
||||
return nil, errors.New("could not find url property in settings")
|
||||
}
|
||||
return &dingDingSettings{
|
||||
URL: URL,
|
||||
MessageType: settings.Get("msgType").MustString(defaultDingdingMsgType),
|
||||
Title: settings.Get("title").MustString(channels.DefaultMessageTitleEmbed),
|
||||
Message: settings.Get("message").MustString(channels.DefaultMessageEmbed),
|
||||
}, nil
|
||||
if settings.MessageType == "" {
|
||||
settings.MessageType = defaultDingdingMsgType
|
||||
}
|
||||
if settings.Title == "" {
|
||||
settings.Title = channels.DefaultMessageTitleEmbed
|
||||
}
|
||||
if settings.Message == "" {
|
||||
settings.Message = channels.DefaultMessageEmbed
|
||||
}
|
||||
return &settings, nil
|
||||
}
|
||||
|
||||
func DingDingFactory(fc channels.FactoryConfig) (channels.NotificationChannel, error) {
|
||||
|
@ -80,7 +80,7 @@ func TestDingdingNotifier(t *testing.T) {
|
||||
expMsgError: nil,
|
||||
}, {
|
||||
name: "Default config with one alert and custom title and description",
|
||||
settings: `{"url": "http://localhost", "title": "Alerts firing: {{ len .Alerts.Firing }}", "message": "customMessage"}}`,
|
||||
settings: `{"url": "http://localhost", "title": "Alerts firing: {{ len .Alerts.Firing }}", "message": "customMessage"}`,
|
||||
alerts: []*types.Alert{
|
||||
{
|
||||
Alert: model.Alert{
|
||||
|
@ -27,15 +27,33 @@ type DiscordNotifier struct {
|
||||
ns channels.WebhookSender
|
||||
images channels.ImageStore
|
||||
tmpl *template.Template
|
||||
settings discordSettings
|
||||
settings *discordSettings
|
||||
}
|
||||
|
||||
type discordSettings struct {
|
||||
Title string
|
||||
Content string
|
||||
AvatarURL string
|
||||
WebhookURL string
|
||||
UseDiscordUsername bool
|
||||
Title string `json:"title,omitempty" yaml:"title,omitempty"`
|
||||
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
||||
AvatarURL string `json:"avatar_url,omitempty" yaml:"avatar_url,omitempty"`
|
||||
WebhookURL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
UseDiscordUsername bool `json:"use_discord_username,omitempty" yaml:"use_discord_username,omitempty"`
|
||||
}
|
||||
|
||||
func buildDiscordSettings(fc channels.FactoryConfig) (*discordSettings, error) {
|
||||
var settings discordSettings
|
||||
err := json.Unmarshal(fc.Config.Settings, &settings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal settings: %w", err)
|
||||
}
|
||||
if settings.WebhookURL == "" {
|
||||
return nil, errors.New("could not find webhook url property in settings")
|
||||
}
|
||||
if settings.Title == "" {
|
||||
settings.Title = channels.DefaultMessageTitleEmbed
|
||||
}
|
||||
if settings.Message == "" {
|
||||
settings.Message = channels.DefaultMessageEmbed
|
||||
}
|
||||
return &settings, nil
|
||||
}
|
||||
|
||||
type discordAttachment struct {
|
||||
@ -60,28 +78,17 @@ func DiscordFactory(fc channels.FactoryConfig) (channels.NotificationChannel, er
|
||||
}
|
||||
|
||||
func newDiscordNotifier(fc channels.FactoryConfig) (*DiscordNotifier, error) {
|
||||
settings, err := simplejson.NewJson(fc.Config.Settings)
|
||||
settings, err := buildDiscordSettings(fc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dUrl := settings.Get("url").MustString()
|
||||
if dUrl == "" {
|
||||
return nil, errors.New("could not find webhook url property in settings")
|
||||
}
|
||||
|
||||
return &DiscordNotifier{
|
||||
Base: channels.NewBase(fc.Config),
|
||||
log: fc.Logger,
|
||||
ns: fc.NotificationService,
|
||||
images: fc.ImageStore,
|
||||
tmpl: fc.Template,
|
||||
settings: discordSettings{
|
||||
Title: settings.Get("title").MustString(channels.DefaultMessageTitleEmbed),
|
||||
Content: settings.Get("message").MustString(channels.DefaultMessageEmbed),
|
||||
AvatarURL: settings.Get("avatar_url").MustString(),
|
||||
WebhookURL: dUrl,
|
||||
UseDiscordUsername: settings.Get("use_discord_username").MustBool(false),
|
||||
},
|
||||
Base: channels.NewBase(fc.Config),
|
||||
log: fc.Logger,
|
||||
ns: fc.NotificationService,
|
||||
images: fc.ImageStore,
|
||||
tmpl: fc.Template,
|
||||
settings: settings,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -97,7 +104,7 @@ func (d DiscordNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool,
|
||||
var tmplErr error
|
||||
tmpl, _ := channels.TmplText(ctx, d.tmpl, as, d.log, &tmplErr)
|
||||
|
||||
bodyJSON.Set("content", tmpl(d.settings.Content))
|
||||
bodyJSON.Set("content", tmpl(d.settings.Message))
|
||||
if tmplErr != nil {
|
||||
d.log.Warn("failed to template Discord notification content", "error", tmplErr.Error())
|
||||
// Reset tmplErr for templating other fields.
|
||||
|
@ -12,7 +12,6 @@ import (
|
||||
"github.com/prometheus/alertmanager/template"
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@ -24,13 +23,32 @@ type GoogleChatNotifier struct {
|
||||
ns channels.WebhookSender
|
||||
images channels.ImageStore
|
||||
tmpl *template.Template
|
||||
settings googleChatSettings
|
||||
settings *googleChatSettings
|
||||
}
|
||||
|
||||
type googleChatSettings struct {
|
||||
URL string
|
||||
Title string
|
||||
Content string
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
Title string `json:"title,omitempty" yaml:"title,omitempty"`
|
||||
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
||||
}
|
||||
|
||||
func buildGoogleChatSettings(fc channels.FactoryConfig) (*googleChatSettings, error) {
|
||||
var settings googleChatSettings
|
||||
err := json.Unmarshal(fc.Config.Settings, &settings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal settings: %w", err)
|
||||
}
|
||||
|
||||
if settings.URL == "" {
|
||||
return nil, errors.New("could not find url property in settings")
|
||||
}
|
||||
if settings.Title == "" {
|
||||
settings.Title = channels.DefaultMessageTitleEmbed
|
||||
}
|
||||
if settings.Message == "" {
|
||||
settings.Message = channels.DefaultMessageEmbed
|
||||
}
|
||||
return &settings, nil
|
||||
}
|
||||
|
||||
func GoogleChatFactory(fc channels.FactoryConfig) (channels.NotificationChannel, error) {
|
||||
@ -45,32 +63,17 @@ func GoogleChatFactory(fc channels.FactoryConfig) (channels.NotificationChannel,
|
||||
}
|
||||
|
||||
func newGoogleChatNotifier(fc channels.FactoryConfig) (*GoogleChatNotifier, error) {
|
||||
var settings googleChatSettings
|
||||
err := json.Unmarshal(fc.Config.Settings, &settings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal settings: %w", err)
|
||||
}
|
||||
|
||||
rawsettings, err := simplejson.NewJson(fc.Config.Settings)
|
||||
settings, err := buildGoogleChatSettings(fc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
URL := rawsettings.Get("url").MustString()
|
||||
if URL == "" {
|
||||
return nil, errors.New("could not find url property in settings")
|
||||
}
|
||||
|
||||
return &GoogleChatNotifier{
|
||||
Base: channels.NewBase(fc.Config),
|
||||
log: fc.Logger,
|
||||
ns: fc.NotificationService,
|
||||
images: fc.ImageStore,
|
||||
tmpl: fc.Template,
|
||||
settings: googleChatSettings{
|
||||
URL: URL,
|
||||
Title: rawsettings.Get("title").MustString(channels.DefaultMessageTitleEmbed),
|
||||
Content: rawsettings.Get("message").MustString(channels.DefaultMessageEmbed),
|
||||
},
|
||||
Base: channels.NewBase(fc.Config),
|
||||
log: fc.Logger,
|
||||
ns: fc.NotificationService,
|
||||
images: fc.ImageStore,
|
||||
tmpl: fc.Template,
|
||||
settings: settings,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -83,7 +86,7 @@ func (gcn *GoogleChatNotifier) Notify(ctx context.Context, as ...*types.Alert) (
|
||||
|
||||
var widgets []widget
|
||||
|
||||
if msg := tmpl(gcn.settings.Content); msg != "" {
|
||||
if msg := tmpl(gcn.settings.Message); msg != "" {
|
||||
// Add a text paragraph widget for the message if there is a message.
|
||||
// Google Chat API doesn't accept an empty text property.
|
||||
widgets = append(widgets, textParagraphWidget{Text: text{Text: msg}})
|
||||
|
@ -2,7 +2,9 @@ package channels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/alertmanager/notify"
|
||||
@ -24,14 +26,36 @@ type KafkaNotifier struct {
|
||||
images channels.ImageStore
|
||||
ns channels.WebhookSender
|
||||
tmpl *template.Template
|
||||
settings kafkaSettings
|
||||
settings *kafkaSettings
|
||||
}
|
||||
|
||||
type kafkaSettings struct {
|
||||
Endpoint string
|
||||
Topic string
|
||||
Description string
|
||||
Details string
|
||||
Endpoint string `json:"kafkaRestProxy,omitempty" yaml:"kafkaRestProxy,omitempty"`
|
||||
Topic string `json:"kafkaTopic,omitempty" yaml:"kafkaTopic,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Details string `json:"details,omitempty" yaml:"details,omitempty"`
|
||||
}
|
||||
|
||||
func buildKafkaSettings(fc channels.FactoryConfig) (*kafkaSettings, error) {
|
||||
var settings kafkaSettings
|
||||
err := json.Unmarshal(fc.Config.Settings, &settings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal settings: %w", err)
|
||||
}
|
||||
|
||||
if settings.Endpoint == "" {
|
||||
return nil, errors.New("could not find kafka rest proxy endpoint property in settings")
|
||||
}
|
||||
if settings.Topic == "" {
|
||||
return nil, errors.New("could not find kafka topic property in settings")
|
||||
}
|
||||
if settings.Description == "" {
|
||||
settings.Description = channels.DefaultMessageTitleEmbed
|
||||
}
|
||||
if settings.Details == "" {
|
||||
settings.Details = channels.DefaultMessageEmbed
|
||||
}
|
||||
return &settings, nil
|
||||
}
|
||||
|
||||
func KafkaFactory(fc channels.FactoryConfig) (channels.NotificationChannel, error) {
|
||||
@ -47,20 +71,10 @@ func KafkaFactory(fc channels.FactoryConfig) (channels.NotificationChannel, erro
|
||||
|
||||
// newKafkaNotifier is the constructor function for the Kafka notifier.
|
||||
func newKafkaNotifier(fc channels.FactoryConfig) (*KafkaNotifier, error) {
|
||||
settings, err := simplejson.NewJson(fc.Config.Settings)
|
||||
settings, err := buildKafkaSettings(fc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endpoint := settings.Get("kafkaRestProxy").MustString()
|
||||
if endpoint == "" {
|
||||
return nil, errors.New("could not find kafka rest proxy endpoint property in settings")
|
||||
}
|
||||
topic := settings.Get("kafkaTopic").MustString()
|
||||
if topic == "" {
|
||||
return nil, errors.New("could not find kafka topic property in settings")
|
||||
}
|
||||
description := settings.Get("description").MustString(channels.DefaultMessageTitleEmbed)
|
||||
details := settings.Get("details").MustString(channels.DefaultMessageEmbed)
|
||||
|
||||
return &KafkaNotifier{
|
||||
Base: channels.NewBase(fc.Config),
|
||||
@ -68,7 +82,7 @@ func newKafkaNotifier(fc channels.FactoryConfig) (*KafkaNotifier, error) {
|
||||
images: fc.ImageStore,
|
||||
ns: fc.NotificationService,
|
||||
tmpl: fc.Template,
|
||||
settings: kafkaSettings{Endpoint: endpoint, Topic: topic, Description: description, Details: details},
|
||||
settings: settings,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package channels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
@ -10,8 +11,6 @@ import (
|
||||
"github.com/grafana/alerting/alerting/notifier/channels"
|
||||
"github.com/prometheus/alertmanager/template"
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -25,13 +24,32 @@ type LineNotifier struct {
|
||||
log channels.Logger
|
||||
ns channels.WebhookSender
|
||||
tmpl *template.Template
|
||||
settings lineSettings
|
||||
settings *lineSettings
|
||||
}
|
||||
|
||||
type lineSettings struct {
|
||||
token string
|
||||
title string
|
||||
description string
|
||||
Token string `json:"token,omitempty" yaml:"token,omitempty"`
|
||||
Title string `json:"title,omitempty" yaml:"title,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
}
|
||||
|
||||
func buildLineSettings(fc channels.FactoryConfig) (*lineSettings, error) {
|
||||
var settings lineSettings
|
||||
err := json.Unmarshal(fc.Config.Settings, &settings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal settings: %w", err)
|
||||
}
|
||||
settings.Token = fc.DecryptFunc(context.Background(), fc.Config.SecureSettings, "token", settings.Token)
|
||||
if settings.Token == "" {
|
||||
return nil, errors.New("could not find token in settings")
|
||||
}
|
||||
if settings.Title == "" {
|
||||
settings.Title = channels.DefaultMessageTitleEmbed
|
||||
}
|
||||
if settings.Description == "" {
|
||||
settings.Description = channels.DefaultMessageEmbed
|
||||
}
|
||||
return &settings, nil
|
||||
}
|
||||
|
||||
func LineFactory(fc channels.FactoryConfig) (channels.NotificationChannel, error) {
|
||||
@ -47,23 +65,17 @@ func LineFactory(fc channels.FactoryConfig) (channels.NotificationChannel, error
|
||||
|
||||
// newLineNotifier is the constructor for the LINE notifier
|
||||
func newLineNotifier(fc channels.FactoryConfig) (*LineNotifier, error) {
|
||||
settings, err := simplejson.NewJson(fc.Config.Settings)
|
||||
settings, err := buildLineSettings(fc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
token := fc.DecryptFunc(context.Background(), fc.Config.SecureSettings, "token", settings.Get("token").MustString())
|
||||
if token == "" {
|
||||
return nil, errors.New("could not find token in settings")
|
||||
}
|
||||
title := settings.Get("title").MustString(channels.DefaultMessageTitleEmbed)
|
||||
description := settings.Get("description").MustString(channels.DefaultMessageEmbed)
|
||||
|
||||
return &LineNotifier{
|
||||
Base: channels.NewBase(fc.Config),
|
||||
log: fc.Logger,
|
||||
ns: fc.NotificationService,
|
||||
tmpl: fc.Template,
|
||||
settings: lineSettings{token: token, title: title, description: description},
|
||||
settings: settings,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -80,7 +92,7 @@ func (ln *LineNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool, e
|
||||
URL: LineNotifyURL,
|
||||
HTTPMethod: "POST",
|
||||
HTTPHeader: map[string]string{
|
||||
"Authorization": fmt.Sprintf("Bearer %s", ln.settings.token),
|
||||
"Authorization": fmt.Sprintf("Bearer %s", ln.settings.Token),
|
||||
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
||||
},
|
||||
Body: form.Encode(),
|
||||
@ -106,9 +118,9 @@ func (ln *LineNotifier) buildMessage(ctx context.Context, as ...*types.Alert) st
|
||||
|
||||
body := fmt.Sprintf(
|
||||
"%s\n%s\n\n%s",
|
||||
tmpl(ln.settings.title),
|
||||
tmpl(ln.settings.Title),
|
||||
ruleURL,
|
||||
tmpl(ln.settings.description),
|
||||
tmpl(ln.settings.Description),
|
||||
)
|
||||
if tmplErr != nil {
|
||||
ln.log.Warn("failed to template Line message", "error", tmplErr.Error())
|
||||
|
Loading…
Reference in New Issue
Block a user