mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* Allow customizable googlechat message via optional setting * Add optional message field in googlechat contact point configurator * Fix strange error message on send if template fails to fully evaluate * Elevate template evaluation failure logs to Warn level * Extract default.title template embed from all channels to shared constant
133 lines
4.0 KiB
Go
133 lines
4.0 KiB
Go
package channels
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/grafana/grafana/pkg/bus"
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/prometheus/alertmanager/template"
|
|
"github.com/prometheus/alertmanager/types"
|
|
"github.com/prometheus/common/model"
|
|
)
|
|
|
|
var (
|
|
ThreemaGwBaseURL = "https://msgapi.threema.ch/send_simple"
|
|
)
|
|
|
|
// ThreemaNotifier is responsible for sending
|
|
// alert notifications to Threema.
|
|
type ThreemaNotifier struct {
|
|
*Base
|
|
GatewayID string
|
|
RecipientID string
|
|
APISecret string
|
|
log log.Logger
|
|
tmpl *template.Template
|
|
}
|
|
|
|
// NewThreemaNotifier is the constructor for the Threema notifier
|
|
func NewThreemaNotifier(model *NotificationChannelConfig, t *template.Template, fn GetDecryptedValueFn) (*ThreemaNotifier, error) {
|
|
if model.Settings == nil {
|
|
return nil, receiverInitError{Cfg: *model, Reason: "no settings supplied"}
|
|
}
|
|
if model.SecureSettings == nil {
|
|
return nil, receiverInitError{Cfg: *model, Reason: "no secure settings supplied"}
|
|
}
|
|
gatewayID := model.Settings.Get("gateway_id").MustString()
|
|
recipientID := model.Settings.Get("recipient_id").MustString()
|
|
apiSecret := fn(context.Background(), model.SecureSettings, "api_secret", model.Settings.Get("api_secret").MustString())
|
|
|
|
// Validation
|
|
if gatewayID == "" {
|
|
return nil, receiverInitError{Cfg: *model, Reason: "could not find Threema Gateway ID in settings"}
|
|
}
|
|
if !strings.HasPrefix(gatewayID, "*") {
|
|
return nil, receiverInitError{Cfg: *model, Reason: "invalid Threema Gateway ID: Must start with a *"}
|
|
}
|
|
if len(gatewayID) != 8 {
|
|
return nil, receiverInitError{Cfg: *model, Reason: "invalid Threema Gateway ID: Must be 8 characters long"}
|
|
}
|
|
if recipientID == "" {
|
|
return nil, receiverInitError{Cfg: *model, Reason: "could not find Threema Recipient ID in settings"}
|
|
}
|
|
if len(recipientID) != 8 {
|
|
return nil, receiverInitError{Cfg: *model, Reason: "invalid Threema Recipient ID: Must be 8 characters long"}
|
|
}
|
|
if apiSecret == "" {
|
|
return nil, receiverInitError{Cfg: *model, Reason: "could not find Threema API secret in settings"}
|
|
}
|
|
|
|
return &ThreemaNotifier{
|
|
Base: NewBase(&models.AlertNotification{
|
|
Uid: model.UID,
|
|
Name: model.Name,
|
|
Type: model.Type,
|
|
DisableResolveMessage: model.DisableResolveMessage,
|
|
Settings: model.Settings,
|
|
}),
|
|
GatewayID: gatewayID,
|
|
RecipientID: recipientID,
|
|
APISecret: apiSecret,
|
|
log: log.New("alerting.notifier.threema"),
|
|
tmpl: t,
|
|
}, nil
|
|
}
|
|
|
|
// Notify send an alert notification to Threema
|
|
func (tn *ThreemaNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
|
|
tn.log.Debug("Sending threema alert notification", "from", tn.GatewayID, "to", tn.RecipientID)
|
|
|
|
var tmplErr error
|
|
tmpl, _ := TmplText(ctx, tn.tmpl, as, tn.log, &tmplErr)
|
|
|
|
// Set up basic API request data
|
|
data := url.Values{}
|
|
data.Set("from", tn.GatewayID)
|
|
data.Set("to", tn.RecipientID)
|
|
data.Set("secret", tn.APISecret)
|
|
|
|
// Determine emoji
|
|
stateEmoji := "\u26A0\uFE0F " // Warning sign
|
|
alerts := types.Alerts(as...)
|
|
if alerts.Status() == model.AlertResolved {
|
|
stateEmoji = "\u2705 " // Check Mark Button
|
|
}
|
|
|
|
// Build message
|
|
message := fmt.Sprintf("%s%s\n\n*Message:*\n%s\n*URL:* %s\n",
|
|
stateEmoji,
|
|
tmpl(DefaultMessageTitleEmbed),
|
|
tmpl(`{{ template "default.message" . }}`),
|
|
path.Join(tn.tmpl.ExternalURL.String(), "/alerting/list"),
|
|
)
|
|
data.Set("text", message)
|
|
|
|
if tmplErr != nil {
|
|
tn.log.Warn("failed to template Threema message", "err", tmplErr.Error())
|
|
}
|
|
|
|
cmd := &models.SendWebhookSync{
|
|
Url: ThreemaGwBaseURL,
|
|
Body: data.Encode(),
|
|
HttpMethod: "POST",
|
|
HttpHeader: map[string]string{
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
},
|
|
}
|
|
if err := bus.Dispatch(ctx, cmd); err != nil {
|
|
tn.log.Error("Failed to send threema notification", "error", err, "webhook", tn.Name)
|
|
return false, err
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
func (tn *ThreemaNotifier) SendResolved() bool {
|
|
return !tn.GetDisableResolveMessage()
|
|
}
|