Alerting: replace usage of simplejson to json.RawMessage in NotificationChannelConfig (#60423)

* introduce alias for json.RawMessage with name RawMessage. This is needed to keep raw JSON and implement a marshaler for YAML, which does not seem to be used but there are tests that fail.
* replace usage of simplejson with RawMessage in NotificationChannelConfig
* remove usage of simplejson in tests
* change migration code to convert simplejson to raw message
pull/60489/head
Yuri Tseretyan 3 years ago committed by GitHub
parent 09bb4423d2
commit 9ad45aedcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      pkg/services/ngalert/api/api_alertmanager_guards.go
  2. 18
      pkg/services/ngalert/api/api_alertmanager_guards_test.go
  3. 47
      pkg/services/ngalert/api/tooling/definitions/alertmanager.go
  4. 46
      pkg/services/ngalert/api/tooling/definitions/alertmanager_test.go
  5. 6
      pkg/services/ngalert/api/tooling/definitions/provisioning_contactpoints.go
  6. 2
      pkg/services/ngalert/notifier/alertmanager.go
  7. 12
      pkg/services/ngalert/notifier/channels/alertmanager.go
  8. 7
      pkg/services/ngalert/notifier/channels/alertmanager_test.go
  9. 14
      pkg/services/ngalert/notifier/channels/dingding.go
  10. 7
      pkg/services/ngalert/notifier/channels/dingding_test.go
  11. 14
      pkg/services/ngalert/notifier/channels/discord.go
  12. 5
      pkg/services/ngalert/notifier/channels/discord_test.go
  13. 13
      pkg/services/ngalert/notifier/channels/email.go
  14. 28
      pkg/services/ngalert/notifier/channels/email_test.go
  15. 11
      pkg/services/ngalert/notifier/channels/googlechat.go
  16. 6
      pkg/services/ngalert/notifier/channels/googlechat_test.go
  17. 12
      pkg/services/ngalert/notifier/channels/kafka.go
  18. 8
      pkg/services/ngalert/notifier/channels/kafka_test.go
  19. 12
      pkg/services/ngalert/notifier/channels/line.go
  20. 5
      pkg/services/ngalert/notifier/channels/line_test.go
  21. 5
      pkg/services/ngalert/notifier/channels/opsgenie_test.go
  22. 4
      pkg/services/ngalert/notifier/channels/pagerduty_test.go
  23. 5
      pkg/services/ngalert/notifier/channels/pushover_test.go
  24. 4
      pkg/services/ngalert/notifier/channels/sensugo_test.go
  25. 7
      pkg/services/ngalert/notifier/channels/slack_test.go
  26. 5
      pkg/services/ngalert/notifier/channels/teams_test.go
  27. 4
      pkg/services/ngalert/notifier/channels/telegram_test.go
  28. 5
      pkg/services/ngalert/notifier/channels/threema_test.go
  29. 14
      pkg/services/ngalert/notifier/channels/util.go
  30. 11
      pkg/services/ngalert/notifier/channels/victorops_test.go
  31. 5
      pkg/services/ngalert/notifier/channels/webex_test.go
  32. 4
      pkg/services/ngalert/notifier/channels/webhook_test.go
  33. 17
      pkg/services/ngalert/notifier/channels/wecom_test.go
  34. 31
      pkg/services/ngalert/provisioning/contactpoints.go
  35. 7
      pkg/services/sqlstore/migrations/ualert/ualert.go

@ -1,15 +1,17 @@
package api package api
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-cmp/cmp/cmpopts"
amConfig "github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/pkg/labels"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/util/cmputil" "github.com/grafana/grafana/pkg/util/cmputil"
amConfig "github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/pkg/labels"
) )
func (srv AlertmanagerSrv) provenanceGuard(currentConfig apimodels.GettableUserConfig, newConfig apimodels.PostableUserConfig) error { func (srv AlertmanagerSrv) provenanceGuard(currentConfig apimodels.GettableUserConfig, newConfig apimodels.PostableUserConfig) error {
@ -96,11 +98,16 @@ func checkContactPoints(currReceivers []*apimodels.GettableApiReceiver, newRecei
return editErr return editErr
} }
} }
existingSettings, err := contactPoint.Settings.Map() existingSettings := map[string]interface{}{}
err := json.Unmarshal(contactPoint.Settings, &existingSettings)
if err != nil {
return err
}
newSettings := map[string]interface{}{}
err = json.Unmarshal(contactPoint.Settings, &newSettings)
if err != nil { if err != nil {
return err return err
} }
newSettings, err := postedContactPoint.Settings.Map()
if err != nil { if err != nil {
return err return err
} }

@ -3,14 +3,14 @@ package api
import ( import (
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models"
amConfig "github.com/prometheus/alertmanager/config" amConfig "github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/pkg/labels" "github.com/prometheus/alertmanager/pkg/labels"
"github.com/prometheus/alertmanager/timeinterval" "github.com/prometheus/alertmanager/timeinterval"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models"
) )
func TestCheckRoute(t *testing.T) { func TestCheckRoute(t *testing.T) {
@ -319,9 +319,9 @@ func defaultGettableReceiver(t *testing.T, uid string, provenance models.Provena
SecureFields: map[string]bool{ SecureFields: map[string]bool{
"url": true, "url": true,
}, },
Settings: simplejson.NewFromAny(map[string]interface{}{ Settings: definitions.RawMessage(`{
"hello": "world", "hello": "world"
}), }`),
}, },
}, },
}, },
@ -338,9 +338,9 @@ func defaultPostableReceiver(t *testing.T, uid string) *definitions.PostableApiR
Name: "yeah", Name: "yeah",
Type: "slack", Type: "slack",
DisableResolveMessage: true, DisableResolveMessage: true,
Settings: simplejson.NewFromAny(map[string]interface{}{ Settings: definitions.RawMessage(`{
"hello": "world", "hello": "world"
}), }`),
}, },
}, },
}, },

