grafana/pkg/services/alerting/store_notification.go

595 lines
18 KiB
Go
Raw Normal View History

package alerting
2016-06-13 09:39:00 -05:00
import (
"bytes"
"context"
2018-09-28 04:17:03 -05:00
"errors"
"fmt"
"strings"
"time"
2016-06-13 09:39:00 -05:00
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/alerting/models"
2018-12-14 03:53:50 -06:00
"github.com/grafana/grafana/pkg/util"
2016-06-13 09:39:00 -05:00
)
type AlertNotificationStore interface {
DeleteAlertNotification(ctx context.Context, cmd *models.DeleteAlertNotificationCommand) error
DeleteAlertNotificationWithUid(ctx context.Context, cmd *models.DeleteAlertNotificationWithUidCommand) error
GetAlertNotifications(ctx context.Context, query *models.GetAlertNotificationsQuery) (*models.AlertNotification, error)
GetAlertNotificationUidWithId(ctx context.Context, query *models.GetAlertNotificationUidQuery) (string, error)
GetAlertNotificationsWithUid(ctx context.Context, query *models.GetAlertNotificationsWithUidQuery) (*models.AlertNotification, error)
GetAllAlertNotifications(ctx context.Context, query *models.GetAllAlertNotificationsQuery) ([]*models.AlertNotification, error)
GetAlertNotificationsWithUidToSend(ctx context.Context, query *models.GetAlertNotificationsWithUidToSendQuery) ([]*models.AlertNotification, error)
CreateAlertNotificationCommand(ctx context.Context, cmd *models.CreateAlertNotificationCommand) (*models.AlertNotification, error)
UpdateAlertNotification(ctx context.Context, cmd *models.UpdateAlertNotificationCommand) (*models.AlertNotification, error)
UpdateAlertNotificationWithUid(ctx context.Context, cmd *models.UpdateAlertNotificationWithUidCommand) (*models.AlertNotification, error)
SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToCompleteCommand) error
SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToPendingCommand) error
GetOrCreateAlertNotificationState(ctx context.Context, cmd *models.GetOrCreateNotificationStateQuery) (*models.AlertNotificationState, error)
}
// timeNow makes it possible to test usage of time
var timeNow = time.Now
func (ss *sqlStore) DeleteAlertNotification(ctx context.Context, cmd *models.DeleteAlertNotificationCommand) error {
return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
sql := "DELETE FROM alert_notification WHERE alert_notification.org_id = ? AND alert_notification.id = ?"
res, err := sess.Exec(sql, cmd.OrgID, cmd.ID)
if err != nil {
return err
}
rowsAffected, err := res.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
return models.ErrAlertNotificationNotFound
}
if _, err := sess.Exec("DELETE FROM alert_notification_state WHERE alert_notification_state.org_id = ? AND alert_notification_state.notifier_id = ?", cmd.OrgID, cmd.ID); err != nil {
return err
}
return nil
})
2016-06-13 09:39:00 -05:00
}
func (ss *sqlStore) DeleteAlertNotificationWithUid(ctx context.Context, cmd *models.DeleteAlertNotificationWithUidCommand) (err error) {
var res *models.AlertNotification
if err = ss.db.WithDbSession(ctx, func(sess *db.Session) error {
existingNotification := &models.GetAlertNotificationsWithUidQuery{OrgID: cmd.OrgID, UID: cmd.UID}
res, err = getAlertNotificationWithUidInternal(ctx, existingNotification, sess)
return err
}); err != nil {
2018-12-20 04:45:18 -06:00
return err
2018-12-14 03:53:50 -06:00
}
if res == nil {
return models.ErrAlertNotificationNotFound
}
cmd.DeletedAlertNotificationID = res.ID
deleteCommand := &models.DeleteAlertNotificationCommand{
ID: res.ID,
OrgID: res.OrgID,
2018-12-14 03:53:50 -06:00
}
return ss.DeleteAlertNotification(ctx, deleteCommand)
2018-12-14 03:53:50 -06:00
}
func (ss *sqlStore) GetAlertNotifications(ctx context.Context, query *models.GetAlertNotificationsQuery) (res *models.AlertNotification, err error) {
err = ss.db.WithDbSession(ctx, func(sess *db.Session) error {
res, err = getAlertNotificationInternal(ctx, query, sess)
return err
})
return res, err
}
func (ss *sqlStore) GetAlertNotificationUidWithId(ctx context.Context, query *models.GetAlertNotificationUidQuery) (res string, err error) {
cacheKey := newAlertNotificationUidCacheKey(query.OrgID, query.ID)
if cached, found := ss.cache.Get(cacheKey); found {
return cached.(string), nil
}
if err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
res, err = getAlertNotificationUidInternal(ctx, query, sess)
return err
}); err != nil {
return "", err
}
ss.cache.Set(cacheKey, res, -1) // Infinite, never changes
return res, nil
}
func newAlertNotificationUidCacheKey(orgID, notificationId int64) string {
return fmt.Sprintf("notification-uid-by-org-%d-and-id-%d", orgID, notificationId)
}
func (ss *sqlStore) GetAlertNotificationsWithUid(ctx context.Context, query *models.GetAlertNotificationsWithUidQuery) (res *models.AlertNotification, err error) {
err = ss.db.WithDbSession(ctx, func(sess *db.Session) error {
res, err = getAlertNotificationWithUidInternal(ctx, query, sess)
return err
})
return res, err
2018-12-14 03:53:50 -06:00
}
func (ss *sqlStore) GetAllAlertNotifications(ctx context.Context, query *models.GetAllAlertNotificationsQuery) (res []*models.AlertNotification, err error) {
res = make([]*models.AlertNotification, 0)
err = ss.db.WithDbSession(ctx, func(sess *db.Session) error {
if err := sess.Where("org_id = ?", query.OrgID).Asc("name").Find(&res); err != nil {
return err
}
return nil
})
return res, err
}
func (ss *sqlStore) GetAlertNotificationsWithUidToSend(ctx context.Context, query *models.GetAlertNotificationsWithUidToSendQuery) (res []*models.AlertNotification, err error) {
res = make([]*models.AlertNotification, 0)
err = ss.db.WithDbSession(ctx, func(sess *db.Session) error {
var sql bytes.Buffer
params := make([]interface{}, 0)
sql.WriteString(`SELECT
alert_notification.id,
2018-12-14 03:53:50 -06:00
alert_notification.uid,
alert_notification.org_id,
alert_notification.name,
alert_notification.type,
alert_notification.created,
alert_notification.updated,
alert_notification.settings,
alert_notification.secure_settings,
2018-05-20 11:12:10 -05:00
alert_notification.is_default,
2018-10-17 03:41:18 -05:00
alert_notification.disable_resolve_message,
alert_notification.send_reminder,
2018-05-20 11:12:10 -05:00
alert_notification.frequency
FROM alert_notification
`)
sql.WriteString(` WHERE alert_notification.org_id = ?`)
params = append(params, query.OrgID)
sql.WriteString(` AND ((alert_notification.is_default = ?)`)
params = append(params, ss.db.GetDialect().BooleanStr(true))
2018-12-14 03:53:50 -06:00
if len(query.UIDs) > 0 {
sql.WriteString(` OR alert_notification.uid IN (?` + strings.Repeat(",?", len(query.UIDs)-1) + ")")
for _, v := range query.UIDs {
params = append(params, v)
}
}
sql.WriteString(`)`)
return sess.SQL(sql.String(), params...).Find(&res)
})
return res, err
}
func getAlertNotificationUidInternal(ctx context.Context, query *models.GetAlertNotificationUidQuery, sess *db.Session) (res string, err error) {
var sql bytes.Buffer
params := make([]interface{}, 0)
sql.WriteString(`SELECT
alert_notification.uid
FROM alert_notification
`)
sql.WriteString(` WHERE alert_notification.org_id = ?`)
params = append(params, query.OrgID)
sql.WriteString(` AND alert_notification.id = ?`)
params = append(params, query.ID)
results := make([]string, 0)
if err := sess.SQL(sql.String(), params...).Find(&results); err != nil {
return "", err
}
if len(results) == 0 {
return "", models.ErrAlertNotificationFailedTranslateUniqueID
}
res = results[0]
return res, nil
}
func getAlertNotificationInternal(ctx context.Context, query *models.GetAlertNotificationsQuery, sess *db.Session) (res *models.AlertNotification, err error) {
2016-06-13 09:39:00 -05:00
var sql bytes.Buffer
params := make([]interface{}, 0)
sql.WriteString(`SELECT
alert_notification.id,
alert_notification.uid,
alert_notification.org_id,
alert_notification.name,
alert_notification.type,
alert_notification.created,
alert_notification.updated,
alert_notification.settings,
alert_notification.secure_settings,
2018-05-20 11:12:10 -05:00
alert_notification.is_default,
2018-10-17 03:41:18 -05:00
alert_notification.disable_resolve_message,
alert_notification.send_reminder,
2018-05-20 11:12:10 -05:00
alert_notification.frequency
FROM alert_notification
`)
2016-06-13 09:39:00 -05:00
sql.WriteString(` WHERE alert_notification.org_id = ?`)
params = append(params, query.OrgID)
2016-06-13 09:39:00 -05:00
if query.Name != "" || query.ID != 0 {
if query.Name != "" {
sql.WriteString(` AND alert_notification.name = ?`)
params = append(params, query.Name)
}
2016-06-13 09:39:00 -05:00
if query.ID != 0 {
sql.WriteString(` AND alert_notification.id = ?`)
params = append(params, query.ID)
}
}
results := make([]*models.AlertNotification, 0)
pkg/services/sqlstore: Fix x.Sql is deprecated: use SQL instead. (megacheck) See, $ gometalinter --vendor --disable-all --enable=megacheck --disable=gotype --deadline 6m ./... | grep SQL alert.go:43:9:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) alert_notification.go:122:12:warning: sess.Sql is deprecated: use SQL instead. (SA1019) (megacheck) annotation.go:226:12:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) dashboard.go:228:9:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) dashboard.go:302:10:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) dashboard.go:416:9:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) dashboard.go:635:12:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) migrations/user_mig.go:137:9:warning: sess.Sql is deprecated: use SQL instead. (SA1019) (megacheck) plugin_setting.go:29:10:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) quota.go:41:12:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) quota.go:84:13:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) quota.go:143:12:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) quota.go:186:13:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) quota.go:234:12:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) team.go:172:12:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) team.go:199:17:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) team.go:223:9:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) temp_user.go:99:10:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) temp_user.go:124:10:warning: x.Sql is deprecated: use SQL instead. (SA1019) (megacheck) user.go:375:3:warning: sess.Sql is deprecated: use SQL instead. (SA1019) (megacheck) user.go:377:3:warning: sess.Sql is deprecated: use SQL instead. (SA1019) (megacheck) user.go:379:3:warning: sess.Sql is deprecated: use SQL instead. (SA1019) (megacheck)
2018-09-16 05:26:05 -05:00
if err := sess.SQL(sql.String(), params...).Find(&results); err != nil {
return nil, err
2016-06-13 09:39:00 -05:00
}
if len(results) == 0 {
return nil, nil
}
return results[0], nil
2016-06-13 09:39:00 -05:00
}
func getAlertNotificationWithUidInternal(ctx context.Context, query *models.GetAlertNotificationsWithUidQuery, sess *db.Session) (res *models.AlertNotification, err error) {
2018-12-14 03:53:50 -06:00
var sql bytes.Buffer
params := make([]interface{}, 0)
sql.WriteString(`SELECT
alert_notification.id,
alert_notification.uid,
alert_notification.org_id,
alert_notification.name,
alert_notification.type,
alert_notification.created,
alert_notification.updated,
alert_notification.settings,
alert_notification.secure_settings,
2018-12-14 03:53:50 -06:00
alert_notification.is_default,
alert_notification.disable_resolve_message,
alert_notification.send_reminder,
alert_notification.frequency
FROM alert_notification
`)
sql.WriteString(` WHERE alert_notification.org_id = ? AND alert_notification.uid = ?`)
params = append(params, query.OrgID, query.UID)
2018-12-14 03:53:50 -06:00
results := make([]*models.AlertNotification, 0)
2018-12-14 03:53:50 -06:00
if err := sess.SQL(sql.String(), params...).Find(&results); err != nil {
return nil, err
2018-12-14 03:53:50 -06:00
}
if len(results) == 0 {
return nil, nil
2018-12-14 03:53:50 -06:00
}
return results[0], nil
2018-12-14 03:53:50 -06:00
}
func (ss *sqlStore) CreateAlertNotificationCommand(ctx context.Context, cmd *models.CreateAlertNotificationCommand) (res *models.AlertNotification, err error) {
err = ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
if cmd.UID == "" {
uid, uidGenerationErr := generateNewAlertNotificationUid(ctx, sess, cmd.OrgID)
if uidGenerationErr != nil {
2018-12-14 03:53:50 -06:00
return uidGenerationErr
}
cmd.UID = uid
2018-12-14 03:53:50 -06:00
}
existingQuery := &models.GetAlertNotificationsWithUidQuery{OrgID: cmd.OrgID, UID: cmd.UID}
if notification, err := getAlertNotificationWithUidInternal(ctx, existingQuery, sess); err != nil {
return err
} else if notification != nil {
return models.ErrAlertNotificationWithSameUIDExists
2018-12-14 03:53:50 -06:00
}
// check if name exists
sameNameQuery := &models.GetAlertNotificationsQuery{OrgID: cmd.OrgID, Name: cmd.Name}
if notification, err := getAlertNotificationInternal(ctx, sameNameQuery, sess); err != nil {
2018-12-14 03:53:50 -06:00
return err
} else if notification != nil {
return models.ErrAlertNotificationWithSameNameExists
}
2016-06-13 09:39:00 -05:00
2018-05-25 13:14:33 -05:00
var frequency time.Duration
if cmd.SendReminder {
if cmd.Frequency == "" {
return models.ErrNotificationFrequencyNotFound
}
frequency, err = time.ParseDuration(cmd.Frequency)
if err != nil {
return err
}
2018-05-20 11:12:10 -05:00
}
// delete empty keys
for k, v := range cmd.SecureSettings {
if v == "" {
delete(cmd.SecureSettings, k)
}
}
alertNotification := &models.AlertNotification{
UID: cmd.UID,
OrgID: cmd.OrgID,
2018-10-17 03:41:18 -05:00
Name: cmd.Name,
Type: cmd.Type,
Settings: cmd.Settings,
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>
2021-10-07 09:33:50 -05:00
SecureSettings: cmd.EncryptedSecureSettings,
2018-10-17 03:41:18 -05:00
SendReminder: cmd.SendReminder,
DisableResolveMessage: cmd.DisableResolveMessage,
Frequency: frequency,
Created: time.Now(),
Updated: time.Now(),
IsDefault: cmd.IsDefault,
}
2016-06-13 09:39:00 -05:00
if _, err = sess.MustCols("send_reminder").Insert(alertNotification); err != nil {
return err
}
res = alertNotification
return nil
2016-06-13 09:39:00 -05:00
})
return res, err
2016-06-13 09:39:00 -05:00
}
func generateNewAlertNotificationUid(ctx context.Context, sess *db.Session, orgId int64) (string, error) {
2018-12-14 03:53:50 -06:00
for i := 0; i < 3; i++ {
2019-01-29 14:17:56 -06:00
uid := util.GenerateShortUID()
exists, err := sess.Where("org_id=? AND uid=?", orgId, uid).Get(&models.AlertNotification{})
2018-12-14 03:53:50 -06:00
if err != nil {
return "", err
}
2018-12-14 03:53:50 -06:00
if !exists {
return uid, nil
}
}
return "", models.ErrAlertNotificationFailedGenerateUniqueUid
2018-12-14 03:53:50 -06:00
}
func (ss *sqlStore) UpdateAlertNotification(ctx context.Context, cmd *models.UpdateAlertNotificationCommand) (res *models.AlertNotification, err error) {
err = ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) (err error) {
current := models.AlertNotification{}
2016-06-13 09:39:00 -05:00
if _, err = sess.ID(cmd.ID).Get(&current); err != nil {
return err
}
if current.ID == 0 {
return models.ErrAlertNotificationNotFound
}
// check if name exists
sameNameQuery := &models.GetAlertNotificationsQuery{OrgID: cmd.OrgID, Name: cmd.Name}
notification, err := getAlertNotificationInternal(ctx, sameNameQuery, sess)
if err != nil {
return err
}
if notification != nil && notification.ID != current.ID {
return fmt.Errorf("alert notification name %q already exists", cmd.Name)
}
// delete empty keys
for k, v := range cmd.SecureSettings {
if v == "" {
delete(cmd.SecureSettings, k)
}
}
current.Updated = time.Now()
current.Settings = cmd.Settings
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>
2021-10-07 09:33:50 -05:00
current.SecureSettings = cmd.EncryptedSecureSettings
current.Name = cmd.Name
current.Type = cmd.Type
current.IsDefault = cmd.IsDefault
current.SendReminder = cmd.SendReminder
2018-10-17 03:41:18 -05:00
current.DisableResolveMessage = cmd.DisableResolveMessage
2018-05-20 11:12:10 -05:00
if cmd.UID != "" {
current.UID = cmd.UID
}
if current.SendReminder {
if cmd.Frequency == "" {
return models.ErrNotificationFrequencyNotFound
}
2018-05-20 15:08:42 -05:00
frequency, err := time.ParseDuration(cmd.Frequency)
if err != nil {
return err
}
current.Frequency = frequency
2018-05-20 11:12:10 -05:00
}
2018-10-17 03:41:18 -05:00
sess.UseBool("is_default", "send_reminder", "disable_resolve_message")
if affected, err := sess.ID(cmd.ID).Update(current); err != nil {
return err
} else if affected == 0 {
return fmt.Errorf("could not update alert notification")
}
res = &current
return nil
})
return res, err
}
func (ss *sqlStore) UpdateAlertNotificationWithUid(ctx context.Context, cmd *models.UpdateAlertNotificationWithUidCommand) (res *models.AlertNotification, err error) {
getAlertNotificationWithUidQuery := &models.GetAlertNotificationsWithUidQuery{OrgID: cmd.OrgID, UID: cmd.UID}
2018-12-14 03:53:50 -06:00
if err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
res, err = getAlertNotificationWithUidInternal(ctx, getAlertNotificationWithUidQuery, sess)
2018-12-20 04:45:18 -06:00
return err
}); err != nil {
return nil, err
2018-12-14 03:53:50 -06:00
}
current := res
2018-12-14 03:53:50 -06:00
if current == nil {
return nil, models.ErrAlertNotificationNotFound
2018-12-14 03:53:50 -06:00
}
if cmd.NewUID == "" {
cmd.NewUID = cmd.UID
}
updateNotification := &models.UpdateAlertNotificationCommand{
ID: current.ID,
UID: cmd.NewUID,
2018-12-14 03:53:50 -06:00
Name: cmd.Name,
Type: cmd.Type,
SendReminder: cmd.SendReminder,
DisableResolveMessage: cmd.DisableResolveMessage,
Frequency: cmd.Frequency,
IsDefault: cmd.IsDefault,
Settings: cmd.Settings,
SecureSettings: cmd.SecureSettings,
2018-12-14 03:53:50 -06:00
OrgID: cmd.OrgID,
2018-12-14 03:53:50 -06:00
}
return ss.UpdateAlertNotification(ctx, updateNotification)
2018-12-14 03:53:50 -06:00
}
func (ss *sqlStore) SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToCompleteCommand) error {
return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
version := cmd.Version
var current models.AlertNotificationState
if _, err := sess.ID(cmd.ID).Get(&current); err != nil {
return err
}
newVersion := cmd.Version + 1
sql := `UPDATE alert_notification_state SET
2018-09-28 04:17:03 -05:00
state = ?,
2018-09-28 08:11:03 -05:00
version = ?,
updated_at = ?
WHERE
id = ?`
_, err := sess.Exec(sql, models.AlertNotificationStateCompleted, newVersion, timeNow().Unix(), cmd.ID)
if err != nil {
return err
}
if current.Version != version {
ss.log.Error("notification state out of sync. the notification is marked as complete but has been modified between set as pending and completion.", "notifierId", current.NotifierID)
}
return nil
})
}
func (ss *sqlStore) SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToPendingCommand) error {
return ss.db.WithDbSession(ctx, func(sess *db.Session) error {
newVersion := cmd.Version + 1
sql := `UPDATE alert_notification_state SET
2018-09-28 04:17:03 -05:00
state = ?,
version = ?,
updated_at = ?,
alert_rule_state_updated_version = ?
WHERE
id = ? AND
(version = ? OR alert_rule_state_updated_version < ?)`
res, err := sess.Exec(sql,
models.AlertNotificationStatePending,
newVersion,
timeNow().Unix(),
cmd.AlertRuleStateUpdatedVersion,
cmd.ID,
cmd.Version,
cmd.AlertRuleStateUpdatedVersion)
if err != nil {
return err
}
affected, _ := res.RowsAffected()
if affected == 0 {
return models.ErrAlertNotificationStateVersionConflict
}
cmd.ResultVersion = newVersion
return nil
})
}
func (ss *sqlStore) GetOrCreateAlertNotificationState(ctx context.Context, cmd *models.GetOrCreateNotificationStateQuery) (res *models.AlertNotificationState, err error) {
err = ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
nj := &models.AlertNotificationState{}
exist, err := getAlertNotificationState(ctx, sess, cmd, nj)
2018-09-27 07:32:54 -05:00
// if exists, return it, otherwise create it with default values
if err != nil {
return err
}
if exist {
res = nj
return nil
}
notificationState := &models.AlertNotificationState{
OrgID: cmd.OrgID,
AlertID: cmd.AlertID,
NotifierID: cmd.NotifierID,
State: models.AlertNotificationStateUnknown,
UpdatedAt: timeNow().Unix(),
2018-09-28 04:17:03 -05:00
}
2018-09-27 07:32:54 -05:00
2018-09-28 04:17:03 -05:00
if _, err := sess.Insert(notificationState); err != nil {
if ss.db.GetDialect().IsUniqueConstraintViolation(err) {
exist, err = getAlertNotificationState(ctx, sess, cmd, nj)
2018-09-27 07:32:54 -05:00
2018-09-28 04:17:03 -05:00
if err != nil {
return err
}
2018-09-28 04:17:03 -05:00
if !exist {
return errors.New("should not happen")
2018-09-27 07:32:54 -05:00
}
res = nj
2018-09-28 04:17:03 -05:00
return nil
}
2018-09-28 04:17:03 -05:00
return err
}
res = notificationState
return nil
})
return res, err
}
func getAlertNotificationState(ctx context.Context, sess *db.Session, cmd *models.GetOrCreateNotificationStateQuery, nj *models.AlertNotificationState) (bool, error) {
return sess.
Where("alert_notification_state.org_id = ?", cmd.OrgID).
Where("alert_notification_state.alert_id = ?", cmd.AlertID).
Where("alert_notification_state.notifier_id = ?", cmd.NotifierID).
Get(nj)
}