mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Remove vendored models in migration service (#74503)
This PR replaces the vendored models in the migration with their equivalent ngalert models. It also replaces the raw SQL selects and inserts with service calls.
It also fills in some gaps in the testing suite around:
- Migration of alert rules: verifying that the actual data model (queries, conditions) are correct 9a7cfa9
- Secure settings migration: verifying that secure fields remain encrypted for all available notifiers and certain fields migrate from plain text to encrypted secure settings correctly e7d3993
Replacing the checks for custom dashboard ACLs will be replaced in a separate targeted PR as it will be complex enough alone.
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/tests/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/secrets/database"
|
||||
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -37,7 +38,7 @@ func setupAMTest(t *testing.T) *alertmanager {
|
||||
DashboardService: dashboards.NewFakeDashboardService(t),
|
||||
}
|
||||
|
||||
kvStore := NewFakeKVStore(t)
|
||||
kvStore := fakes.NewFakeKVStore(t)
|
||||
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
|
||||
decryptFn := secretsService.GetDecryptedValue
|
||||
am, err := newAlertmanager(context.Background(), 1, cfg, s, kvStore, &NilPeer{}, decryptFn, nil, m)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package channels_config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
alertingOpsgenie "github.com/grafana/alerting/receivers/opsgenie"
|
||||
@@ -1340,3 +1341,20 @@ func GetAvailableNotifiers() []*NotifierPlugin {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetSecretKeysForContactPointType returns settings keys of contact point of the given type that are expected to be secrets. Returns error is contact point type is not known.
|
||||
func GetSecretKeysForContactPointType(contactPointType string) ([]string, error) {
|
||||
notifiers := GetAvailableNotifiers()
|
||||
for _, n := range notifiers {
|
||||
if n.Type == contactPointType {
|
||||
var secureFields []string
|
||||
for _, field := range n.Options {
|
||||
if field.Secure {
|
||||
secureFields = append(secureFields, field.PropertyName)
|
||||
}
|
||||
}
|
||||
return secureFields, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no secrets configured for type '%s'", contactPointType)
|
||||
}
|
||||
|
||||
@@ -7,10 +7,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/tests/fakes"
|
||||
)
|
||||
|
||||
func TestFileStore_FilepathFor_DirectoryNotExist(t *testing.T) {
|
||||
store := NewFakeKVStore(t)
|
||||
store := fakes.NewFakeKVStore(t)
|
||||
workingDir := filepath.Join(t.TempDir(), "notexistdir")
|
||||
fs := NewFileStore(1, store, workingDir)
|
||||
filekey := "silences"
|
||||
@@ -31,7 +33,7 @@ func TestFileStore_FilepathFor_DirectoryNotExist(t *testing.T) {
|
||||
}
|
||||
}
|
||||
func TestFileStore_FilepathFor(t *testing.T) {
|
||||
store := NewFakeKVStore(t)
|
||||
store := fakes.NewFakeKVStore(t)
|
||||
workingDir := t.TempDir()
|
||||
fs := NewFileStore(1, store, workingDir)
|
||||
filekey := "silences"
|
||||
@@ -73,7 +75,7 @@ func TestFileStore_FilepathFor(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFileStore_Persist(t *testing.T) {
|
||||
store := NewFakeKVStore(t)
|
||||
store := fakes.NewFakeKVStore(t)
|
||||
state := &fakeState{data: "something to marshal"}
|
||||
workingDir := t.TempDir()
|
||||
fs := NewFileStore(1, store, workingDir)
|
||||
@@ -82,9 +84,9 @@ func TestFileStore_Persist(t *testing.T) {
|
||||
size, err := fs.Persist(context.Background(), filekey, state)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(20), size)
|
||||
store.mtx.Lock()
|
||||
require.Len(t, store.store, 1)
|
||||
store.mtx.Unlock()
|
||||
store.Mtx.Lock()
|
||||
require.Len(t, store.Store, 1)
|
||||
store.Mtx.Unlock()
|
||||
v, ok, err := store.Get(context.Background(), 1, KVNamespace, filekey)
|
||||
require.NoError(t, err)
|
||||
require.True(t, ok)
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/provisioning"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
ngfakes "github.com/grafana/grafana/pkg/services/ngalert/tests/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -31,7 +32,7 @@ func TestMultiOrgAlertmanager_SyncAlertmanagersForOrgs(t *testing.T) {
|
||||
}
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
kvStore := NewFakeKVStore(t)
|
||||
kvStore := ngfakes.NewFakeKVStore(t)
|
||||
provStore := provisioning.NewFakeProvisioningStore()
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
decryptFn := secretsService.GetDecryptedValue
|
||||
@@ -165,7 +166,7 @@ func TestMultiOrgAlertmanager_SyncAlertmanagersForOrgsWithFailures(t *testing.T)
|
||||
}
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
kvStore := NewFakeKVStore(t)
|
||||
kvStore := ngfakes.NewFakeKVStore(t)
|
||||
provStore := provisioning.NewFakeProvisioningStore()
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
decryptFn := secretsService.GetDecryptedValue
|
||||
@@ -259,7 +260,7 @@ func TestMultiOrgAlertmanager_AlertmanagerFor(t *testing.T) {
|
||||
DataPath: tmpDir,
|
||||
UnifiedAlerting: setting.UnifiedAlertingSettings{AlertmanagerConfigPollInterval: 3 * time.Minute, DefaultConfiguration: setting.GetAlertmanagerDefaultConfiguration()}, // do not poll in tests.
|
||||
}
|
||||
kvStore := NewFakeKVStore(t)
|
||||
kvStore := ngfakes.NewFakeKVStore(t)
|
||||
provStore := provisioning.NewFakeProvisioningStore()
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
decryptFn := secretsService.GetDecryptedValue
|
||||
@@ -310,7 +311,7 @@ func TestMultiOrgAlertmanager_ActivateHistoricalConfiguration(t *testing.T) {
|
||||
DataPath: tmpDir,
|
||||
UnifiedAlerting: setting.UnifiedAlertingSettings{AlertmanagerConfigPollInterval: 3 * time.Minute, DefaultConfiguration: defaultConfig}, // do not poll in tests.
|
||||
}
|
||||
kvStore := NewFakeKVStore(t)
|
||||
kvStore := ngfakes.NewFakeKVStore(t)
|
||||
provStore := provisioning.NewFakeProvisioningStore()
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
decryptFn := secretsService.GetDecryptedValue
|
||||
|
||||
@@ -5,12 +5,9 @@ import (
|
||||
"crypto/md5"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
|
||||
@@ -195,98 +192,6 @@ func (f *FakeOrgStore) GetOrgs(_ context.Context) ([]int64, error) {
|
||||
return f.orgs, nil
|
||||
}
|
||||
|
||||
type FakeKVStore struct {
|
||||
mtx sync.Mutex
|
||||
store map[int64]map[string]map[string]string
|
||||
}
|
||||
|
||||
func NewFakeKVStore(t *testing.T) *FakeKVStore {
|
||||
t.Helper()
|
||||
|
||||
return &FakeKVStore{
|
||||
store: map[int64]map[string]map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
func (fkv *FakeKVStore) Get(_ context.Context, orgId int64, namespace string, key string) (string, bool, error) {
|
||||
fkv.mtx.Lock()
|
||||
defer fkv.mtx.Unlock()
|
||||
org, ok := fkv.store[orgId]
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
k, ok := org[namespace]
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
v, ok := k[key]
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
return v, true, nil
|
||||
}
|
||||
func (fkv *FakeKVStore) Set(_ context.Context, orgId int64, namespace string, key string, value string) error {
|
||||
fkv.mtx.Lock()
|
||||
defer fkv.mtx.Unlock()
|
||||
org, ok := fkv.store[orgId]
|
||||
if !ok {
|
||||
fkv.store[orgId] = map[string]map[string]string{}
|
||||
}
|
||||
_, ok = org[namespace]
|
||||
if !ok {
|
||||
fkv.store[orgId][namespace] = map[string]string{}
|
||||
}
|
||||
|
||||
fkv.store[orgId][namespace][key] = value
|
||||
|
||||
return nil
|
||||
}
|
||||
func (fkv *FakeKVStore) Del(_ context.Context, orgId int64, namespace string, key string) error {
|
||||
fkv.mtx.Lock()
|
||||
defer fkv.mtx.Unlock()
|
||||
org, ok := fkv.store[orgId]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
_, ok = org[namespace]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
delete(fkv.store[orgId][namespace], key)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fkv *FakeKVStore) Keys(ctx context.Context, orgID int64, namespace string, keyPrefix string) ([]kvstore.Key, error) {
|
||||
fkv.mtx.Lock()
|
||||
defer fkv.mtx.Unlock()
|
||||
var keys []kvstore.Key
|
||||
for orgIDFromStore, namespaceMap := range fkv.store {
|
||||
if orgID != kvstore.AllOrganizations && orgID != orgIDFromStore {
|
||||
continue
|
||||
}
|
||||
if keyMap, exists := namespaceMap[namespace]; exists {
|
||||
for k := range keyMap {
|
||||
if strings.HasPrefix(k, keyPrefix) {
|
||||
keys = append(keys, kvstore.Key{
|
||||
OrgId: orgIDFromStore,
|
||||
Namespace: namespace,
|
||||
Key: keyPrefix,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (fkv *FakeKVStore) GetAll(ctx context.Context, orgId int64, namespace string) (map[int64]map[string]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type fakeState struct {
|
||||
data string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user