Alerting: Refactoring ConfigRevision methods (#111192)
* make validateReceiver private * make functions and type alias private * move EncryptedReceivers and DecryptedReceivers to notifier package to reduce exposure of definitions package via legacy_storage * return receivers with Grafana origin after create\update * add tests for ConfigRevision methods
This commit is contained in:
@@ -10,7 +10,9 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"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/notifier/channels_config"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier/legacy_storage"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
)
|
||||
@@ -302,3 +304,49 @@ func (c *ExtraConfigsCrypto) DecryptExtraConfigs(ctx context.Context, config *de
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DecryptedReceivers(receivers []*definitions.PostableApiReceiver, decryptFn models.DecryptFn) ([]*definitions.PostableApiReceiver, error) {
|
||||
decrypted := make([]*definitions.PostableApiReceiver, len(receivers))
|
||||
for i, r := range receivers {
|
||||
// We don't care about the provenance here, so we pass ProvenanceNone.
|
||||
rcv, err := legacy_storage.PostableApiReceiverToReceiver(r, models.ProvenanceNone, models.ResourceOriginGrafana)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = rcv.Decrypt(decryptFn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt receiver %q: %w", rcv.Name, err)
|
||||
}
|
||||
|
||||
postable, err := legacy_storage.ReceiverToPostableApiReceiver(rcv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert Receiver %q to APIReceiver: %w", rcv.Name, err)
|
||||
}
|
||||
decrypted[i] = postable
|
||||
}
|
||||
return decrypted, nil
|
||||
}
|
||||
|
||||
func EncryptedReceivers(receivers []*definitions.PostableApiReceiver, encryptFn models.EncryptFn) ([]*definitions.PostableApiReceiver, error) {
|
||||
encrypted := make([]*definitions.PostableApiReceiver, len(receivers))
|
||||
for i, r := range receivers {
|
||||
// We don't care about the provenance here, so we pass ProvenanceNone.
|
||||
rcv, err := legacy_storage.PostableApiReceiverToReceiver(r, models.ProvenanceNone, models.ResourceOriginGrafana)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = rcv.Encrypt(encryptFn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt receiver %q: %w", rcv.Name, err)
|
||||
}
|
||||
|
||||
postable, err := legacy_storage.ReceiverToPostableApiReceiver(rcv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert Receiver %q to APIReceiver: %w", rcv.Name, err)
|
||||
}
|
||||
encrypted[i] = postable
|
||||
}
|
||||
return encrypted, nil
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
type Provenances map[string]models.Provenance
|
||||
type provenances = map[string]models.Provenance
|
||||
|
||||
func (rev *ConfigRevision) DeleteReceiver(uid string) {
|
||||
// Remove the receiver from the configuration.
|
||||
@@ -39,11 +39,11 @@ func (rev *ConfigRevision) CreateReceiver(receiver *models.Receiver) (*models.Re
|
||||
|
||||
rev.Config.AlertmanagerConfig.Receivers = append(rev.Config.AlertmanagerConfig.Receivers, postable)
|
||||
|
||||
if err := rev.ValidateReceiver(postable); err != nil {
|
||||
if err := rev.validateReceiver(postable); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return PostableApiReceiverToReceiver(postable, receiver.Provenance, receiver.Origin)
|
||||
return PostableApiReceiverToReceiver(postable, receiver.Provenance, models.ResourceOriginGrafana)
|
||||
}
|
||||
|
||||
func (rev *ConfigRevision) UpdateReceiver(receiver *models.Receiver) (*models.Receiver, error) {
|
||||
@@ -65,11 +65,11 @@ func (rev *ConfigRevision) UpdateReceiver(receiver *models.Receiver) (*models.Re
|
||||
|
||||
rev.Config.AlertmanagerConfig.Receivers[existingIdx] = newReceiver
|
||||
|
||||
if err := rev.ValidateReceiver(newReceiver); err != nil {
|
||||
if err := rev.validateReceiver(newReceiver); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return PostableApiReceiverToReceiver(newReceiver, receiver.Provenance, receiver.Origin)
|
||||
return PostableApiReceiverToReceiver(newReceiver, receiver.Provenance, models.ResourceOriginGrafana)
|
||||
}
|
||||
|
||||
// ReceiverNameUsedByRoutes checks if a receiver name is used in any routes.
|
||||
@@ -84,7 +84,7 @@ func (rev *ConfigRevision) ReceiverUseByName() map[string]int {
|
||||
return m
|
||||
}
|
||||
|
||||
func (rev *ConfigRevision) GetReceiver(uid string, prov Provenances) (*models.Receiver, error) {
|
||||
func (rev *ConfigRevision) GetReceiver(uid string, prov provenances) (*models.Receiver, error) {
|
||||
for _, r := range rev.Config.AlertmanagerConfig.Receivers {
|
||||
if NameToUid(r.GetName()) != uid {
|
||||
continue
|
||||
@@ -98,7 +98,7 @@ func (rev *ConfigRevision) GetReceiver(uid string, prov Provenances) (*models.Re
|
||||
return nil, ErrReceiverNotFound.Errorf("")
|
||||
}
|
||||
|
||||
func (rev *ConfigRevision) GetReceivers(uids []string, prov Provenances) ([]*models.Receiver, error) {
|
||||
func (rev *ConfigRevision) GetReceivers(uids []string, prov provenances) ([]*models.Receiver, error) {
|
||||
capacity := len(uids)
|
||||
if capacity == 0 {
|
||||
capacity = len(rev.Config.AlertmanagerConfig.Receivers)
|
||||
@@ -127,60 +127,14 @@ func (rev *ConfigRevision) GetReceiversNames() map[string]struct{} {
|
||||
return result
|
||||
}
|
||||
|
||||
func DecryptedReceivers(receivers []*definitions.PostableApiReceiver, decryptFn models.DecryptFn) ([]*definitions.PostableApiReceiver, error) {
|
||||
decrypted := make([]*definitions.PostableApiReceiver, len(receivers))
|
||||
for i, r := range receivers {
|
||||
// We don't care about the provenance here, so we pass ProvenanceNone.
|
||||
rcv, err := PostableApiReceiverToReceiver(r, models.ProvenanceNone, models.ResourceOriginGrafana)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = rcv.Decrypt(decryptFn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt receiver %q: %w", rcv.Name, err)
|
||||
}
|
||||
|
||||
postable, err := ReceiverToPostableApiReceiver(rcv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert Receiver %q to APIReceiver: %w", rcv.Name, err)
|
||||
}
|
||||
decrypted[i] = postable
|
||||
}
|
||||
return decrypted, nil
|
||||
}
|
||||
|
||||
func EncryptedReceivers(receivers []*definitions.PostableApiReceiver, encryptFn models.EncryptFn) ([]*definitions.PostableApiReceiver, error) {
|
||||
encrypted := make([]*definitions.PostableApiReceiver, len(receivers))
|
||||
for i, r := range receivers {
|
||||
// We don't care about the provenance here, so we pass ProvenanceNone.
|
||||
rcv, err := PostableApiReceiverToReceiver(r, models.ProvenanceNone, models.ResourceOriginGrafana)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = rcv.Encrypt(encryptFn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt receiver %q: %w", rcv.Name, err)
|
||||
}
|
||||
|
||||
postable, err := ReceiverToPostableApiReceiver(rcv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert Receiver %q to APIReceiver: %w", rcv.Name, err)
|
||||
}
|
||||
encrypted[i] = postable
|
||||
}
|
||||
return encrypted, nil
|
||||
}
|
||||
|
||||
// RenameReceiverInRoutes renames all references to a receiver in routes. Returns number of routes that were updated
|
||||
func (rev *ConfigRevision) RenameReceiverInRoutes(oldName, newName string) int {
|
||||
return RenameReceiverInRoute(oldName, newName, rev.Config.AlertmanagerConfig.Route)
|
||||
return renameReceiverInRoute(oldName, newName, rev.Config.AlertmanagerConfig.Route)
|
||||
}
|
||||
|
||||
// ValidateReceiver checks if the given receiver conflicts in name or integration UID with existing receivers.
|
||||
// validateReceiver checks if the given receiver conflicts in name or integration UID with existing receivers.
|
||||
// We only check the receiver being modified to prevent existing issues from other receivers being reported.
|
||||
func (rev *ConfigRevision) ValidateReceiver(p *definitions.PostableApiReceiver) error {
|
||||
func (rev *ConfigRevision) validateReceiver(p *definitions.PostableApiReceiver) error {
|
||||
uids := make(map[string]struct{}, len(rev.Config.AlertmanagerConfig.Receivers))
|
||||
for _, integrations := range p.GrafanaManagedReceivers {
|
||||
if _, exists := uids[integrations.UID]; exists {
|
||||
@@ -207,7 +161,7 @@ func (rev *ConfigRevision) ValidateReceiver(p *definitions.PostableApiReceiver)
|
||||
return nil
|
||||
}
|
||||
|
||||
func RenameReceiverInRoute(oldName, newName string, routes ...*definitions.Route) int {
|
||||
func renameReceiverInRoute(oldName, newName string, routes ...*definitions.Route) int {
|
||||
if len(routes) == 0 {
|
||||
return 0
|
||||
}
|
||||
@@ -217,7 +171,7 @@ func RenameReceiverInRoute(oldName, newName string, routes ...*definitions.Route
|
||||
route.Receiver = newName
|
||||
updated++
|
||||
}
|
||||
updated += RenameReceiverInRoute(oldName, newName, route.Routes...)
|
||||
updated += renameReceiverInRoute(oldName, newName, route.Routes...)
|
||||
}
|
||||
return updated
|
||||
}
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
package legacy_storage
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/alerting/definition"
|
||||
"github.com/grafana/alerting/notify"
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func TestReceiverInUse(t *testing.T) {
|
||||
@@ -38,3 +47,477 @@ func TestReceiverInUse(t *testing.T) {
|
||||
})
|
||||
require.False(t, result)
|
||||
}
|
||||
|
||||
func TestDeleteReceiver(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
receiverUID string
|
||||
assert func(t *testing.T, rev *ConfigRevision)
|
||||
}{
|
||||
{
|
||||
name: "should remove receiver if exists",
|
||||
receiverUID: NameToUid("receiver1"),
|
||||
assert: func(t *testing.T, rev *ConfigRevision) {
|
||||
require.False(t, slices.ContainsFunc(rev.Config.AlertmanagerConfig.Receivers, func(receiver *definition.PostableApiReceiver) bool {
|
||||
return receiver.Name == "receiver1"
|
||||
}))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should do nothing if receiver does not exist",
|
||||
receiverUID: NameToUid("not-existing"),
|
||||
assert: func(t *testing.T, rev *ConfigRevision) {
|
||||
require.Equal(t, getConfigRevisionForTest(), rev)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should remove all receivers with the same name",
|
||||
receiverUID: NameToUid("dupe-receiver"),
|
||||
assert: func(t *testing.T, rev *ConfigRevision) {
|
||||
require.False(t, slices.ContainsFunc(rev.Config.AlertmanagerConfig.Receivers, func(receiver *definition.PostableApiReceiver) bool {
|
||||
return receiver.Name == "dupe-receiver"
|
||||
}))
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
rev := getConfigRevisionForTest()
|
||||
rev.DeleteReceiver(tc.receiverUID)
|
||||
tc.assert(t, rev)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateReceiver(t *testing.T) {
|
||||
rawCfg := notify.AllKnownConfigsForTesting["webhook"]
|
||||
cfgSchema, err := models.IntegrationConfigFromType(rawCfg.NotifierType, util.Pointer("v1"))
|
||||
require.NoError(t, err)
|
||||
settings := map[string]any{}
|
||||
require.NoError(t, json.Unmarshal([]byte(rawCfg.Config), &settings))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
receiver *models.Receiver
|
||||
expectedError error
|
||||
assertResponse func(t *testing.T, rev *ConfigRevision, receiver *models.Receiver)
|
||||
}{
|
||||
{
|
||||
name: "should error if receiver already exists by UID",
|
||||
receiver: &models.Receiver{
|
||||
UID: NameToUid("receiver1"),
|
||||
Name: "New receiver name",
|
||||
},
|
||||
expectedError: ErrReceiverExists,
|
||||
},
|
||||
{
|
||||
name: "should error if receiver already exists by name",
|
||||
receiver: &models.Receiver{
|
||||
UID: "some-uid",
|
||||
Name: "receiver1",
|
||||
},
|
||||
expectedError: ErrReceiverInvalid,
|
||||
},
|
||||
{
|
||||
name: "should fail if integration UID is not valid",
|
||||
receiver: &models.Receiver{
|
||||
UID: "some-uid",
|
||||
Name: "receiver",
|
||||
Integrations: []*models.Integration{
|
||||
{
|
||||
UID: strings.Repeat("*", 256),
|
||||
Config: cfgSchema,
|
||||
Settings: settings,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: ErrReceiverInvalid,
|
||||
},
|
||||
{
|
||||
name: "should fail if integration UID already exists",
|
||||
receiver: &models.Receiver{
|
||||
UID: "some-uid",
|
||||
Name: "receiver",
|
||||
Integrations: []*models.Integration{
|
||||
{
|
||||
UID: "integration-uid-1",
|
||||
Config: cfgSchema,
|
||||
Settings: settings,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: ErrReceiverInvalid,
|
||||
},
|
||||
{
|
||||
name: "should add the receiver to configuration and set integrations UID",
|
||||
receiver: &models.Receiver{
|
||||
UID: "some-uid",
|
||||
Name: "receiver2",
|
||||
Provenance: "test",
|
||||
Integrations: []*models.Integration{
|
||||
{
|
||||
Config: cfgSchema,
|
||||
Settings: settings,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: nil,
|
||||
assertResponse: func(t *testing.T, rev *ConfigRevision, receiver *models.Receiver) {
|
||||
t.Helper()
|
||||
idx := slices.IndexFunc(rev.Config.AlertmanagerConfig.Receivers, func(r *definition.PostableApiReceiver) bool {
|
||||
return r.Name == "receiver2"
|
||||
})
|
||||
assert.Greaterf(t, idx, -1, "receiver was not added to the configuration")
|
||||
postable := rev.Config.AlertmanagerConfig.Receivers[idx]
|
||||
require.Len(t, postable.GrafanaManagedReceivers, 1)
|
||||
require.Equal(t, receiver.Name, postable.Name)
|
||||
require.NotEmpty(t, postable.GrafanaManagedReceivers[0].UID)
|
||||
require.JSONEq(t, string(postable.GrafanaManagedReceivers[0].Settings), rawCfg.Config)
|
||||
|
||||
assert.Equal(t, models.ResourceOriginGrafana, receiver.Origin)
|
||||
assert.Equal(t, NameToUid("receiver2"), receiver.UID)
|
||||
assert.Equal(t, postable.GrafanaManagedReceivers[0].UID, receiver.Integrations[0].UID)
|
||||
assert.EqualValues(t, "test", receiver.Provenance)
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
rev := getConfigRevisionForTest()
|
||||
recv, err := rev.CreateReceiver(tc.receiver)
|
||||
if tc.expectedError != nil {
|
||||
require.ErrorIs(t, err, tc.expectedError)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
tc.assertResponse(t, rev, recv)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateReceiver(t *testing.T) {
|
||||
rawCfg := notify.AllKnownConfigsForTesting["webhook"]
|
||||
cfgSchema, err := models.IntegrationConfigFromType(rawCfg.NotifierType, util.Pointer("v1"))
|
||||
require.NoError(t, err)
|
||||
settings := map[string]any{}
|
||||
require.NoError(t, json.Unmarshal([]byte(rawCfg.Config), &settings))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
receiver *models.Receiver
|
||||
expectedError error
|
||||
assertResponse func(t *testing.T, rev *ConfigRevision, receiver *models.Receiver)
|
||||
}{
|
||||
{
|
||||
name: "should error if receiver does not exists by UID",
|
||||
receiver: &models.Receiver{
|
||||
UID: NameToUid("receiver2"),
|
||||
Name: "receiver1",
|
||||
},
|
||||
expectedError: ErrReceiverNotFound,
|
||||
},
|
||||
{
|
||||
name: "should fail if integration UID is not valid",
|
||||
receiver: &models.Receiver{
|
||||
UID: NameToUid("receiver1"),
|
||||
Name: "receiver1",
|
||||
Integrations: []*models.Integration{
|
||||
{
|
||||
UID: strings.Repeat("*", 256),
|
||||
Config: cfgSchema,
|
||||
Settings: settings,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: ErrReceiverInvalid,
|
||||
},
|
||||
{
|
||||
name: "should fail if integration UID already exists",
|
||||
receiver: &models.Receiver{
|
||||
UID: NameToUid("receiver1"),
|
||||
Name: "receiver1",
|
||||
Integrations: []*models.Integration{
|
||||
{
|
||||
UID: "integration-uid-2",
|
||||
Config: cfgSchema,
|
||||
Settings: settings,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: ErrReceiverInvalid,
|
||||
},
|
||||
{
|
||||
name: "should update the existing receiver",
|
||||
receiver: &models.Receiver{
|
||||
UID: NameToUid("receiver1"),
|
||||
Name: "receiver-new",
|
||||
Provenance: "test",
|
||||
Integrations: []*models.Integration{
|
||||
{
|
||||
Config: cfgSchema,
|
||||
Settings: settings,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: nil,
|
||||
assertResponse: func(t *testing.T, rev *ConfigRevision, receiver *models.Receiver) {
|
||||
t.Helper()
|
||||
idx := slices.IndexFunc(rev.Config.AlertmanagerConfig.Receivers, func(r *definition.PostableApiReceiver) bool {
|
||||
return r.Name == "receiver-new"
|
||||
})
|
||||
assert.Greaterf(t, idx, -1, "receiver was not found to the configuration")
|
||||
old := getConfigRevisionForTest().Config.AlertmanagerConfig.Receivers[idx]
|
||||
require.Equalf(t, old.Name, "receiver1", "the receiver should be updated in place")
|
||||
|
||||
postable := rev.Config.AlertmanagerConfig.Receivers[idx]
|
||||
require.Len(t, postable.GrafanaManagedReceivers, 1)
|
||||
require.Equal(t, receiver.Name, postable.Name)
|
||||
require.NotEmpty(t, postable.GrafanaManagedReceivers[0].UID)
|
||||
require.JSONEq(t, string(postable.GrafanaManagedReceivers[0].Settings), rawCfg.Config)
|
||||
|
||||
assert.Equal(t, postable.GrafanaManagedReceivers[0].UID, receiver.Integrations[0].UID)
|
||||
assert.Equal(t, NameToUid("receiver-new"), receiver.UID)
|
||||
assert.EqualValues(t, "test", receiver.Provenance)
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
rev := getConfigRevisionForTest()
|
||||
recv, err := rev.UpdateReceiver(tc.receiver)
|
||||
if tc.expectedError != nil {
|
||||
require.ErrorIs(t, err, tc.expectedError)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
tc.assertResponse(t, rev, recv)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetReceiver(t *testing.T) {
|
||||
rawCfg := notify.AllKnownConfigsForTesting["webhook"]
|
||||
cfgSchema, err := models.IntegrationConfigFromType(rawCfg.NotifierType, util.Pointer("v1"))
|
||||
require.NoError(t, err)
|
||||
settings := map[string]any{}
|
||||
require.NoError(t, json.Unmarshal([]byte(rawCfg.Config), &settings))
|
||||
|
||||
t.Run("should return ErrReceiverNotFound if receiver does not exists", func(t *testing.T) {
|
||||
rev := getConfigRevisionForTest()
|
||||
_, err := rev.GetReceiver("not-found", nil)
|
||||
require.ErrorIs(t, err, ErrReceiverNotFound)
|
||||
})
|
||||
|
||||
t.Run("should return receiver if exists", func(t *testing.T) {
|
||||
prov := provenances{
|
||||
"integration-uid-1": "test",
|
||||
}
|
||||
|
||||
expected := &models.Receiver{
|
||||
UID: NameToUid("receiver1"),
|
||||
Name: "receiver1",
|
||||
Provenance: models.Provenance("test"),
|
||||
Origin: models.ResourceOriginGrafana,
|
||||
Version: "6e2fb0f572bc90f7",
|
||||
Integrations: []*models.Integration{
|
||||
{
|
||||
UID: "integration-uid-1",
|
||||
Config: cfgSchema,
|
||||
Settings: settings,
|
||||
SecureSettings: make(map[string]string),
|
||||
},
|
||||
},
|
||||
}
|
||||
rev := getConfigRevisionForTest()
|
||||
result, err := rev.GetReceiver(NameToUid("receiver1"), prov)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetReceivers(t *testing.T) {
|
||||
rev := getConfigRevisionForTest()
|
||||
|
||||
t.Run("should return all receivers with correct provenance", func(t *testing.T) {
|
||||
prov := provenances{
|
||||
"integration-uid-1": "test",
|
||||
"integration-uid-2": "some",
|
||||
}
|
||||
receivers, err := rev.GetReceivers(nil, prov)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, receivers, len(rev.Config.AlertmanagerConfig.Receivers))
|
||||
for _, r := range receivers {
|
||||
assert.Equalf(t, NameToUid(r.Name), r.UID, "receiver UID should be function of receiver name")
|
||||
assert.Equal(t, r.Origin, models.ResourceOriginGrafana)
|
||||
if r.Name == "receiver1" {
|
||||
assert.EqualValues(t, "test", r.Provenance)
|
||||
} else if r.Name == "dupe-receiver" && r.Integrations[0].UID == "integration-uid-2" {
|
||||
assert.EqualValues(t, "some", r.Provenance)
|
||||
} else {
|
||||
assert.Empty(t, r.Provenance)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("should filter by uids", func(t *testing.T) {
|
||||
receivers, err := rev.GetReceivers([]string{"not-found-1", "not-found-2"}, nil)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, receivers)
|
||||
receivers, err = rev.GetReceivers([]string{NameToUid("receiver1")}, nil)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, receivers, 1)
|
||||
expected, err := rev.GetReceiver(NameToUid("receiver1"), nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, receivers[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestReceiverNameUsedByRoutes(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
receiverName string
|
||||
expectedResult bool
|
||||
}{
|
||||
{
|
||||
name: "should return true if receiver is used by routes",
|
||||
receiverName: "receiver1",
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "should return false if receiver is not used by routes",
|
||||
receiverName: "receiver2",
|
||||
expectedResult: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
rev := getConfigRevisionForTest()
|
||||
result := rev.ReceiverNameUsedByRoutes(tc.receiverName)
|
||||
require.Equal(t, tc.expectedResult, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReceiverUseByName(t *testing.T) {
|
||||
rev := getConfigRevisionForTest()
|
||||
rev.Config.AlertmanagerConfig.Route.Routes = append(rev.Config.AlertmanagerConfig.Route.Routes,
|
||||
&definitions.Route{
|
||||
Routes: []*definitions.Route{
|
||||
{
|
||||
Receiver: "receiver1",
|
||||
},
|
||||
{
|
||||
Receiver: "dupe-receiver",
|
||||
},
|
||||
{
|
||||
Receiver: "some-missing-receiver",
|
||||
},
|
||||
},
|
||||
})
|
||||
expected := map[string]int{
|
||||
"": 1, // some routes do not have receiver set
|
||||
"receiver1": 2,
|
||||
"dupe-receiver": 1,
|
||||
"some-missing-receiver": 1,
|
||||
}
|
||||
require.Equal(t, expected, rev.ReceiverUseByName())
|
||||
}
|
||||
|
||||
func TestRenameReceiverInRoutes(t *testing.T) {
|
||||
rev := getConfigRevisionForTest()
|
||||
rev.Config.AlertmanagerConfig.Route.Routes = append(rev.Config.AlertmanagerConfig.Route.Routes, &definitions.Route{
|
||||
Receiver: "receiver1",
|
||||
Routes: []*definitions.Route{
|
||||
{
|
||||
Receiver: "receiver1",
|
||||
Routes: []*definitions.Route{
|
||||
{
|
||||
Receiver: "missing-receiver",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Receiver: "dupe-receiver",
|
||||
Routes: []*definitions.Route{
|
||||
{
|
||||
Receiver: "receiver1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
t.Run("should do nothing if receiver is not used by routes ", func(t *testing.T) {
|
||||
result := rev.RenameReceiverInRoutes("not-found", "found")
|
||||
require.Zero(t, result)
|
||||
expected := map[string]int{
|
||||
"receiver1": 4,
|
||||
"missing-receiver": 1,
|
||||
"dupe-receiver": 1,
|
||||
}
|
||||
require.Equal(t, expected, rev.ReceiverUseByName())
|
||||
})
|
||||
|
||||
t.Run("should rename all references", func(t *testing.T) {
|
||||
result := rev.RenameReceiverInRoutes("receiver1", "found")
|
||||
require.Equal(t, result, 4)
|
||||
expected := map[string]int{
|
||||
"found": 4,
|
||||
"missing-receiver": 1,
|
||||
"dupe-receiver": 1,
|
||||
}
|
||||
require.Equal(t, expected, rev.ReceiverUseByName())
|
||||
})
|
||||
}
|
||||
|
||||
func getConfigRevisionForTest() *ConfigRevision {
|
||||
return &ConfigRevision{
|
||||
Config: &definitions.PostableUserConfig{
|
||||
AlertmanagerConfig: definitions.PostableApiAlertingConfig{
|
||||
Config: definitions.Config{
|
||||
Route: &definitions.Route{Receiver: "receiver1"},
|
||||
},
|
||||
Receivers: []*definition.PostableApiReceiver{
|
||||
{
|
||||
Receiver: config.Receiver{
|
||||
Name: "receiver1",
|
||||
},
|
||||
PostableGrafanaReceivers: definition.PostableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definition.PostableGrafanaReceiver{
|
||||
{
|
||||
UID: "integration-uid-1",
|
||||
Type: "webhook",
|
||||
Settings: definitions.RawMessage(notify.AllKnownConfigsForTesting["webhook"].Config),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Receiver: config.Receiver{Name: "dupe-receiver"},
|
||||
PostableGrafanaReceivers: definition.PostableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definition.PostableGrafanaReceiver{
|
||||
{
|
||||
UID: "integration-uid-2",
|
||||
Type: "webhook",
|
||||
Settings: definitions.RawMessage(notify.AllKnownConfigsForTesting["webhook"].Config),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Receiver: config.Receiver{Name: "dupe-receiver"},
|
||||
PostableGrafanaReceivers: definition.PostableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definition.PostableGrafanaReceiver{
|
||||
{
|
||||
UID: "integration-uid-3",
|
||||
Type: "email",
|
||||
Settings: definitions.RawMessage(notify.AllKnownConfigsForTesting["email"].Config),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier/legacy_storage"
|
||||
remoteClient "github.com/grafana/grafana/pkg/services/ngalert/remote/client"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/sender"
|
||||
"github.com/grafana/grafana/pkg/util/cmputil"
|
||||
@@ -315,7 +314,7 @@ func (am *Alertmanager) buildConfiguration(ctx context.Context, raw []byte, crea
|
||||
}
|
||||
|
||||
// Decrypt the receivers in the configuration.
|
||||
decryptedReceivers, err := legacy_storage.DecryptedReceivers(c.AlertmanagerConfig.Receivers, decrypter(ctx, am.crypto))
|
||||
decryptedReceivers, err := notifier.DecryptedReceivers(c.AlertmanagerConfig.Receivers, decrypter(ctx, am.crypto))
|
||||
if err != nil {
|
||||
return remoteClient.UserGrafanaConfig{}, fmt.Errorf("unable to decrypt receivers: %w", err)
|
||||
}
|
||||
@@ -605,7 +604,7 @@ func (am *Alertmanager) GetReceivers(ctx context.Context) ([]apimodels.Receiver,
|
||||
}
|
||||
|
||||
func (am *Alertmanager) TestReceivers(ctx context.Context, c apimodels.TestReceiversConfigBodyParams) (*alertingNotify.TestReceiversResult, int, error) {
|
||||
decryptedReceivers, err := legacy_storage.DecryptedReceivers(c.Receivers, decrypter(ctx, am.crypto))
|
||||
decryptedReceivers, err := notifier.DecryptedReceivers(c.Receivers, decrypter(ctx, am.crypto))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to decrypt receivers: %w", err)
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier/legacy_storage"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/remote/client"
|
||||
ngfakes "github.com/grafana/grafana/pkg/services/ngalert/tests/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
@@ -152,7 +151,7 @@ func TestGetRemoteState(t *testing.T) {
|
||||
|
||||
// getOkHandler allows us to specify a full state the test server is going to respond with.
|
||||
getOkHandler := func(state string) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, tenantID, r.Header.Get(client.MimirTenantHeader))
|
||||
require.Equal(t, "true", r.Header.Get(client.RemoteAlertmanagerHeader))
|
||||
|
||||
@@ -164,7 +163,7 @@ func TestGetRemoteState(t *testing.T) {
|
||||
}
|
||||
w.Header().Add("content-type", "application/json")
|
||||
require.NoError(t, json.NewEncoder(w).Encode(res))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// errorHandler makes the test server return a 500 status code and a non-JSON response.
|
||||
@@ -302,7 +301,7 @@ func TestIntegrationApplyConfig(t *testing.T) {
|
||||
var c apimodels.PostableUserConfig
|
||||
require.NoError(t, json.Unmarshal([]byte(testGrafanaConfigWithSecret), &c))
|
||||
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(db.InitTestDB(t)))
|
||||
encryptedReceivers, err := legacy_storage.EncryptedReceivers(c.AlertmanagerConfig.Receivers, func(payload string) (string, error) {
|
||||
encryptedReceivers, err := notifier.EncryptedReceivers(c.AlertmanagerConfig.Receivers, func(payload string) (string, error) {
|
||||
encrypted, err := secretsService.Encrypt(context.Background(), []byte(payload), secrets.WithoutScope())
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -381,7 +380,7 @@ func TestIntegrationApplyConfig(t *testing.T) {
|
||||
// should result in us sending the configuration but not the state.
|
||||
am.syncInterval = 0
|
||||
config = &ngmodels.AlertConfiguration{
|
||||
AlertmanagerConfiguration: string(testGrafanaConfig),
|
||||
AlertmanagerConfiguration: testGrafanaConfig,
|
||||
}
|
||||
require.NoError(t, am.ApplyConfig(ctx, config))
|
||||
require.Equal(t, 2, configSyncs)
|
||||
@@ -467,7 +466,7 @@ func TestCompareAndSendConfiguration(t *testing.T) {
|
||||
// Create a config with correctly encrypted and encoded secrets.
|
||||
var inputCfg apimodels.PostableUserConfig
|
||||
require.NoError(t, json.Unmarshal([]byte(testGrafanaConfigWithSecret), &inputCfg))
|
||||
encryptedReceivers, err := legacy_storage.EncryptedReceivers(inputCfg.AlertmanagerConfig.Receivers, func(payload string) (string, error) {
|
||||
encryptedReceivers, err := notifier.EncryptedReceivers(inputCfg.AlertmanagerConfig.Receivers, func(payload string) (string, error) {
|
||||
encrypted, err := secretsService.Encrypt(context.Background(), []byte(payload), secrets.WithoutScope())
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -669,7 +668,7 @@ func Test_TestReceiversDecryptsSecureSettings(t *testing.T) {
|
||||
|
||||
var inputCfg apimodels.PostableUserConfig
|
||||
require.NoError(t, json.Unmarshal([]byte(testGrafanaConfigWithSecret), &inputCfg))
|
||||
encryptedReceivers, err := legacy_storage.EncryptedReceivers(inputCfg.AlertmanagerConfig.Receivers, func(payload string) (string, error) {
|
||||
encryptedReceivers, err := notifier.EncryptedReceivers(inputCfg.AlertmanagerConfig.Receivers, func(payload string) (string, error) {
|
||||
encrypted, err := secretsService.Encrypt(context.Background(), []byte(payload), secrets.WithoutScope())
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -1045,7 +1044,7 @@ func TestIntegrationRemoteAlertmanagerConfiguration(t *testing.T) {
|
||||
{
|
||||
postableCfg, err := notifier.Load([]byte(testGrafanaConfigWithSecret))
|
||||
require.NoError(t, err)
|
||||
encryptedReceivers, err := legacy_storage.EncryptedReceivers(postableCfg.AlertmanagerConfig.Receivers, func(payload string) (string, error) {
|
||||
encryptedReceivers, err := notifier.EncryptedReceivers(postableCfg.AlertmanagerConfig.Receivers, func(payload string) (string, error) {
|
||||
encrypted, err := secretsService.Encrypt(context.Background(), []byte(payload), secrets.WithoutScope())
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
Reference in New Issue
Block a user