@ -17,7 +17,6 @@ import (
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
@ -964,12 +963,54 @@ func AllReceivers(route *config.Route) (res []string) {
return res return res
} }
type RawMessage json.RawMessage // This type alias adds YAML marshaling to the json.RawMessage.
// MarshalJSON returns m as the JSON encoding of m.
func (r RawMessage) MarshalJSON() ([]byte, error) {
return json.Marshal(json.RawMessage(r))
}
func (r *RawMessage) UnmarshalJSON(data []byte) error {
var raw json.RawMessage
err := json.Unmarshal(data, &raw)
if err != nil {
return err
}
*r = RawMessage(raw)
return nil
}
func (r *RawMessage) UnmarshalYAML(unmarshal func(interface{}) error) error {
var data interface{}
if err := unmarshal(&data); err != nil {
return err
}
bytes, err := json.Marshal(data)
if err != nil {
return err
}
*r = bytes
return nil
}
func (r RawMessage) MarshalYAML() (interface{}, error) {
if r == nil {
return nil, nil
}
var d interface{}
err := json.Unmarshal(r, &d)
if err != nil {
return nil, err
}
return d, nil
}
type GettableGrafanaReceiver struct { type GettableGrafanaReceiver struct {
UID string `json:"uid"` UID string `json:"uid"`
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`
DisableResolveMessage bool `json:"disableResolveMessage"` DisableResolveMessage bool `json:"disableResolveMessage"`
Settings *simplejson.Json `json:"settings"` Settings RawMessage `json:"settings,omitempty"`
SecureFields map[string]bool `json:"secureFields"` SecureFields map[string]bool `json:"secureFields"`
Provenance models.Provenance `json:"provenance,omitempty"` Provenance models.Provenance `json:"provenance,omitempty"`
} }
@ -979,7 +1020,7 @@ type PostableGrafanaReceiver struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`
DisableResolveMessage bool `json:"disableResolveMessage"` DisableResolveMessage bool `json:"disableResolveMessage"`
Settings *simplejson.Json `json:"settings"` Settings RawMessage `json:"settings,omitempty"`
SecureSettings map[string]string `json:"secureSettings"` SecureSettings map[string]string `json:"secureSettings"`
} }

@ -1040,3 +1040,49 @@ func Test_Marshaling_Validation(t *testing.T) {
expected := []model.LabelName{"alertname"} expected := []model.LabelName{"alertname"}
require.Equal(t, expected, tmp.AlertmanagerConfig.Config.Route.GroupBy) require.Equal(t, expected, tmp.AlertmanagerConfig.Config.Route.GroupBy)
} }
func Test_RawMessageMarshaling(t *testing.T) {
type Data struct {
Field RawMessage `json:"field" yaml:"field"`
}
t.Run("should unmarshal nil", func(t *testing.T) {
v := Data{
Field: nil,
}
data, err := json.Marshal(v)
require.NoError(t, err)
assert.JSONEq(t, `{ "field": null }`, string(data))
var n Data
require.NoError(t, json.Unmarshal(data, &n))
assert.Equal(t, RawMessage("null"), n.Field)
data, err = yaml.Marshal(&v)
require.NoError(t, err)
assert.Equal(t, "field: null\n", string(data))
require.NoError(t, yaml.Unmarshal(data, &n))
assert.Nil(t, n.Field)
})
t.Run("should unmarshal value", func(t *testing.T) {
v := Data{
Field: RawMessage(`{ "data": "test"}`),
}
data, err := json.Marshal(v)
require.NoError(t, err)
assert.JSONEq(t, `{"field":{"data":"test"}}`, string(data))
var n Data
require.NoError(t, json.Unmarshal(data, &n))
assert.Equal(t, RawMessage(`{"data":"test"}`), n.Field)
data, err = yaml.Marshal(&v)
require.NoError(t, err)
assert.Equal(t, "field:\n data: test\n", string(data))
require.NoError(t, yaml.Unmarshal(data, &n))
assert.Equal(t, RawMessage(`{"data":"test"}`), n.Field)
})
}

