Encryption: Refactor securejsondata.SecureJsonData to stop relying on global functions (#38865)
* Encryption: Add support to encrypt/decrypt sjd * Add datasources.Service as a proxy to datasources db operations * Encrypt ds.SecureJsonData before calling SQLStore * Move ds cache code into ds service * Fix tlsmanager tests * Fix pluginproxy tests * Remove some securejsondata.GetEncryptedJsonData usages * Add pluginsettings.Service as a proxy for plugin settings db operations * Add AlertNotificationService as a proxy for alert notification db operations * Remove some securejsondata.GetEncryptedJsonData usages * Remove more securejsondata.GetEncryptedJsonData usages * Fix lint errors * Minor fixes * Remove encryption global functions usages from ngalert * Fix lint errors * Minor fixes * Minor fixes * Remove securejsondata.DecryptedValue usage * Refactor the refactor * Remove securejsondata.DecryptedValue usage * Move securejsondata to migrations package * Move securejsondata to migrations package * Minor fix * Fix integration test * Fix integration tests * Undo undesired changes * Fix tests * Add context.Context into encryption methods * Fix tests * Fix tests * Fix tests * Trigger CI * Fix test * Add names to params of encryption service interface * Remove bus from CacheServiceImpl * Add logging * Add keys to logger Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com> * Add missing key to logger Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com> * Undo changes in markdown files * Fix formatting * Add context to secrets service * Rename decryptSecureJsonData to decryptSecureJsonDataFn * Name args in GetDecryptedValueFn * Add template back to NewAlertmanagerNotifier * Copy GetDecryptedValueFn to ngalert * Add logging to pluginsettings * Fix pluginsettings test Co-authored-by: Tania B <yalyna.ts@gmail.com> Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
This commit is contained in:
co-authored by
Emil Tullstedt
Tania B
parent
da813877fb
commit
722c414fef
@@ -9,28 +9,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
bus.AddHandler("sql", GetAlertNotifications)
|
||||
bus.AddHandler("sql", CreateAlertNotificationCommand)
|
||||
bus.AddHandler("sql", UpdateAlertNotification)
|
||||
bus.AddHandler("sql", DeleteAlertNotification)
|
||||
bus.AddHandler("sql", GetAllAlertNotifications)
|
||||
bus.AddHandlerCtx("sql", GetOrCreateAlertNotificationState)
|
||||
bus.AddHandlerCtx("sql", SetAlertNotificationStateToCompleteCommand)
|
||||
bus.AddHandlerCtx("sql", SetAlertNotificationStateToPendingCommand)
|
||||
|
||||
bus.AddHandler("sql", GetAlertNotificationsWithUid)
|
||||
bus.AddHandler("sql", UpdateAlertNotificationWithUid)
|
||||
bus.AddHandler("sql", DeleteAlertNotificationWithUid)
|
||||
bus.AddHandler("sql", GetAlertNotificationsWithUidToSend)
|
||||
}
|
||||
|
||||
func DeleteAlertNotification(cmd *models.DeleteAlertNotificationCommand) error {
|
||||
func (ss *SQLStore) DeleteAlertNotification(cmd *models.DeleteAlertNotificationCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
sql := "DELETE FROM alert_notification WHERE alert_notification.org_id = ? AND alert_notification.id = ?"
|
||||
res, err := sess.Exec(sql, cmd.OrgId, cmd.Id)
|
||||
@@ -54,7 +37,7 @@ func DeleteAlertNotification(cmd *models.DeleteAlertNotificationCommand) error {
|
||||
})
|
||||
}
|
||||
|
||||
func DeleteAlertNotificationWithUid(cmd *models.DeleteAlertNotificationWithUidCommand) error {
|
||||
func (ss *SQLStore) DeleteAlertNotificationWithUid(cmd *models.DeleteAlertNotificationWithUidCommand) error {
|
||||
existingNotification := &models.GetAlertNotificationsWithUidQuery{OrgId: cmd.OrgId, Uid: cmd.Uid}
|
||||
if err := getAlertNotificationWithUidInternal(existingNotification, newSession(context.Background())); err != nil {
|
||||
return err
|
||||
@@ -76,7 +59,7 @@ func DeleteAlertNotificationWithUid(cmd *models.DeleteAlertNotificationWithUidCo
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAlertNotifications(query *models.GetAlertNotificationsQuery) error {
|
||||
func (ss *SQLStore) GetAlertNotifications(query *models.GetAlertNotificationsQuery) error {
|
||||
return getAlertNotificationInternal(query, newSession(context.Background()))
|
||||
}
|
||||
|
||||
@@ -106,11 +89,11 @@ func newAlertNotificationUidCacheKey(orgID, notificationId int64) string {
|
||||
return fmt.Sprintf("notification-uid-by-org-%d-and-id-%d", orgID, notificationId)
|
||||
}
|
||||
|
||||
func GetAlertNotificationsWithUid(query *models.GetAlertNotificationsWithUidQuery) error {
|
||||
func (ss *SQLStore) GetAlertNotificationsWithUid(query *models.GetAlertNotificationsWithUidQuery) error {
|
||||
return getAlertNotificationWithUidInternal(query, newSession(context.Background()))
|
||||
}
|
||||
|
||||
func GetAllAlertNotifications(query *models.GetAllAlertNotificationsQuery) error {
|
||||
func (ss *SQLStore) GetAllAlertNotifications(query *models.GetAllAlertNotificationsQuery) error {
|
||||
results := make([]*models.AlertNotification, 0)
|
||||
if err := x.Where("org_id = ?", query.OrgId).Asc("name").Find(&results); err != nil {
|
||||
return err
|
||||
@@ -120,7 +103,7 @@ func GetAllAlertNotifications(query *models.GetAllAlertNotificationsQuery) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAlertNotificationsWithUidToSend(query *models.GetAlertNotificationsWithUidToSendQuery) error {
|
||||
func (ss *SQLStore) GetAlertNotificationsWithUidToSend(query *models.GetAlertNotificationsWithUidToSendQuery) error {
|
||||
var sql bytes.Buffer
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
@@ -281,7 +264,7 @@ func getAlertNotificationWithUidInternal(query *models.GetAlertNotificationsWith
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateAlertNotificationCommand(cmd *models.CreateAlertNotificationCommand) error {
|
||||
func (ss *SQLStore) CreateAlertNotificationCommand(cmd *models.CreateAlertNotificationCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
if cmd.Uid == "" {
|
||||
uid, uidGenerationErr := generateNewAlertNotificationUid(sess, cmd.OrgId)
|
||||
@@ -337,7 +320,7 @@ func CreateAlertNotificationCommand(cmd *models.CreateAlertNotificationCommand)
|
||||
Name: cmd.Name,
|
||||
Type: cmd.Type,
|
||||
Settings: cmd.Settings,
|
||||
SecureSettings: securejsondata.GetEncryptedJsonData(cmd.SecureSettings),
|
||||
SecureSettings: cmd.EncryptedSecureSettings,
|
||||
SendReminder: cmd.SendReminder,
|
||||
DisableResolveMessage: cmd.DisableResolveMessage,
|
||||
Frequency: frequency,
|
||||
@@ -371,7 +354,7 @@ func generateNewAlertNotificationUid(sess *DBSession, orgId int64) (string, erro
|
||||
return "", models.ErrAlertNotificationFailedGenerateUniqueUid
|
||||
}
|
||||
|
||||
func UpdateAlertNotification(cmd *models.UpdateAlertNotificationCommand) error {
|
||||
func (ss *SQLStore) UpdateAlertNotification(cmd *models.UpdateAlertNotificationCommand) error {
|
||||
return inTransaction(func(sess *DBSession) (err error) {
|
||||
current := models.AlertNotification{}
|
||||
|
||||
@@ -402,7 +385,7 @@ func UpdateAlertNotification(cmd *models.UpdateAlertNotificationCommand) error {
|
||||
|
||||
current.Updated = time.Now()
|
||||
current.Settings = cmd.Settings
|
||||
current.SecureSettings = securejsondata.GetEncryptedJsonData(cmd.SecureSettings)
|
||||
current.SecureSettings = cmd.EncryptedSecureSettings
|
||||
current.Name = cmd.Name
|
||||
current.Type = cmd.Type
|
||||
current.IsDefault = cmd.IsDefault
|
||||
@@ -439,7 +422,7 @@ func UpdateAlertNotification(cmd *models.UpdateAlertNotificationCommand) error {
|
||||
})
|
||||
}
|
||||
|
||||
func UpdateAlertNotificationWithUid(cmd *models.UpdateAlertNotificationWithUidCommand) error {
|
||||
func (ss *SQLStore) UpdateAlertNotificationWithUid(cmd *models.UpdateAlertNotificationWithUidCommand) error {
|
||||
getAlertNotificationWithUidQuery := &models.GetAlertNotificationsWithUidQuery{OrgId: cmd.OrgId, Uid: cmd.Uid}
|
||||
|
||||
if err := getAlertNotificationWithUidInternal(getAlertNotificationWithUidQuery, newSession(context.Background())); err != nil {
|
||||
@@ -480,7 +463,7 @@ func UpdateAlertNotificationWithUid(cmd *models.UpdateAlertNotificationWithUidCo
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToCompleteCommand) error {
|
||||
func (ss *SQLStore) SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToCompleteCommand) error {
|
||||
return inTransactionCtx(ctx, func(sess *DBSession) error {
|
||||
version := cmd.Version
|
||||
var current models.AlertNotificationState
|
||||
@@ -509,7 +492,7 @@ func SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *models
|
||||
})
|
||||
}
|
||||
|
||||
func SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToPendingCommand) error {
|
||||
func (ss *SQLStore) SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToPendingCommand) error {
|
||||
return withDbSession(ctx, x, func(sess *DBSession) error {
|
||||
newVersion := cmd.Version + 1
|
||||
sql := `UPDATE alert_notification_state SET
|
||||
@@ -545,7 +528,7 @@ func SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *models.
|
||||
})
|
||||
}
|
||||
|
||||
func GetOrCreateAlertNotificationState(ctx context.Context, cmd *models.GetOrCreateNotificationStateQuery) error {
|
||||
func (ss *SQLStore) GetOrCreateAlertNotificationState(ctx context.Context, cmd *models.GetOrCreateNotificationStateQuery) error {
|
||||
return inTransactionCtx(ctx, func(sess *DBSession) error {
|
||||
nj := &models.AlertNotificationState{}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
@@ -17,7 +18,12 @@ import (
|
||||
|
||||
func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Convey("Testing Alert notification sql access", t, func() {
|
||||
InitTestDB(t)
|
||||
sqlStore := InitTestDB(t)
|
||||
|
||||
// Set up bus handlers
|
||||
bus.AddHandler("deleteAlertNotification", func(cmd *models.DeleteAlertNotificationCommand) error {
|
||||
return sqlStore.DeleteAlertNotification(cmd)
|
||||
})
|
||||
|
||||
Convey("Alert notification state", func() {
|
||||
var alertID int64 = 7
|
||||
@@ -29,7 +35,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
|
||||
Convey("Get no existing state should create a new state", func() {
|
||||
query := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID}
|
||||
err := GetOrCreateAlertNotificationState(context.Background(), query)
|
||||
err := sqlStore.GetOrCreateAlertNotificationState(context.Background(), query)
|
||||
So(err, ShouldBeNil)
|
||||
So(query.Result, ShouldNotBeNil)
|
||||
So(query.Result.State, ShouldEqual, "unknown")
|
||||
@@ -38,7 +44,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
|
||||
Convey("Get existing state should not create a new state", func() {
|
||||
query2 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID}
|
||||
err := GetOrCreateAlertNotificationState(context.Background(), query2)
|
||||
err := sqlStore.GetOrCreateAlertNotificationState(context.Background(), query2)
|
||||
So(err, ShouldBeNil)
|
||||
So(query2.Result, ShouldNotBeNil)
|
||||
So(query2.Result.Id, ShouldEqual, query.Result.Id)
|
||||
@@ -54,12 +60,12 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
AlertRuleStateUpdatedVersion: s.AlertRuleStateUpdatedVersion,
|
||||
}
|
||||
|
||||
err := SetAlertNotificationStateToPendingCommand(context.Background(), &cmd)
|
||||
err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd)
|
||||
So(err, ShouldBeNil)
|
||||
So(cmd.ResultVersion, ShouldEqual, 1)
|
||||
|
||||
query2 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID}
|
||||
err = GetOrCreateAlertNotificationState(context.Background(), query2)
|
||||
err = sqlStore.GetOrCreateAlertNotificationState(context.Background(), query2)
|
||||
So(err, ShouldBeNil)
|
||||
So(query2.Result.Version, ShouldEqual, 1)
|
||||
So(query2.Result.State, ShouldEqual, models.AlertNotificationStatePending)
|
||||
@@ -71,11 +77,11 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Id: s.Id,
|
||||
Version: cmd.ResultVersion,
|
||||
}
|
||||
err := SetAlertNotificationStateToCompleteCommand(context.Background(), &setStateCmd)
|
||||
err := sqlStore.SetAlertNotificationStateToCompleteCommand(context.Background(), &setStateCmd)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query3 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID}
|
||||
err = GetOrCreateAlertNotificationState(context.Background(), query3)
|
||||
err = sqlStore.GetOrCreateAlertNotificationState(context.Background(), query3)
|
||||
So(err, ShouldBeNil)
|
||||
So(query3.Result.Version, ShouldEqual, 2)
|
||||
So(query3.Result.State, ShouldEqual, models.AlertNotificationStateCompleted)
|
||||
@@ -89,11 +95,11 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Id: s.Id,
|
||||
Version: unknownVersion,
|
||||
}
|
||||
err := SetAlertNotificationStateToCompleteCommand(context.Background(), &cmd)
|
||||
err := sqlStore.SetAlertNotificationStateToCompleteCommand(context.Background(), &cmd)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query3 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID}
|
||||
err = GetOrCreateAlertNotificationState(context.Background(), query3)
|
||||
err = sqlStore.GetOrCreateAlertNotificationState(context.Background(), query3)
|
||||
So(err, ShouldBeNil)
|
||||
So(query3.Result.Version, ShouldEqual, unknownVersion+1)
|
||||
So(query3.Result.State, ShouldEqual, models.AlertNotificationStateCompleted)
|
||||
@@ -109,7 +115,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Version: s.Version,
|
||||
AlertRuleStateUpdatedVersion: s.AlertRuleStateUpdatedVersion,
|
||||
}
|
||||
err := SetAlertNotificationStateToPendingCommand(context.Background(), &cmd)
|
||||
err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd)
|
||||
So(err, ShouldEqual, models.ErrAlertNotificationStateVersionConflict)
|
||||
})
|
||||
|
||||
@@ -120,7 +126,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Version: s.Version,
|
||||
AlertRuleStateUpdatedVersion: 1000,
|
||||
}
|
||||
err := SetAlertNotificationStateToPendingCommand(context.Background(), &cmd)
|
||||
err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(cmd.ResultVersion, ShouldEqual, 1)
|
||||
@@ -134,7 +140,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Version: s.Version,
|
||||
AlertRuleStateUpdatedVersion: s.AlertRuleStateUpdatedVersion,
|
||||
}
|
||||
err := SetAlertNotificationStateToPendingCommand(context.Background(), &cmd)
|
||||
err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
@@ -150,7 +156,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Name: "email",
|
||||
}
|
||||
|
||||
err := GetAlertNotifications(cmd)
|
||||
err := sqlStore.GetAlertNotifications(cmd)
|
||||
So(err, ShouldBeNil)
|
||||
So(cmd.Result, ShouldBeNil)
|
||||
})
|
||||
@@ -165,14 +171,14 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
}
|
||||
|
||||
Convey("and missing frequency", func() {
|
||||
err := CreateAlertNotificationCommand(cmd)
|
||||
err := sqlStore.CreateAlertNotificationCommand(cmd)
|
||||
So(err, ShouldEqual, models.ErrNotificationFrequencyNotFound)
|
||||
})
|
||||
|
||||
Convey("invalid frequency", func() {
|
||||
cmd.Frequency = "invalid duration"
|
||||
|
||||
err := CreateAlertNotificationCommand(cmd)
|
||||
err := sqlStore.CreateAlertNotificationCommand(cmd)
|
||||
So(regexp.MustCompile(`^time: invalid duration "?invalid duration"?$`).MatchString(
|
||||
err.Error()), ShouldBeTrue)
|
||||
})
|
||||
@@ -187,7 +193,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Settings: simplejson.New(),
|
||||
}
|
||||
|
||||
err := CreateAlertNotificationCommand(cmd)
|
||||
err := sqlStore.CreateAlertNotificationCommand(cmd)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
updateCmd := &models.UpdateAlertNotificationCommand{
|
||||
@@ -196,14 +202,14 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
}
|
||||
|
||||
Convey("and missing frequency", func() {
|
||||
err := UpdateAlertNotification(updateCmd)
|
||||
err := sqlStore.UpdateAlertNotification(updateCmd)
|
||||
So(err, ShouldEqual, models.ErrNotificationFrequencyNotFound)
|
||||
})
|
||||
|
||||
Convey("invalid frequency", func() {
|
||||
updateCmd.Frequency = "invalid duration"
|
||||
|
||||
err := UpdateAlertNotification(updateCmd)
|
||||
err := sqlStore.UpdateAlertNotification(updateCmd)
|
||||
So(err, ShouldNotBeNil)
|
||||
So(regexp.MustCompile(`^time: invalid duration "?invalid duration"?$`).MatchString(
|
||||
err.Error()), ShouldBeTrue)
|
||||
@@ -220,7 +226,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Settings: simplejson.New(),
|
||||
}
|
||||
|
||||
err := CreateAlertNotificationCommand(cmd)
|
||||
err := sqlStore.CreateAlertNotificationCommand(cmd)
|
||||
So(err, ShouldBeNil)
|
||||
So(cmd.Result.Id, ShouldNotEqual, 0)
|
||||
So(cmd.Result.OrgId, ShouldNotEqual, 0)
|
||||
@@ -230,7 +236,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
So(cmd.Result.Uid, ShouldNotBeEmpty)
|
||||
|
||||
Convey("Cannot save Alert Notification with the same name", func() {
|
||||
err = CreateAlertNotificationCommand(cmd)
|
||||
err = sqlStore.CreateAlertNotificationCommand(cmd)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
Convey("Cannot save Alert Notification with the same name and another uid", func() {
|
||||
@@ -243,7 +249,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Settings: cmd.Settings,
|
||||
Uid: "notifier1",
|
||||
}
|
||||
err = CreateAlertNotificationCommand(anotherUidCmd)
|
||||
err = sqlStore.CreateAlertNotificationCommand(anotherUidCmd)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
Convey("Can save Alert Notification with another name and another uid", func() {
|
||||
@@ -256,7 +262,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Settings: cmd.Settings,
|
||||
Uid: "notifier2",
|
||||
}
|
||||
err = CreateAlertNotificationCommand(anotherUidCmd)
|
||||
err = sqlStore.CreateAlertNotificationCommand(anotherUidCmd)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
@@ -271,7 +277,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Settings: simplejson.New(),
|
||||
Id: cmd.Result.Id,
|
||||
}
|
||||
err := UpdateAlertNotification(newCmd)
|
||||
err := sqlStore.UpdateAlertNotification(newCmd)
|
||||
So(err, ShouldBeNil)
|
||||
So(newCmd.Result.Name, ShouldEqual, "NewName")
|
||||
So(newCmd.Result.Frequency, ShouldEqual, 60*time.Second)
|
||||
@@ -287,7 +293,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Settings: simplejson.New(),
|
||||
Id: cmd.Result.Id,
|
||||
}
|
||||
err := UpdateAlertNotification(newCmd)
|
||||
err := sqlStore.UpdateAlertNotification(newCmd)
|
||||
So(err, ShouldBeNil)
|
||||
So(newCmd.Result.SendReminder, ShouldBeFalse)
|
||||
})
|
||||
@@ -301,11 +307,11 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
|
||||
otherOrg := models.CreateAlertNotificationCommand{Name: "default", Type: "email", OrgId: 2, SendReminder: true, Frequency: "10s", Settings: simplejson.New()}
|
||||
|
||||
So(CreateAlertNotificationCommand(&cmd1), ShouldBeNil)
|
||||
So(CreateAlertNotificationCommand(&cmd2), ShouldBeNil)
|
||||
So(CreateAlertNotificationCommand(&cmd3), ShouldBeNil)
|
||||
So(CreateAlertNotificationCommand(&cmd4), ShouldBeNil)
|
||||
So(CreateAlertNotificationCommand(&otherOrg), ShouldBeNil)
|
||||
So(sqlStore.CreateAlertNotificationCommand(&cmd1), ShouldBeNil)
|
||||
So(sqlStore.CreateAlertNotificationCommand(&cmd2), ShouldBeNil)
|
||||
So(sqlStore.CreateAlertNotificationCommand(&cmd3), ShouldBeNil)
|
||||
So(sqlStore.CreateAlertNotificationCommand(&cmd4), ShouldBeNil)
|
||||
So(sqlStore.CreateAlertNotificationCommand(&otherOrg), ShouldBeNil)
|
||||
|
||||
Convey("search", func() {
|
||||
query := &models.GetAlertNotificationsWithUidToSendQuery{
|
||||
@@ -313,7 +319,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
OrgId: 1,
|
||||
}
|
||||
|
||||
err := GetAlertNotificationsWithUidToSend(query)
|
||||
err := sqlStore.GetAlertNotificationsWithUidToSend(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 3)
|
||||
})
|
||||
@@ -323,7 +329,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
OrgId: 1,
|
||||
}
|
||||
|
||||
err := GetAllAlertNotifications(query)
|
||||
err := sqlStore.GetAllAlertNotifications(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 4)
|
||||
So(query.Result[0].Name, ShouldEqual, cmd4.Name)
|
||||
@@ -337,7 +343,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
ss := InitTestDB(t)
|
||||
|
||||
notification := &models.CreateAlertNotificationCommand{Uid: "aNotificationUid", OrgId: 1, Name: "aNotificationUid"}
|
||||
err := CreateAlertNotificationCommand(notification)
|
||||
err := sqlStore.CreateAlertNotificationCommand(notification)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
byUidQuery := &models.GetAlertNotificationsWithUidQuery{
|
||||
@@ -345,7 +351,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
OrgId: notification.OrgId,
|
||||
}
|
||||
|
||||
notificationByUidErr := GetAlertNotificationsWithUid(byUidQuery)
|
||||
notificationByUidErr := sqlStore.GetAlertNotificationsWithUid(byUidQuery)
|
||||
So(notificationByUidErr, ShouldBeNil)
|
||||
|
||||
Convey("Can cache notification Uid", func() {
|
||||
@@ -410,7 +416,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Settings: simplejson.New(),
|
||||
Id: 1,
|
||||
}
|
||||
err := UpdateAlertNotification(updateCmd)
|
||||
err := sqlStore.UpdateAlertNotification(updateCmd)
|
||||
So(err, ShouldEqual, models.ErrAlertNotificationNotFound)
|
||||
|
||||
Convey("using UID", func() {
|
||||
@@ -425,7 +431,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Uid: "uid",
|
||||
NewUid: "newUid",
|
||||
}
|
||||
err := UpdateAlertNotificationWithUid(updateWithUidCmd)
|
||||
err := sqlStore.UpdateAlertNotificationWithUid(updateWithUidCmd)
|
||||
So(err, ShouldEqual, models.ErrAlertNotificationNotFound)
|
||||
})
|
||||
})
|
||||
@@ -439,25 +445,26 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Settings: simplejson.New(),
|
||||
}
|
||||
|
||||
err := CreateAlertNotificationCommand(cmd)
|
||||
err := sqlStore.CreateAlertNotificationCommand(cmd)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
deleteCmd := &models.DeleteAlertNotificationCommand{
|
||||
Id: cmd.Result.Id,
|
||||
OrgId: 1,
|
||||
}
|
||||
err = DeleteAlertNotification(deleteCmd)
|
||||
err = sqlStore.DeleteAlertNotification(deleteCmd)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("using UID", func() {
|
||||
err := CreateAlertNotificationCommand(cmd)
|
||||
err := sqlStore.CreateAlertNotificationCommand(cmd)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
deleteWithUidCmd := &models.DeleteAlertNotificationWithUidCommand{
|
||||
Uid: cmd.Result.Uid,
|
||||
OrgId: 1,
|
||||
}
|
||||
err = DeleteAlertNotificationWithUid(deleteWithUidCmd)
|
||||
|
||||
err = sqlStore.DeleteAlertNotificationWithUid(deleteWithUidCmd)
|
||||
So(err, ShouldBeNil)
|
||||
So(deleteWithUidCmd.DeletedAlertNotificationId, ShouldEqual, cmd.Result.Id)
|
||||
})
|
||||
@@ -468,7 +475,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Id: 1,
|
||||
OrgId: 1,
|
||||
}
|
||||
err := DeleteAlertNotification(deleteCmd)
|
||||
err := sqlStore.DeleteAlertNotification(deleteCmd)
|
||||
So(err, ShouldEqual, models.ErrAlertNotificationNotFound)
|
||||
|
||||
Convey("using UID", func() {
|
||||
@@ -476,7 +483,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
Uid: "uid",
|
||||
OrgId: 1,
|
||||
}
|
||||
err = DeleteAlertNotificationWithUid(deleteWithUidCmd)
|
||||
err = sqlStore.DeleteAlertNotificationWithUid(deleteWithUidCmd)
|
||||
So(err, ShouldEqual, models.ErrAlertNotificationNotFound)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -30,7 +31,7 @@ func TestDashboardSnapshotDBAccess(t *testing.T) {
|
||||
rawDashboard, err := dashboard.Encode()
|
||||
require.NoError(t, err)
|
||||
|
||||
encryptedDashboard, err := ossencryption.ProvideService().Encrypt(rawDashboard, setting.SecretKey)
|
||||
encryptedDashboard, err := ossencryption.ProvideService().Encrypt(context.Background(), rawDashboard, setting.SecretKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmd := models.CreateDashboardSnapshotCommand{
|
||||
@@ -51,6 +52,7 @@ func TestDashboardSnapshotDBAccess(t *testing.T) {
|
||||
assert.NotNil(t, query.Result)
|
||||
|
||||
decryptedDashboard, err := ossencryption.ProvideService().Decrypt(
|
||||
context.Background(),
|
||||
query.Result.DashboardEncrypted,
|
||||
setting.SecretKey,
|
||||
)
|
||||
@@ -132,6 +134,7 @@ func TestDashboardSnapshotDBAccess(t *testing.T) {
|
||||
|
||||
t.Run("Should have encrypted dashboard data", func(t *testing.T) {
|
||||
decryptedDashboard, err := ossencryption.ProvideService().Decrypt(
|
||||
context.Background(),
|
||||
cmd.Result.DashboardEncrypted,
|
||||
setting.SecretKey,
|
||||
)
|
||||
|
||||
@@ -5,49 +5,17 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/events"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
"github.com/grafana/grafana/pkg/events"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
bus.AddHandler("sql", GetDataSources)
|
||||
bus.AddHandler("sql", GetDataSourcesByType)
|
||||
bus.AddHandler("sql", GetDataSource)
|
||||
bus.AddHandler("sql", AddDataSource)
|
||||
bus.AddHandler("sql", DeleteDataSource)
|
||||
bus.AddHandler("sql", UpdateDataSource)
|
||||
bus.AddHandler("sql", GetDefaultDataSource)
|
||||
}
|
||||
|
||||
// GetDataSource returns a datasource by org_id and either uid (preferred), id, or name.
|
||||
// Zero values (0, or "") should be used for the parameters that will not be queried.
|
||||
func (ss *SQLStore) GetDataSource(uid string, id int64, name string, orgID int64) (*models.DataSource, error) {
|
||||
query := &models.GetDataSourceQuery{
|
||||
Id: id,
|
||||
Uid: uid,
|
||||
Name: name,
|
||||
OrgId: orgID,
|
||||
}
|
||||
|
||||
if err := GetDataSource(query); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return query.Result, nil
|
||||
}
|
||||
|
||||
// GetDataSource adds a datasource to the query model by querying by org_id as well as
|
||||
// either uid (preferred), id, or name and is added to the bus.
|
||||
func GetDataSource(query *models.GetDataSourceQuery) error {
|
||||
func (ss *SQLStore) GetDataSource(query *models.GetDataSourceQuery) error {
|
||||
metrics.MDBDataSourceQueryByID.Inc()
|
||||
if query.OrgId == 0 || (query.Id == 0 && len(query.Name) == 0 && len(query.Uid) == 0) {
|
||||
return models.ErrDataSourceIdentifierNotSet
|
||||
@@ -67,7 +35,7 @@ func GetDataSource(query *models.GetDataSourceQuery) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDataSources(query *models.GetDataSourcesQuery) error {
|
||||
func (ss *SQLStore) GetDataSources(query *models.GetDataSourcesQuery) error {
|
||||
var sess *xorm.Session
|
||||
if query.DataSourceLimit <= 0 {
|
||||
sess = x.Where("org_id=?", query.OrgId).Asc("name")
|
||||
@@ -80,7 +48,7 @@ func GetDataSources(query *models.GetDataSourcesQuery) error {
|
||||
}
|
||||
|
||||
// GetDataSourcesByType returns all datasources for a given type or an error if the specified type is an empty string
|
||||
func GetDataSourcesByType(query *models.GetDataSourcesByTypeQuery) error {
|
||||
func (ss *SQLStore) GetDataSourcesByType(query *models.GetDataSourcesByTypeQuery) error {
|
||||
if query.Type == "" {
|
||||
return fmt.Errorf("datasource type cannot be empty")
|
||||
}
|
||||
@@ -90,7 +58,7 @@ func GetDataSourcesByType(query *models.GetDataSourcesByTypeQuery) error {
|
||||
}
|
||||
|
||||
// GetDefaultDataSource is used to get the default datasource of organization
|
||||
func GetDefaultDataSource(query *models.GetDefaultDataSourceQuery) error {
|
||||
func (ss *SQLStore) GetDefaultDataSource(query *models.GetDefaultDataSourceQuery) error {
|
||||
datasource := models.DataSource{}
|
||||
|
||||
exists, err := x.Where("org_id=? AND is_default=?", query.OrgId, true).Get(&datasource)
|
||||
@@ -103,26 +71,9 @@ func GetDefaultDataSource(query *models.GetDefaultDataSourceQuery) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteDataSource deletes a datasource by org_id and either uid (preferred), id, or name.
|
||||
// Zero values (0, or "") should be used for the parameters that will not be queried.
|
||||
func (ss *SQLStore) DeleteDataSource(uid string, id int64, name string, orgID int64) (int64, error) {
|
||||
cmd := &models.DeleteDataSourceCommand{
|
||||
ID: id,
|
||||
UID: uid,
|
||||
Name: name,
|
||||
OrgID: orgID,
|
||||
}
|
||||
|
||||
if err := DeleteDataSource(cmd); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return cmd.DeletedDatasourcesCount, nil
|
||||
}
|
||||
|
||||
// DeleteDataSource removes a datasource by org_id as well as either uid (preferred), id, or name
|
||||
// and is added to the bus.
|
||||
func DeleteDataSource(cmd *models.DeleteDataSourceCommand) error {
|
||||
func (ss *SQLStore) DeleteDataSource(cmd *models.DeleteDataSourceCommand) error {
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
makeQuery := func(sql string, p ...interface{}) {
|
||||
@@ -159,7 +110,7 @@ func DeleteDataSource(cmd *models.DeleteDataSourceCommand) error {
|
||||
})
|
||||
}
|
||||
|
||||
func AddDataSource(cmd *models.AddDataSourceCommand) error {
|
||||
func (ss *SQLStore) AddDataSource(cmd *models.AddDataSourceCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
existing := models.DataSource{OrgId: cmd.OrgId, Name: cmd.Name}
|
||||
has, _ := sess.Get(&existing)
|
||||
@@ -195,7 +146,7 @@ func AddDataSource(cmd *models.AddDataSourceCommand) error {
|
||||
BasicAuthPassword: cmd.BasicAuthPassword,
|
||||
WithCredentials: cmd.WithCredentials,
|
||||
JsonData: cmd.JsonData,
|
||||
SecureJsonData: securejsondata.GetEncryptedJsonData(cmd.SecureJsonData),
|
||||
SecureJsonData: cmd.EncryptedSecureJsonData,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
Version: 1,
|
||||
@@ -237,7 +188,7 @@ func updateIsDefaultFlag(ds *models.DataSource, sess *DBSession) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateDataSource(cmd *models.UpdateDataSourceCommand) error {
|
||||
func (ss *SQLStore) UpdateDataSource(cmd *models.UpdateDataSourceCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
if cmd.JsonData == nil {
|
||||
cmd.JsonData = simplejson.New()
|
||||
@@ -259,7 +210,7 @@ func UpdateDataSource(cmd *models.UpdateDataSourceCommand) error {
|
||||
BasicAuthPassword: cmd.BasicAuthPassword,
|
||||
WithCredentials: cmd.WithCredentials,
|
||||
JsonData: cmd.JsonData,
|
||||
SecureJsonData: securejsondata.GetEncryptedJsonData(cmd.SecureJsonData),
|
||||
SecureJsonData: cmd.EncryptedSecureJsonData,
|
||||
Updated: time.Now(),
|
||||
ReadOnly: cmd.ReadOnly,
|
||||
Version: cmd.Version + 1,
|
||||
|
||||
@@ -33,13 +33,13 @@ func TestDataAccess(t *testing.T) {
|
||||
Url: "http://test",
|
||||
}
|
||||
|
||||
initDatasource := func() *models.DataSource {
|
||||
initDatasource := func(sqlStore *SQLStore) *models.DataSource {
|
||||
cmd := defaultAddDatasourceCommand
|
||||
err := AddDataSource(&cmd)
|
||||
err := sqlStore.AddDataSource(&cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||
err = GetDataSources(&query)
|
||||
err = sqlStore.GetDataSources(&query)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(query.Result))
|
||||
|
||||
@@ -48,9 +48,9 @@ func TestDataAccess(t *testing.T) {
|
||||
|
||||
t.Run("AddDataSource", func(t *testing.T) {
|
||||
t.Run("Can add datasource", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
sqlStore := InitTestDB(t)
|
||||
|
||||
err := AddDataSource(&models.AddDataSourceCommand{
|
||||
err := sqlStore.AddDataSource(&models.AddDataSourceCommand{
|
||||
OrgId: 10,
|
||||
Name: "laban",
|
||||
Type: models.DS_GRAPHITE,
|
||||
@@ -62,7 +62,7 @@ func TestDataAccess(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||
err = GetDataSources(&query)
|
||||
err = sqlStore.GetDataSources(&query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(query.Result))
|
||||
@@ -74,26 +74,26 @@ func TestDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("generates uid if not specified", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
require.NotEmpty(t, ds.Uid)
|
||||
})
|
||||
|
||||
t.Run("fails to insert ds with same uid", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
sqlStore := InitTestDB(t)
|
||||
cmd1 := defaultAddDatasourceCommand
|
||||
cmd2 := defaultAddDatasourceCommand
|
||||
cmd1.Uid = "test"
|
||||
cmd2.Uid = "test"
|
||||
err := AddDataSource(&cmd1)
|
||||
err := sqlStore.AddDataSource(&cmd1)
|
||||
require.NoError(t, err)
|
||||
err = AddDataSource(&cmd2)
|
||||
err = sqlStore.AddDataSource(&cmd2)
|
||||
require.Error(t, err)
|
||||
require.IsType(t, models.ErrDataSourceUidExists, err)
|
||||
})
|
||||
|
||||
t.Run("fires an event when the datasource is added", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
sqlStore := InitTestDB(t)
|
||||
|
||||
var created *events.DataSourceCreated
|
||||
bus.AddEventListener(func(e *events.DataSourceCreated) error {
|
||||
@@ -101,7 +101,7 @@ func TestDataAccess(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
|
||||
err := AddDataSource(&defaultAddDatasourceCommand)
|
||||
err := sqlStore.AddDataSource(&defaultAddDatasourceCommand)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Eventually(t, func() bool {
|
||||
@@ -109,7 +109,7 @@ func TestDataAccess(t *testing.T) {
|
||||
}, time.Second, time.Millisecond)
|
||||
|
||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||
err = GetDataSources(&query)
|
||||
err = sqlStore.GetDataSources(&query)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(query.Result))
|
||||
|
||||
@@ -122,34 +122,34 @@ func TestDataAccess(t *testing.T) {
|
||||
|
||||
t.Run("UpdateDataSource", func(t *testing.T) {
|
||||
t.Run("updates datasource with version", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
cmd := defaultUpdateDatasourceCommand
|
||||
cmd.Id = ds.Id
|
||||
cmd.Version = ds.Version
|
||||
err := UpdateDataSource(&cmd)
|
||||
err := sqlStore.UpdateDataSource(&cmd)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("does not overwrite Uid if not specified", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
require.NotEmpty(t, ds.Uid)
|
||||
|
||||
cmd := defaultUpdateDatasourceCommand
|
||||
cmd.Id = ds.Id
|
||||
err := UpdateDataSource(&cmd)
|
||||
err := sqlStore.UpdateDataSource(&cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
query := models.GetDataSourceQuery{Id: ds.Id, OrgId: 10}
|
||||
err = GetDataSource(&query)
|
||||
err = sqlStore.GetDataSource(&query)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ds.Uid, query.Result.Uid)
|
||||
})
|
||||
|
||||
t.Run("prevents update if version changed", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
|
||||
cmd := models.UpdateDataSourceCommand{
|
||||
Id: ds.Id,
|
||||
@@ -163,16 +163,16 @@ func TestDataAccess(t *testing.T) {
|
||||
// Make a copy as UpdateDataSource modifies it
|
||||
cmd2 := cmd
|
||||
|
||||
err := UpdateDataSource(&cmd)
|
||||
err := sqlStore.UpdateDataSource(&cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = UpdateDataSource(&cmd2)
|
||||
err = sqlStore.UpdateDataSource(&cmd2)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("updates ds without version specified", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
|
||||
cmd := &models.UpdateDataSourceCommand{
|
||||
Id: ds.Id,
|
||||
@@ -183,13 +183,13 @@ func TestDataAccess(t *testing.T) {
|
||||
Url: "http://test",
|
||||
}
|
||||
|
||||
err := UpdateDataSource(cmd)
|
||||
err := sqlStore.UpdateDataSource(cmd)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("updates ds without higher version", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
|
||||
cmd := &models.UpdateDataSourceCommand{
|
||||
Id: ds.Id,
|
||||
@@ -201,34 +201,34 @@ func TestDataAccess(t *testing.T) {
|
||||
Version: 90000,
|
||||
}
|
||||
|
||||
err := UpdateDataSource(cmd)
|
||||
err := sqlStore.UpdateDataSource(cmd)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("DeleteDataSourceById", func(t *testing.T) {
|
||||
t.Run("can delete datasource", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
|
||||
err := DeleteDataSource(&models.DeleteDataSourceCommand{ID: ds.Id, OrgID: ds.OrgId})
|
||||
err := sqlStore.DeleteDataSource(&models.DeleteDataSourceCommand{ID: ds.Id, OrgID: ds.OrgId})
|
||||
require.NoError(t, err)
|
||||
|
||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||
err = GetDataSources(&query)
|
||||
err = sqlStore.GetDataSources(&query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 0, len(query.Result))
|
||||
})
|
||||
|
||||
t.Run("Can not delete datasource with wrong orgId", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
|
||||
err := DeleteDataSource(&models.DeleteDataSourceCommand{ID: ds.Id, OrgID: 123123})
|
||||
err := sqlStore.DeleteDataSource(&models.DeleteDataSourceCommand{ID: ds.Id, OrgID: 123123})
|
||||
require.NoError(t, err)
|
||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||
err = GetDataSources(&query)
|
||||
err = sqlStore.GetDataSources(&query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(query.Result))
|
||||
@@ -236,8 +236,8 @@ func TestDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("fires an event when the datasource is deleted", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
|
||||
var deleted *events.DataSourceDeleted
|
||||
bus.AddEventListener(func(e *events.DataSourceDeleted) error {
|
||||
@@ -245,7 +245,7 @@ func TestDataAccess(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
|
||||
err := DeleteDataSource(&models.DeleteDataSourceCommand{ID: ds.Id, UID: "nisse-uid", Name: "nisse", OrgID: 123123})
|
||||
err := sqlStore.DeleteDataSource(&models.DeleteDataSourceCommand{ID: ds.Id, UID: "nisse-uid", Name: "nisse", OrgID: 123123})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Eventually(t, func() bool {
|
||||
@@ -259,14 +259,14 @@ func TestDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("DeleteDataSourceByName", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
ds := initDatasource()
|
||||
sqlStore := InitTestDB(t)
|
||||
ds := initDatasource(sqlStore)
|
||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||
|
||||
err := DeleteDataSource(&models.DeleteDataSourceCommand{Name: ds.Name, OrgID: ds.OrgId})
|
||||
err := sqlStore.DeleteDataSource(&models.DeleteDataSourceCommand{Name: ds.Name, OrgID: ds.OrgId})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = GetDataSources(&query)
|
||||
err = sqlStore.GetDataSources(&query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 0, len(query.Result))
|
||||
@@ -274,10 +274,10 @@ func TestDataAccess(t *testing.T) {
|
||||
|
||||
t.Run("GetDataSources", func(t *testing.T) {
|
||||
t.Run("Number of data sources returned limited to 6 per organization", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
sqlStore := InitTestDB(t)
|
||||
datasourceLimit := 6
|
||||
for i := 0; i < datasourceLimit+1; i++ {
|
||||
err := AddDataSource(&models.AddDataSourceCommand{
|
||||
err := sqlStore.AddDataSource(&models.AddDataSourceCommand{
|
||||
OrgId: 10,
|
||||
Name: "laban" + strconv.Itoa(i),
|
||||
Type: models.DS_GRAPHITE,
|
||||
@@ -290,17 +290,17 @@ func TestDataAccess(t *testing.T) {
|
||||
}
|
||||
query := models.GetDataSourcesQuery{OrgId: 10, DataSourceLimit: datasourceLimit}
|
||||
|
||||
err := GetDataSources(&query)
|
||||
err := sqlStore.GetDataSources(&query)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, datasourceLimit, len(query.Result))
|
||||
})
|
||||
|
||||
t.Run("No limit should be applied on the returned data sources if the limit is not set", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
sqlStore := InitTestDB(t)
|
||||
numberOfDatasource := 5100
|
||||
for i := 0; i < numberOfDatasource; i++ {
|
||||
err := AddDataSource(&models.AddDataSourceCommand{
|
||||
err := sqlStore.AddDataSource(&models.AddDataSourceCommand{
|
||||
OrgId: 10,
|
||||
Name: "laban" + strconv.Itoa(i),
|
||||
Type: models.DS_GRAPHITE,
|
||||
@@ -313,17 +313,17 @@ func TestDataAccess(t *testing.T) {
|
||||
}
|
||||
query := models.GetDataSourcesQuery{OrgId: 10}
|
||||
|
||||
err := GetDataSources(&query)
|
||||
err := sqlStore.GetDataSources(&query)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, numberOfDatasource, len(query.Result))
|
||||
})
|
||||
|
||||
t.Run("No limit should be applied on the returned data sources if the limit is negative", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
sqlStore := InitTestDB(t)
|
||||
numberOfDatasource := 5100
|
||||
for i := 0; i < numberOfDatasource; i++ {
|
||||
err := AddDataSource(&models.AddDataSourceCommand{
|
||||
err := sqlStore.AddDataSource(&models.AddDataSourceCommand{
|
||||
OrgId: 10,
|
||||
Name: "laban" + strconv.Itoa(i),
|
||||
Type: models.DS_GRAPHITE,
|
||||
@@ -336,7 +336,7 @@ func TestDataAccess(t *testing.T) {
|
||||
}
|
||||
query := models.GetDataSourcesQuery{OrgId: 10, DataSourceLimit: -1}
|
||||
|
||||
err := GetDataSources(&query)
|
||||
err := sqlStore.GetDataSources(&query)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, numberOfDatasource, len(query.Result))
|
||||
@@ -345,9 +345,9 @@ func TestDataAccess(t *testing.T) {
|
||||
|
||||
t.Run("GetDataSourcesByType", func(t *testing.T) {
|
||||
t.Run("Only returns datasources of specified type", func(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
sqlStore := InitTestDB(t)
|
||||
|
||||
err := AddDataSource(&models.AddDataSourceCommand{
|
||||
err := sqlStore.AddDataSource(&models.AddDataSourceCommand{
|
||||
OrgId: 10,
|
||||
Name: "Elasticsearch",
|
||||
Type: models.DS_ES,
|
||||
@@ -358,7 +358,7 @@ func TestDataAccess(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = AddDataSource(&models.AddDataSourceCommand{
|
||||
err = sqlStore.AddDataSource(&models.AddDataSourceCommand{
|
||||
OrgId: 10,
|
||||
Name: "Graphite",
|
||||
Type: models.DS_GRAPHITE,
|
||||
@@ -371,16 +371,18 @@ func TestDataAccess(t *testing.T) {
|
||||
|
||||
query := models.GetDataSourcesByTypeQuery{Type: models.DS_ES}
|
||||
|
||||
err = GetDataSourcesByType(&query)
|
||||
err = sqlStore.GetDataSourcesByType(&query)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(query.Result))
|
||||
})
|
||||
|
||||
t.Run("Returns an error if no type specified", func(t *testing.T) {
|
||||
sqlStore := InitTestDB(t)
|
||||
|
||||
query := models.GetDataSourcesByTypeQuery{}
|
||||
|
||||
err := GetDataSourcesByType(&query)
|
||||
err := sqlStore.GetDataSourcesByType(&query)
|
||||
|
||||
require.Error(t, err)
|
||||
})
|
||||
@@ -391,6 +393,8 @@ func TestGetDefaultDataSource(t *testing.T) {
|
||||
InitTestDB(t)
|
||||
|
||||
t.Run("should return error if there is no default datasource", func(t *testing.T) {
|
||||
sqlStore := InitTestDB(t)
|
||||
|
||||
cmd := models.AddDataSourceCommand{
|
||||
OrgId: 10,
|
||||
Name: "nisse",
|
||||
@@ -399,16 +403,18 @@ func TestGetDefaultDataSource(t *testing.T) {
|
||||
Url: "http://test",
|
||||
}
|
||||
|
||||
err := AddDataSource(&cmd)
|
||||
err := sqlStore.AddDataSource(&cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
query := models.GetDefaultDataSourceQuery{OrgId: 10}
|
||||
err = GetDefaultDataSource(&query)
|
||||
err = sqlStore.GetDefaultDataSource(&query)
|
||||
require.Error(t, err)
|
||||
assert.True(t, errors.Is(err, models.ErrDataSourceNotFound))
|
||||
})
|
||||
|
||||
t.Run("should return default datasource if exists", func(t *testing.T) {
|
||||
sqlStore := InitTestDB(t)
|
||||
|
||||
cmd := models.AddDataSourceCommand{
|
||||
OrgId: 10,
|
||||
Name: "default datasource",
|
||||
@@ -418,18 +424,19 @@ func TestGetDefaultDataSource(t *testing.T) {
|
||||
IsDefault: true,
|
||||
}
|
||||
|
||||
err := AddDataSource(&cmd)
|
||||
err := sqlStore.AddDataSource(&cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
query := models.GetDefaultDataSourceQuery{OrgId: 10}
|
||||
err = GetDefaultDataSource(&query)
|
||||
err = sqlStore.GetDefaultDataSource(&query)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "default datasource", query.Result.Name)
|
||||
})
|
||||
|
||||
t.Run("should not return default datasource of other organisation", func(t *testing.T) {
|
||||
sqlStore := InitTestDB(t)
|
||||
query := models.GetDefaultDataSourceQuery{OrgId: 1}
|
||||
err := GetDefaultDataSource(&query)
|
||||
err := sqlStore.GetDefaultDataSource(&query)
|
||||
require.Error(t, err)
|
||||
assert.True(t, errors.Is(err, models.ErrDataSourceNotFound))
|
||||
})
|
||||
|
||||
@@ -8,23 +8,21 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/alertmanager/pkg/labels"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/prometheus/alertmanager/pkg/labels"
|
||||
)
|
||||
|
||||
type notificationChannel struct {
|
||||
ID int64 `xorm:"id"`
|
||||
OrgID int64 `xorm:"org_id"`
|
||||
Uid string `xorm:"uid"`
|
||||
Name string `xorm:"name"`
|
||||
Type string `xorm:"type"`
|
||||
DisableResolveMessage bool `xorm:"disable_resolve_message"`
|
||||
IsDefault bool `xorm:"is_default"`
|
||||
Settings *simplejson.Json `xorm:"settings"`
|
||||
SecureSettings securejsondata.SecureJsonData `xorm:"secure_settings"`
|
||||
ID int64 `xorm:"id"`
|
||||
OrgID int64 `xorm:"org_id"`
|
||||
Uid string `xorm:"uid"`
|
||||
Name string `xorm:"name"`
|
||||
Type string `xorm:"type"`
|
||||
DisableResolveMessage bool `xorm:"disable_resolve_message"`
|
||||
IsDefault bool `xorm:"is_default"`
|
||||
Settings *simplejson.Json `xorm:"settings"`
|
||||
SecureSettings SecureJsonData `xorm:"secure_settings"`
|
||||
}
|
||||
|
||||
// channelsPerOrg maps notification channels per organisation
|
||||
@@ -332,7 +330,7 @@ func (m *migration) generateChannelUID() (string, bool) {
|
||||
// Some settings were migrated from settings to secure settings in between.
|
||||
// See https://grafana.com/docs/grafana/latest/installation/upgrading/#ensure-encryption-of-existing-alert-notification-channel-secrets.
|
||||
// migrateSettingsToSecureSettings takes care of that.
|
||||
func migrateSettingsToSecureSettings(chanType string, settings *simplejson.Json, secureSettings securejsondata.SecureJsonData) (*simplejson.Json, map[string]string, error) {
|
||||
func migrateSettingsToSecureSettings(chanType string, settings *simplejson.Json, secureSettings SecureJsonData) (*simplejson.Json, map[string]string, error) {
|
||||
keys := []string{}
|
||||
switch chanType {
|
||||
case "slack":
|
||||
@@ -413,7 +411,7 @@ type amConfigsPerOrg = map[int64]*PostableUserConfig
|
||||
func (c *PostableUserConfig) EncryptSecureSettings() error {
|
||||
for _, r := range c.AlertmanagerConfig.Receivers {
|
||||
for _, gr := range r.GrafanaManagedReceivers {
|
||||
encryptedData := securejsondata.GetEncryptedJsonData(gr.SecureSettings)
|
||||
encryptedData := GetEncryptedJsonData(gr.SecureSettings)
|
||||
for k, v := range encryptedData {
|
||||
gr.SecureSettings[k] = base64.StdEncoding.EncodeToString(v)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package ualert
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
// SecureJsonData is used to store encrypted data (for example in data_source table). Only values are separately
|
||||
// encrypted.
|
||||
type SecureJsonData map[string][]byte
|
||||
|
||||
// DecryptedValue returns single decrypted value from SecureJsonData. Similar to normal map access second return value
|
||||
// is true if the key exists and false if not.
|
||||
func (s SecureJsonData) DecryptedValue(key string) (string, bool) {
|
||||
if value, ok := s[key]; ok {
|
||||
decryptedData, err := util.Decrypt(value, setting.SecretKey)
|
||||
if err != nil {
|
||||
log.Fatalf(4, err.Error())
|
||||
}
|
||||
return string(decryptedData), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Decrypt returns map of the same type but where the all the values are decrypted. Opposite of what
|
||||
// GetEncryptedJsonData is doing.
|
||||
func (s SecureJsonData) Decrypt() map[string]string {
|
||||
decrypted := make(map[string]string)
|
||||
for key, data := range s {
|
||||
decryptedData, err := util.Decrypt(data, setting.SecretKey)
|
||||
if err != nil {
|
||||
log.Fatalf(4, err.Error())
|
||||
}
|
||||
|
||||
decrypted[key] = string(decryptedData)
|
||||
}
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// GetEncryptedJsonData returns map where all keys are encrypted.
|
||||
func GetEncryptedJsonData(sjd map[string]string) SecureJsonData {
|
||||
encrypted := make(SecureJsonData)
|
||||
for key, data := range sjd {
|
||||
encryptedData, err := util.Encrypt([]byte(data), setting.SecretKey)
|
||||
if err != nil {
|
||||
log.Fatalf(4, err.Error())
|
||||
}
|
||||
|
||||
encrypted[key] = encryptedData
|
||||
}
|
||||
return encrypted
|
||||
}
|
||||
@@ -3,18 +3,9 @@ package sqlstore
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
func init() {
|
||||
bus.AddHandler("sql", GetPluginSettingById)
|
||||
bus.AddHandler("sql", UpdatePluginSetting)
|
||||
bus.AddHandler("sql", UpdatePluginSettingVersion)
|
||||
}
|
||||
|
||||
func (ss *SQLStore) GetPluginSettings(orgID int64) ([]*models.PluginSettingInfoDTO, error) {
|
||||
sql := `SELECT org_id, plugin_id, enabled, pinned, plugin_version
|
||||
FROM plugin_setting `
|
||||
@@ -33,7 +24,7 @@ func (ss *SQLStore) GetPluginSettings(orgID int64) ([]*models.PluginSettingInfoD
|
||||
return rslt, nil
|
||||
}
|
||||
|
||||
func GetPluginSettingById(query *models.GetPluginSettingByIdQuery) error {
|
||||
func (ss *SQLStore) GetPluginSettingById(query *models.GetPluginSettingByIdQuery) error {
|
||||
pluginSetting := models.PluginSetting{OrgId: query.OrgId, PluginId: query.PluginId}
|
||||
has, err := x.Get(&pluginSetting)
|
||||
if err != nil {
|
||||
@@ -45,9 +36,7 @@ func GetPluginSettingById(query *models.GetPluginSettingByIdQuery) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdatePluginSetting(cmd *models.UpdatePluginSettingCmd) error {
|
||||
encryptedJsonData := securejsondata.GetEncryptedJsonData(cmd.SecureJsonData)
|
||||
|
||||
func (ss *SQLStore) UpdatePluginSetting(cmd *models.UpdatePluginSettingCmd) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
var pluginSetting models.PluginSetting
|
||||
|
||||
@@ -65,7 +54,7 @@ func UpdatePluginSetting(cmd *models.UpdatePluginSettingCmd) error {
|
||||
Pinned: cmd.Pinned,
|
||||
JsonData: cmd.JsonData,
|
||||
PluginVersion: cmd.PluginVersion,
|
||||
SecureJsonData: encryptedJsonData,
|
||||
SecureJsonData: cmd.EncryptedSecureJsonData,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
}
|
||||
@@ -81,7 +70,7 @@ func UpdatePluginSetting(cmd *models.UpdatePluginSettingCmd) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for key, encryptedData := range encryptedJsonData {
|
||||
for key, encryptedData := range cmd.EncryptedSecureJsonData {
|
||||
pluginSetting.SecureJsonData[key] = encryptedData
|
||||
}
|
||||
|
||||
@@ -105,7 +94,7 @@ func UpdatePluginSetting(cmd *models.UpdatePluginSettingCmd) error {
|
||||
})
|
||||
}
|
||||
|
||||
func UpdatePluginSettingVersion(cmd *models.UpdatePluginSettingVersionCmd) error {
|
||||
func (ss *SQLStore) UpdatePluginSettingVersion(cmd *models.UpdatePluginSettingVersionCmd) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
_, err := sess.Exec("UPDATE plugin_setting SET plugin_version=? WHERE org_id=? AND plugin_id=?", cmd.PluginVersion, cmd.OrgId, cmd.PluginId)
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user