Files
grafana/pkg/services/ngalert/notifier/channels/sensugo.go
Tania B 5652bde447 Encryption: Use secrets service (#40251)
* Use secrets service in pluginproxy

* Use secrets service in pluginxontext

* Use secrets service in pluginsettings

* Use secrets service in provisioning

* Use secrets service in authinfoservice

* Use secrets service in api

* Use secrets service in sqlstore

* Use secrets service in dashboardshapshots

* Use secrets service in tsdb

* Use secrets service in datasources

* Use secrets service in alerting

* Use secrets service in ngalert

* Break cyclic dependancy

* Refactor service

* Break cyclic dependancy

* Add FakeSecretsStore

* Setup Secrets Service in sqlstore

* Fix

* Continue secrets service refactoring

* Fix cyclic dependancy in sqlstore tests

* Fix secrets service references

* Fix linter errors

* Add fake secrets service for tests

* Refactor SetupTestSecretsService

* Update setting up secret service in tests

* Fix missing secrets service in multiorg_alertmanager_test

* Use fake db in tests and sort imports

* Use fake db in datasources tests

* Fix more tests

* Fix linter issues

* Attempt to fix plugin proxy tests

* Pass secrets service to getPluginProxiedRequest in pluginproxy tests

* Fix pluginproxy tests

* Revert using secrets service in alerting and provisioning

* Update decryptFn in alerting migration

* Rename defaultProvider to currentProvider

* Use fake secrets service in alert channels tests

* Refactor secrets service test helper

* Update setting up secrets service in tests

* Revert alerting changes in api

* Add comments

* Remove secrets service from background services

* Convert global encryption functions into vars

* Revert "Convert global encryption functions into vars"

This reverts commit 498eb19859.

* Add feature toggle for envelope encryption

* Rename toggle

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
Co-authored-by: Joan López de la Franca Beltran <joanjan14@gmail.com>
2021-11-04 18:47:21 +02:00

158 lines
4.2 KiB
Go

package channels
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"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"
)
type SensuGoNotifier struct {
*Base
log log.Logger
tmpl *template.Template
URL string
Entity string
Check string
Namespace string
Handler string
APIKey string
Message string
}
// NewSensuGoNotifier is the constructor for the SensuGo notifier
func NewSensuGoNotifier(model *NotificationChannelConfig, t *template.Template, fn GetDecryptedValueFn) (*SensuGoNotifier, error) {
if model.Settings == nil {
return nil, receiverInitError{Cfg: *model, Reason: "no settings supplied"}
}
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, receiverInitError{Cfg: *model, Reason: "could not find URL property in settings"}
}
apikey := fn(context.Background(), model.SecureSettings, "apikey", model.Settings.Get("apikey").MustString())
if apikey == "" {
return nil, receiverInitError{Cfg: *model, Reason: "could not find the API key property in settings"}
}
return &SensuGoNotifier{
Base: NewBase(&models.AlertNotification{
Uid: model.UID,
Name: model.Name,
Type: model.Type,
DisableResolveMessage: model.DisableResolveMessage,
Settings: model.Settings,
SecureSettings: model.SecureSettings,
}),
URL: url,
Entity: model.Settings.Get("entity").MustString(),
Check: model.Settings.Get("check").MustString(),
Namespace: model.Settings.Get("namespace").MustString(),
Handler: model.Settings.Get("handler").MustString(),
APIKey: apikey,
Message: model.Settings.Get("message").MustString(`{{ template "default.message" .}}`),
log: log.New("alerting.notifier.sensugo"),
tmpl: t,
}, nil
}
// Notify sends an alert notification to Sensu Go
func (sn *SensuGoNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
sn.log.Debug("Sending Sensu Go result")
var tmplErr error
tmpl, _ := TmplText(ctx, sn.tmpl, as, sn.log, &tmplErr)
// Sensu Go alerts require an entity and a check. We set it to the user-specified
// value (optional), else we fallback and use the grafana rule anme and ruleID.
entity := tmpl(sn.Entity)
if entity == "" {
entity = "default"
}
check := tmpl(sn.Check)
if check == "" {
check = "default"
}
alerts := types.Alerts(as...)
status := 0
if alerts.Status() == model.AlertFiring {
// TODO figure out about NoData old state (we used to send status 1 in that case)
status = 2
}
namespace := tmpl(sn.Namespace)
if namespace == "" {
namespace = "default"
}
var handlers []string
if sn.Handler != "" {
handlers = []string{tmpl(sn.Handler)}
}
ruleURL := joinUrlPath(sn.tmpl.ExternalURL.String(), "/alerting/list", sn.log)
bodyMsgType := map[string]interface{}{
"entity": map[string]interface{}{
"metadata": map[string]interface{}{
"name": entity,
"namespace": namespace,
},
},
"check": map[string]interface{}{
"metadata": map[string]interface{}{
"name": check,
"labels": map[string]string{
"ruleURL": ruleURL,
},
},
"output": tmpl(sn.Message),
"issued": time.Now().Unix(),
"interval": 86400,
"status": status,
"handlers": handlers,
},
"ruleUrl": ruleURL,
}
if tmplErr != nil {
sn.log.Debug("failed to template sensugo message", "err", tmplErr.Error())
}
body, err := json.Marshal(bodyMsgType)
if err != nil {
return false, err
}
cmd := &models.SendWebhookSync{
Url: fmt.Sprintf("%s/api/core/v2/namespaces/%s/events", strings.TrimSuffix(sn.URL, "/"), namespace),
Body: string(body),
HttpMethod: "POST",
HttpHeader: map[string]string{
"Content-Type": "application/json",
"Authorization": fmt.Sprintf("Key %s", sn.APIKey),
},
}
if err := bus.DispatchCtx(ctx, cmd); err != nil {
sn.log.Error("Failed to send Sensu Go event", "error", err, "sensugo", sn.Name)
return false, err
}
return true, nil
}
func (sn *SensuGoNotifier) SendResolved() bool {
return !sn.GetDisableResolveMessage()
}