@ -108,8 +108,12 @@ func (e *EmbeddedContactPoint) Valid(decryptFunc channels.GetDecryptedValueFn) e
if !exists { if !exists {
return fmt.Errorf("unknown type '%s'", e.Type) return fmt.Errorf("unknown type '%s'", e.Type)
} }
jsonBytes, err := e.Settings.MarshalJSON()
if err != nil {
return err
}
cfg, _ := channels.NewFactoryConfig(&channels.NotificationChannelConfig{ cfg, _ := channels.NewFactoryConfig(&channels.NotificationChannelConfig{
Settings: e.Settings, Settings: jsonBytes,
Type: e.Type, Type: e.Type,
}, nil, decryptFunc, nil, nil, func(ctx ...interface{}) channels.Logger { }, nil, decryptFunc, nil, nil, func(ctx ...interface{}) channels.Logger {
return &channels.FakeLogger{} return &channels.FakeLogger{}

@ -510,7 +510,7 @@ func (am *Alertmanager) buildReceiverIntegration(r *apimodels.PostableGrafanaRec
Name: r.Name, Name: r.Name,
Type: r.Type, Type: r.Type,
DisableResolveMessage: r.DisableResolveMessage, DisableResolveMessage: r.DisableResolveMessage,
Settings: r.Settings, Settings: json.RawMessage(r.Settings),
SecureSettings: secureSettings, SecureSettings: secureSettings,
} }
) )

@ -11,6 +11,8 @@ import (
"github.com/prometheus/alertmanager/template" "github.com/prometheus/alertmanager/template"
"github.com/prometheus/alertmanager/types" "github.com/prometheus/alertmanager/types"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/grafana/grafana/pkg/components/simplejson"
) )
// GetDecryptedValueFn is a function that returns the decrypted value of // GetDecryptedValueFn is a function that returns the decrypted value of
@ -25,7 +27,11 @@ type AlertmanagerConfig struct {
} }
func NewAlertmanagerConfig(config *NotificationChannelConfig, fn GetDecryptedValueFn) (*AlertmanagerConfig, error) { func NewAlertmanagerConfig(config *NotificationChannelConfig, fn GetDecryptedValueFn) (*AlertmanagerConfig, error) {
urlStr := config.Settings.Get("url").MustString() simpleConfig, err := simplejson.NewJson(config.Settings)
if err != nil {
return nil, err
}
urlStr := simpleConfig.Get("url").MustString()
if urlStr == "" { if urlStr == "" {
return nil, errors.New("could not find url property in settings") return nil, errors.New("could not find url property in settings")
} }
@ -48,8 +54,8 @@ func NewAlertmanagerConfig(config *NotificationChannelConfig, fn GetDecryptedVal
return &AlertmanagerConfig{ return &AlertmanagerConfig{
NotificationChannelConfig: config, NotificationChannelConfig: config,
URLs: urls, URLs: urls,
BasicAuthUser: config.Settings.Get("basicAuthUser").MustString(), BasicAuthUser: simpleConfig.Get("basicAuthUser").MustString(),
BasicAuthPassword: fn(context.Background(), config.SecureSettings, "basicAuthPassword", config.Settings.Get("basicAuthPassword").MustString()), BasicAuthPassword: fn(context.Background(), config.SecureSettings, "basicAuthPassword", simpleConfig.Get("basicAuthPassword").MustString()),
}, nil }, nil
} }

@ -7,7 +7,6 @@ import (
"net/url" "net/url"
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
@ -46,14 +45,12 @@ func TestNewAlertmanagerNotifier(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings))
require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)
m := &NotificationChannelConfig{ m := &NotificationChannelConfig{
Name: c.receiverName, Name: c.receiverName,
Type: "prometheus-alertmanager", Type: "prometheus-alertmanager",
Settings: settingsJSON, Settings: json.RawMessage(c.settings),
SecureSettings: secureSettings, SecureSettings: secureSettings,
} }
@ -143,7 +140,7 @@ func TestAlertmanagerNotifier_Notify(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err) require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)

@ -9,6 +9,8 @@ import (
"github.com/prometheus/alertmanager/template" "github.com/prometheus/alertmanager/template"
"github.com/prometheus/alertmanager/types" "github.com/prometheus/alertmanager/types"
"github.com/grafana/grafana/pkg/components/simplejson"
) )
const defaultDingdingMsgType = "link" const defaultDingdingMsgType = "link"
@ -21,15 +23,19 @@ type dingDingSettings struct {
} }
func buildDingDingSettings(fc FactoryConfig) (*dingDingSettings, error) { func buildDingDingSettings(fc FactoryConfig) (*dingDingSettings, error) {
URL := fc.Config.Settings.Get("url").MustString() settings, err := simplejson.NewJson(fc.Config.Settings)
if err != nil {
return nil, err
}
URL := settings.Get("url").MustString()
if URL == "" { if URL == "" {
return nil, errors.New("could not find url property in settings") return nil, errors.New("could not find url property in settings")
} }
return &dingDingSettings{ return &dingDingSettings{
URL: URL, URL: URL,
MessageType: fc.Config.Settings.Get("msgType").MustString(defaultDingdingMsgType), MessageType: settings.Get("msgType").MustString(defaultDingdingMsgType),
Title: fc.Config.Settings.Get("title").MustString(DefaultMessageTitleEmbed), Title: settings.Get("title").MustString(DefaultMessageTitleEmbed),
Message: fc.Config.Settings.Get("message").MustString(DefaultMessageEmbed), Message: settings.Get("message").MustString(DefaultMessageEmbed),
}, nil }, nil
} }

@ -10,8 +10,6 @@ import (
"github.com/prometheus/alertmanager/types" "github.com/prometheus/alertmanager/types"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
) )
func TestDingdingNotifier(t *testing.T) { func TestDingdingNotifier(t *testing.T) {
@ -166,15 +164,12 @@ func TestDingdingNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings))
require.NoError(t, err)
webhookSender := mockNotificationService() webhookSender := mockNotificationService()
fc := FactoryConfig{ fc := FactoryConfig{
Config: &NotificationChannelConfig{ Config: &NotificationChannelConfig{
Name: "dingding_testing", Name: "dingding_testing",
Type: "dingding", Type: "dingding",
Settings: settingsJSON, Settings: json.RawMessage(c.settings),
}, },
// TODO: allow changing the associated values for different tests. // TODO: allow changing the associated values for different tests.
NotificationService: webhookSender, NotificationService: webhookSender,

@ -59,7 +59,11 @@ func DiscordFactory(fc FactoryConfig) (NotificationChannel, error) {
} }
func newDiscordNotifier(fc FactoryConfig) (*DiscordNotifier, error) { func newDiscordNotifier(fc FactoryConfig) (*DiscordNotifier, error) {
dUrl := fc.Config.Settings.Get("url").MustString() settings, err := simplejson.NewJson(fc.Config.Settings)
if err != nil {
return nil, err
}
dUrl := settings.Get("url").MustString()
if dUrl == "" { if dUrl == "" {
return nil, errors.New("could not find webhook url property in settings") return nil, errors.New("could not find webhook url property in settings")
} }
@ -71,11 +75,11 @@ func newDiscordNotifier(fc FactoryConfig) (*DiscordNotifier, error) {
images: fc.ImageStore, images: fc.ImageStore,
tmpl: fc.Template, tmpl: fc.Template,
settings: discordSettings{ settings: discordSettings{
Title: fc.Config.Settings.Get("title").MustString(DefaultMessageTitleEmbed), Title: settings.Get("title").MustString(DefaultMessageTitleEmbed),
Content: fc.Config.Settings.Get("message").MustString(DefaultMessageEmbed), Content: settings.Get("message").MustString(DefaultMessageEmbed),
AvatarURL: fc.Config.Settings.Get("avatar_url").MustString(), AvatarURL: settings.Get("avatar_url").MustString(),
WebhookURL: dUrl, WebhookURL: dUrl,
UseDiscordUsername: fc.Config.Settings.Get("use_discord_username").MustBool(false), UseDiscordUsername: settings.Get("use_discord_username").MustBool(false),
}, },
}, nil }, nil
} }

@ -11,7 +11,6 @@ import (
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -287,8 +286,6 @@ func TestDiscordNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJson, err := simplejson.NewJson([]byte(c.settings))
require.NoError(t, err)
webhookSender := mockNotificationService() webhookSender := mockNotificationService()
imageStore := &UnavailableImageStore{} imageStore := &UnavailableImageStore{}
@ -296,7 +293,7 @@ func TestDiscordNotifier(t *testing.T) {
Config: &NotificationChannelConfig{ Config: &NotificationChannelConfig{
Name: "discord_testing", Name: "discord_testing",
Type: "discord", Type: "discord",
Settings: settingsJson, Settings: json.RawMessage(c.settings),
}, },
ImageStore: imageStore, ImageStore: imageStore,
// TODO: allow changing the associated values for different tests. // TODO: allow changing the associated values for different tests.

@ -11,6 +11,7 @@ import (
"github.com/prometheus/alertmanager/template" "github.com/prometheus/alertmanager/template"
"github.com/prometheus/alertmanager/types" "github.com/prometheus/alertmanager/types"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@ -48,7 +49,11 @@ func EmailFactory(fc FactoryConfig) (NotificationChannel, error) {
} }
func NewEmailConfig(config *NotificationChannelConfig) (*EmailConfig, error) { func NewEmailConfig(config *NotificationChannelConfig) (*EmailConfig, error) {
addressesString := config.Settings.Get("addresses").MustString() settings, err := simplejson.NewJson(config.Settings)
if err != nil {
return nil, err
}
addressesString := settings.Get("addresses").MustString()
if addressesString == "" { if addressesString == "" {
return nil, errors.New("could not find addresses in settings") return nil, errors.New("could not find addresses in settings")
} }
@ -56,9 +61,9 @@ func NewEmailConfig(config *NotificationChannelConfig) (*EmailConfig, error) {
addresses := util.SplitEmails(addressesString) addresses := util.SplitEmails(addressesString)
return &EmailConfig{ return &EmailConfig{
NotificationChannelConfig: config, NotificationChannelConfig: config,
SingleEmail: config.Settings.Get("singleEmail").MustBool(false), SingleEmail: settings.Get("singleEmail").MustBool(false),
Message: config.Settings.Get("message").MustString(), Message: settings.Get("message").MustString(),
Subject: config.Settings.Get("subject").MustString(DefaultMessageTitleEmbed), Subject: settings.Get("subject").MustString(DefaultMessageTitleEmbed),
Addresses: addresses, Addresses: addresses,
}, nil }, nil
} }

@ -2,6 +2,7 @@ package channels
import ( import (
"context" "context"
"encoding/json"
"net/url" "net/url"
"testing" "testing"
@ -10,7 +11,6 @@ import (
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/notifications"
) )
@ -22,9 +22,8 @@ func TestEmailNotifier(t *testing.T) {
tmpl.ExternalURL = externalURL tmpl.ExternalURL = externalURL
t.Run("empty settings should return error", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) {
json := `{ }` jsonData := `{ }`
settingsJSON := json.RawMessage(jsonData)
settingsJSON, _ := simplejson.NewJson([]byte(json))
model := &NotificationChannelConfig{ model := &NotificationChannelConfig{
Name: "ops", Name: "ops",
Type: "email", Type: "email",
@ -36,18 +35,16 @@ func TestEmailNotifier(t *testing.T) {
}) })
t.Run("with the correct settings it should not fail and produce the expected command", func(t *testing.T) { t.Run("with the correct settings it should not fail and produce the expected command", func(t *testing.T) {
json := `{ jsonData := `{
"addresses": "someops@example.com;somedev@example.com", "addresses": "someops@example.com;somedev@example.com",
"message": "{{ template \"default.title\" . }}" "message": "{{ template \"default.title\" . }}"
}` }`
settingsJSON, err := simplejson.NewJson([]byte(json))
require.NoError(t, err)
emailSender := mockNotificationService() emailSender := mockNotificationService()
cfg, err := NewEmailConfig(&NotificationChannelConfig{ cfg, err := NewEmailConfig(&NotificationChannelConfig{
Name: "ops", Name: "ops",
Type: "email", Type: "email",
Settings: settingsJSON, Settings: json.RawMessage(jsonData),
}) })
require.NoError(t, err) require.NoError(t, err)
emailNotifier := NewEmailNotifier(cfg, &FakeLogger{}, emailSender, &UnavailableImageStore{}, tmpl) emailNotifier := NewEmailNotifier(cfg, &FakeLogger{}, emailSender, &UnavailableImageStore{}, tmpl)
@ -270,24 +267,23 @@ func TestEmailNotifierIntegration(t *testing.T) {
func createSut(t *testing.T, messageTmpl string, subjectTmpl string, emailTmpl *template.Template, ns *emailSender) *EmailNotifier { func createSut(t *testing.T, messageTmpl string, subjectTmpl string, emailTmpl *template.Template, ns *emailSender) *EmailNotifier {
t.Helper() t.Helper()
json := `{ jsonData := map[string]interface{}{
"addresses": "someops@example.com;somedev@example.com", "addresses": "someops@example.com;somedev@example.com",
"singleEmail": true "singleEmail": true,
}` }
settingsJSON, err := simplejson.NewJson([]byte(json))
if messageTmpl != "" { if messageTmpl != "" {
settingsJSON.Set("message", messageTmpl) jsonData["message"] = messageTmpl
} }
if subjectTmpl != "" { if subjectTmpl != "" {
settingsJSON.Set("subject", subjectTmpl) jsonData["subject"] = subjectTmpl
} }
bytes, err := json.Marshal(jsonData)
require.NoError(t, err) require.NoError(t, err)
cfg, err := NewEmailConfig(&NotificationChannelConfig{ cfg, err := NewEmailConfig(&NotificationChannelConfig{
Name: "ops", Name: "ops",
Type: "email", Type: "email",
Settings: settingsJSON, Settings: bytes,
}) })
require.NoError(t, err) require.NoError(t, err)
emailNotifier := NewEmailNotifier(cfg, &FakeLogger{}, ns, &UnavailableImageStore{}, emailTmpl) emailNotifier := NewEmailNotifier(cfg, &FakeLogger{}, ns, &UnavailableImageStore{}, emailTmpl)

@ -11,6 +11,7 @@ import (
"github.com/prometheus/alertmanager/template" "github.com/prometheus/alertmanager/template"
"github.com/prometheus/alertmanager/types" "github.com/prometheus/alertmanager/types"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -49,7 +50,11 @@ func newGoogleChatNotifier(fc FactoryConfig) (*GoogleChatNotifier, error) {
return nil, fmt.Errorf("failed to unmarshal settings: %w", err) return nil, fmt.Errorf("failed to unmarshal settings: %w", err)
} }
URL := fc.Config.Settings.Get("url").MustString() rawsettings, err := simplejson.NewJson(fc.Config.Settings)
if err != nil {
return nil, err
}
URL := rawsettings.Get("url").MustString()
if URL == "" { if URL == "" {
return nil, errors.New("could not find url property in settings") return nil, errors.New("could not find url property in settings")
} }
@ -62,8 +67,8 @@ func newGoogleChatNotifier(fc FactoryConfig) (*GoogleChatNotifier, error) {
tmpl: fc.Template, tmpl: fc.Template,
settings: googleChatSettings{ settings: googleChatSettings{
URL: URL, URL: URL,
Title: fc.Config.Settings.Get("title").MustString(DefaultMessageTitleEmbed), Title: rawsettings.Get("title").MustString(DefaultMessageTitleEmbed),
Content: fc.Config.Settings.Get("message").MustString(DefaultMessageEmbed), Content: rawsettings.Get("message").MustString(DefaultMessageEmbed),
}, },
}, nil }, nil
} }

@ -12,7 +12,6 @@ import (
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -462,9 +461,6 @@ func TestGoogleChatNotifier(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
tmpl.ExternalURL = externalURL tmpl.ExternalURL = externalURL
settingsJSON, err := simplejson.NewJson([]byte(c.settings))
require.NoError(t, err)
webhookSender := mockNotificationService() webhookSender := mockNotificationService()
imageStore := &UnavailableImageStore{} imageStore := &UnavailableImageStore{}
@ -472,7 +468,7 @@ func TestGoogleChatNotifier(t *testing.T) {
Config: &NotificationChannelConfig{ Config: &NotificationChannelConfig{
Name: "googlechat_testing", Name: "googlechat_testing",
Type: "googlechat", Type: "googlechat",
Settings: settingsJSON, Settings: json.RawMessage(c.settings),
}, },
ImageStore: imageStore, ImageStore: imageStore,
NotificationService: webhookSender, NotificationService: webhookSender,

@ -45,16 +45,20 @@ func KafkaFactory(fc FactoryConfig) (NotificationChannel, error) {
// newKafkaNotifier is the constructor function for the Kafka notifier. // newKafkaNotifier is the constructor function for the Kafka notifier.
func newKafkaNotifier(fc FactoryConfig) (*KafkaNotifier, error) { func newKafkaNotifier(fc FactoryConfig) (*KafkaNotifier, error) {
endpoint := fc.Config.Settings.Get("kafkaRestProxy").MustString() settings, err := simplejson.NewJson(fc.Config.Settings)
if err != nil {
return nil, err
}
endpoint := settings.Get("kafkaRestProxy").MustString()
if endpoint == "" { if endpoint == "" {
return nil, errors.New("could not find kafka rest proxy endpoint property in settings") return nil, errors.New("could not find kafka rest proxy endpoint property in settings")
} }
topic := fc.Config.Settings.Get("kafkaTopic").MustString() topic := settings.Get("kafkaTopic").MustString()
if topic == "" { if topic == "" {
return nil, errors.New("could not find kafka topic property in settings") return nil, errors.New("could not find kafka topic property in settings")
} }
description := fc.Config.Settings.Get("description").MustString(DefaultMessageTitleEmbed) description := settings.Get("description").MustString(DefaultMessageTitleEmbed)
details := fc.Config.Settings.Get("details").MustString(DefaultMessageEmbed) details := settings.Get("details").MustString(DefaultMessageEmbed)
return &KafkaNotifier{ return &KafkaNotifier{
Base: NewBase(fc.Config), Base: NewBase(fc.Config),

@ -2,6 +2,7 @@ package channels
import ( import (
"context" "context"
"encoding/json"
"net/url" "net/url"
"testing" "testing"
@ -9,8 +10,6 @@ import (
"github.com/prometheus/alertmanager/types" "github.com/prometheus/alertmanager/types"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
) )
func TestKafkaNotifier(t *testing.T) { func TestKafkaNotifier(t *testing.T) {
@ -112,16 +111,13 @@ func TestKafkaNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings))
require.NoError(t, err)
webhookSender := mockNotificationService() webhookSender := mockNotificationService()
fc := FactoryConfig{ fc := FactoryConfig{
Config: &NotificationChannelConfig{ Config: &NotificationChannelConfig{
Name: "kafka_testing", Name: "kafka_testing",
Type: "kafka", Type: "kafka",
Settings: settingsJSON, Settings: json.RawMessage(c.settings),
}, },
ImageStore: images, ImageStore: images,
// TODO: allow changing the associated values for different tests. // TODO: allow changing the associated values for different tests.

@ -9,6 +9,8 @@ import (
"github.com/prometheus/alertmanager/template" "github.com/prometheus/alertmanager/template"
"github.com/prometheus/alertmanager/types" "github.com/prometheus/alertmanager/types"
"github.com/grafana/grafana/pkg/components/simplejson"
) )
var ( var (
@ -44,12 +46,16 @@ func LineFactory(fc FactoryConfig) (NotificationChannel, error) {
// newLineNotifier is the constructor for the LINE notifier // newLineNotifier is the constructor for the LINE notifier
func newLineNotifier(fc FactoryConfig) (*LineNotifier, error) { func newLineNotifier(fc FactoryConfig) (*LineNotifier, error) {
token := fc.DecryptFunc(context.Background(), fc.Config.SecureSettings, "token", fc.Config.Settings.Get("token").MustString()) settings, err := simplejson.NewJson(fc.Config.Settings)
if err != nil {
return nil, err
}
token := fc.DecryptFunc(context.Background(), fc.Config.SecureSettings, "token", settings.Get("token").MustString())
if token == "" { if token == "" {
return nil, errors.New("could not find token in settings") return nil, errors.New("could not find token in settings")
} }
title := fc.Config.Settings.Get("title").MustString(DefaultMessageTitleEmbed) title := settings.Get("title").MustString(DefaultMessageTitleEmbed)
description := fc.Config.Settings.Get("description").MustString(DefaultMessageEmbed) description := settings.Get("description").MustString(DefaultMessageEmbed)
return &LineNotifier{ return &LineNotifier{
Base: NewBase(fc.Config), Base: NewBase(fc.Config),

@ -2,6 +2,7 @@ package channels
import ( import (
"context" "context"
"encoding/json"
"net/url" "net/url"
"testing" "testing"
@ -10,7 +11,6 @@ import (
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
) )
@ -96,8 +96,7 @@ func TestLineNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)
webhookSender := mockNotificationService() webhookSender := mockNotificationService()
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())

@ -2,11 +2,11 @@ package channels
import ( import (
"context" "context"
"encoding/json"
"net/url" "net/url"
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
@ -230,8 +230,7 @@ func TestOpsgenieNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)
webhookSender := mockNotificationService() webhookSender := mockNotificationService()

@ -15,7 +15,6 @@ import (
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
) )
@ -276,8 +275,7 @@ func TestPagerdutyNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)
webhookSender := mockNotificationService() webhookSender := mockNotificationService()
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())

@ -3,6 +3,7 @@ package channels
import ( import (
"bytes" "bytes"
"context" "context"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -11,7 +12,6 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
@ -210,8 +210,7 @@ func TestPushoverNotifier(t *testing.T) {
}) })
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)
webhookSender := mockNotificationService() webhookSender := mockNotificationService()

@ -7,7 +7,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
@ -137,8 +136,7 @@ func TestSensuGoNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)
m := &NotificationChannelConfig{ m := &NotificationChannelConfig{

@ -19,7 +19,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
@ -422,10 +421,6 @@ func setupSlackForTests(t *testing.T, settings string) (*SlackNotifier, *slackRe
URL: "https://www.example.com/test.png", URL: "https://www.example.com/test.png",
}}, }},
} }
settingsJSON, err := simplejson.NewJson([]byte(settings))
require.NoError(t, err)
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
notificationService := mockNotificationService() notificationService := mockNotificationService()
@ -433,7 +428,7 @@ func setupSlackForTests(t *testing.T, settings string) (*SlackNotifier, *slackRe
Config: &NotificationChannelConfig{ Config: &NotificationChannelConfig{
Name: "slack_testing", Name: "slack_testing",
Type: "slack", Type: "slack",
Settings: settingsJSON, Settings: json.RawMessage(settings),
SecureSettings: make(map[string][]byte), SecureSettings: make(map[string][]byte),
}, },
ImageStore: images, ImageStore: images,

@ -11,8 +11,6 @@ import (
"github.com/prometheus/alertmanager/types" "github.com/prometheus/alertmanager/types"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
) )
func TestTeamsNotifier(t *testing.T) { func TestTeamsNotifier(t *testing.T) {
@ -249,8 +247,7 @@ func TestTeamsNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
m := &NotificationChannelConfig{ m := &NotificationChannelConfig{
Name: "teams_testing", Name: "teams_testing",

@ -2,11 +2,11 @@ package channels
import ( import (
"context" "context"
"encoding/json"
"net/url" "net/url"
"strings" "strings"
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
@ -116,7 +116,7 @@ func TestTelegramNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err) require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)

@ -2,10 +2,10 @@ package channels
import ( import (
"context" "context"
"encoding/json"
"net/url" "net/url"
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
@ -118,8 +118,7 @@ func TestThreemaNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)
webhookSender := mockNotificationService() webhookSender := mockNotificationService()
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())

@ -24,8 +24,6 @@ import (
"github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/components/simplejson"
) )
const ( const (
@ -170,20 +168,12 @@ type NotificationChannelConfig struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`
DisableResolveMessage bool `json:"disableResolveMessage"` DisableResolveMessage bool `json:"disableResolveMessage"`
Settings *simplejson.Json `json:"settings"` Settings json.RawMessage `json:"settings"`
SecureSettings map[string][]byte `json:"secureSettings"` SecureSettings map[string][]byte `json:"secureSettings"`
} }
func (c NotificationChannelConfig) unmarshalSettings(v interface{}) error { func (c NotificationChannelConfig) unmarshalSettings(v interface{}) error {
ser, err := c.Settings.Encode() return json.Unmarshal(c.Settings, v)
if err != nil {
return err
}
err = json.Unmarshal(ser, v)
if err != nil {
return err
}
return nil
} }
type httpCfg struct { type httpCfg struct {

@ -11,7 +11,6 @@ import (
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -188,8 +187,7 @@ func TestVictoropsNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
m := &NotificationChannelConfig{ m := &NotificationChannelConfig{
Name: "victorops_testing", Name: "victorops_testing",
@ -230,10 +228,11 @@ func TestVictoropsNotifier(t *testing.T) {
require.NotEmpty(t, webhookSender.Webhook.Url) require.NotEmpty(t, webhookSender.Webhook.Url)
// Remove the non-constant timestamp // Remove the non-constant timestamp
j, err := simplejson.NewJson([]byte(webhookSender.Webhook.Body)) data := make(map[string]interface{})
err = json.Unmarshal([]byte(webhookSender.Webhook.Body), &data)
require.NoError(t, err) require.NoError(t, err)
j.Del("timestamp") delete(data, "timestamp")
b, err := j.MarshalJSON() b, err := json.Marshal(data)
require.NoError(t, err) require.NoError(t, err)
body := string(b) body := string(b)

@ -2,12 +2,12 @@ package channels
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"strings" "strings"
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
@ -105,8 +105,7 @@ func TestWebexNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())

@ -7,7 +7,6 @@ import (
"net/url" "net/url"
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
@ -337,8 +336,7 @@ func TestWebhookNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
secureSettings := make(map[string][]byte) secureSettings := make(map[string][]byte)
m := &NotificationChannelConfig{ m := &NotificationChannelConfig{

@ -19,8 +19,6 @@ import (
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
) )
func TestWeComNotifier(t *testing.T) { func TestWeComNotifier(t *testing.T) {
@ -159,8 +157,7 @@ func TestWeComNotifier(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(c.settings)) settingsJSON := json.RawMessage(c.settings)
require.NoError(t, err)
m := &NotificationChannelConfig{ m := &NotificationChannelConfig{
Name: "wecom_testing", Name: "wecom_testing",
@ -345,13 +342,10 @@ func TestWeComNotifierAPIAPP(t *testing.T) {
})) }))
defer server.Close() defer server.Close()
settingsJSON, err := simplejson.NewJson([]byte(tt.settings))
require.NoError(t, err)
m := &NotificationChannelConfig{ m := &NotificationChannelConfig{
Name: "wecom_testing", Name: "wecom_testing",
Type: "wecom", Type: "wecom",
Settings: settingsJSON, Settings: json.RawMessage(tt.settings),
} }
webhookSender := mockNotificationService() webhookSender := mockNotificationService()
@ -532,13 +526,10 @@ func TestWeComFactory(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(tt.settings))
require.NoError(t, err)
m := &NotificationChannelConfig{ m := &NotificationChannelConfig{
Name: "wecom_testing", Name: "wecom_testing",
Type: "wecom", Type: "wecom",
Settings: settingsJSON, Settings: json.RawMessage(tt.settings),
} }
webhookSender := mockNotificationService() webhookSender := mockNotificationService()
@ -552,7 +543,7 @@ func TestWeComFactory(t *testing.T) {
Logger: &FakeLogger{}, Logger: &FakeLogger{},
} }
_, err = WeComFactory(fc) _, err := WeComFactory(fc)
if !tt.wantErr(t, err, fmt.Sprintf("WeComFactory(%v)", fc)) { if !tt.wantErr(t, err, fmt.Sprintf("WeComFactory(%v)", fc)) {
return return
} }

@ -7,12 +7,14 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/prometheus/alertmanager/config"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/prometheus/alertmanager/config"
) )
type ContactPointService struct { type ContactPointService struct {
@ -55,12 +57,16 @@ func (ecp *ContactPointService) GetContactPoints(ctx context.Context, q ContactP
continue continue
} }
simpleJson, err := simplejson.NewJson(contactPoint.Settings)
if err != nil {
return nil, err
}
embeddedContactPoint := apimodels.EmbeddedContactPoint{ embeddedContactPoint := apimodels.EmbeddedContactPoint{
UID: contactPoint.UID, UID: contactPoint.UID,
Type: contactPoint.Type, Type: contactPoint.Type,
Name: contactPoint.Name, Name: contactPoint.Name,
DisableResolveMessage: contactPoint.DisableResolveMessage, DisableResolveMessage: contactPoint.DisableResolveMessage,
Settings: contactPoint.Settings, Settings: simpleJson,
} }
if val, exists := provenances[embeddedContactPoint.UID]; exists && val != "" { if val, exists := provenances[embeddedContactPoint.UID]; exists && val != "" {
embeddedContactPoint.Provenance = string(val) embeddedContactPoint.Provenance = string(val)
@ -96,12 +102,16 @@ func (ecp *ContactPointService) getContactPointDecrypted(ctx context.Context, or
if receiver.UID != uid { if receiver.UID != uid {
continue continue
} }
simpleJson, err := simplejson.NewJson(receiver.Settings)
if err != nil {
return apimodels.EmbeddedContactPoint{}, err
}
embeddedContactPoint := apimodels.EmbeddedContactPoint{ embeddedContactPoint := apimodels.EmbeddedContactPoint{
UID: receiver.UID, UID: receiver.UID,
Type: receiver.Type, Type: receiver.Type,
Name: receiver.Name, Name: receiver.Name,
DisableResolveMessage: receiver.DisableResolveMessage, DisableResolveMessage: receiver.DisableResolveMessage,
Settings: receiver.Settings, Settings: simpleJson,
} }
for k, v := range receiver.SecureSettings { for k, v := range receiver.SecureSettings {
decryptedValue, err := ecp.decryptValue(v) decryptedValue, err := ecp.decryptValue(v)
@ -146,12 +156,18 @@ func (ecp *ContactPointService) CreateContactPoint(ctx context.Context, orgID in
if contactPoint.UID == "" { if contactPoint.UID == "" {
contactPoint.UID = util.GenerateShortUID() contactPoint.UID = util.GenerateShortUID()
} }
jsonData, err := contactPoint.Settings.MarshalJSON()
if err != nil {
return apimodels.EmbeddedContactPoint{}, err
}
grafanaReceiver := &apimodels.PostableGrafanaReceiver{ grafanaReceiver := &apimodels.PostableGrafanaReceiver{
UID: contactPoint.UID, UID: contactPoint.UID,
Name: contactPoint.Name, Name: contactPoint.Name,
Type: contactPoint.Type, Type: contactPoint.Type,
DisableResolveMessage: contactPoint.DisableResolveMessage, DisableResolveMessage: contactPoint.DisableResolveMessage,
Settings: contactPoint.Settings, Settings: jsonData,
SecureSettings: extractedSecrets, SecureSettings: extractedSecrets,
} }
@ -260,12 +276,17 @@ func (ecp *ContactPointService) UpdateContactPoint(ctx context.Context, orgID in
} }
extractedSecrets[k] = encryptedValue extractedSecrets[k] = encryptedValue
} }
jsonData, err := contactPoint.Settings.MarshalJSON()
if err != nil {
return err
}
mergedReceiver := &apimodels.PostableGrafanaReceiver{ mergedReceiver := &apimodels.PostableGrafanaReceiver{
UID: contactPoint.UID, UID: contactPoint.UID,
Name: contactPoint.Name, Name: contactPoint.Name,
Type: contactPoint.Type, Type: contactPoint.Type,
DisableResolveMessage: contactPoint.DisableResolveMessage, DisableResolveMessage: contactPoint.DisableResolveMessage,
Settings: contactPoint.Settings, Settings: jsonData,
SecureSettings: extractedSecrets, SecureSettings: extractedSecrets,
} }
// save to store // save to store

@ -470,6 +470,10 @@ func (m *migration) validateAlertmanagerConfig(orgID int64, config *PostableUser
secureSettings[k] = d secureSettings[k] = d
} }
data, err := gr.Settings.MarshalJSON()
if err != nil {
return err
}
var ( var (
cfg = &channels.NotificationChannelConfig{ cfg = &channels.NotificationChannelConfig{
UID: gr.UID, UID: gr.UID,
@ -477,10 +481,9 @@ func (m *migration) validateAlertmanagerConfig(orgID int64, config *PostableUser
Name: gr.Name, Name: gr.Name,
Type: gr.Type, Type: gr.Type,
DisableResolveMessage: gr.DisableResolveMessage, DisableResolveMessage: gr.DisableResolveMessage,
Settings: gr.Settings, Settings: data,
SecureSettings: secureSettings, SecureSettings: secureSettings,
} }
err error
) )
// decryptFunc represents the legacy way of decrypting data. Before the migration, we don't need any new way, // decryptFunc represents the legacy way of decrypting data. Before the migration, we don't need any new way,

Loading…
Cancel
Save