| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510 |
- package sqlstore
- import (
- "bytes"
- "context"
- "errors"
- "fmt"
- "strings"
- "time"
- "github.com/grafana/grafana/pkg/bus"
- m "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 *m.DeleteAlertNotificationCommand) error {
- return inTransaction(func(sess *DBSession) error {
- sql := "DELETE FROM alert_notification WHERE alert_notification.org_id = ? AND alert_notification.id = ?"
- if _, err := sess.Exec(sql, cmd.OrgId, cmd.Id); err != nil {
- return err
- }
- 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
- })
- }
- func DeleteAlertNotificationWithUid(cmd *m.DeleteAlertNotificationWithUidCommand) error {
- existingNotification := &m.GetAlertNotificationsWithUidQuery{OrgId: cmd.OrgId, Uid: cmd.Uid}
- if err := getAlertNotificationWithUidInternal(existingNotification, newSession()); err != nil {
- return err
- }
- if existingNotification.Result != nil {
- deleteCommand := &m.DeleteAlertNotificationCommand{
- Id: existingNotification.Result.Id,
- OrgId: existingNotification.Result.OrgId,
- }
- if err := bus.Dispatch(deleteCommand); err != nil {
- return err
- }
- }
- return nil
- }
- func GetAlertNotifications(query *m.GetAlertNotificationsQuery) error {
- return getAlertNotificationInternal(query, newSession())
- }
- func GetAlertNotificationsWithUid(query *m.GetAlertNotificationsWithUidQuery) error {
- return getAlertNotificationWithUidInternal(query, newSession())
- }
- func GetAllAlertNotifications(query *m.GetAllAlertNotificationsQuery) error {
- results := make([]*m.AlertNotification, 0)
- if err := x.Where("org_id = ?", query.OrgId).Find(&results); err != nil {
- return err
- }
- query.Result = results
- return nil
- }
- func GetAlertNotificationsWithUidToSend(query *m.GetAlertNotificationsWithUidToSendQuery) error {
- 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.is_default,
- alert_notification.disable_resolve_message,
- alert_notification.send_reminder,
- 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, dialect.BooleanStr(true))
- 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(`)`)
- results := make([]*m.AlertNotification, 0)
- if err := x.SQL(sql.String(), params...).Find(&results); err != nil {
- return err
- }
- query.Result = results
- return nil
- }
- func getAlertNotificationInternal(query *m.GetAlertNotificationsQuery, sess *DBSession) error {
- 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.is_default,
- alert_notification.disable_resolve_message,
- alert_notification.send_reminder,
- alert_notification.frequency
- FROM alert_notification
- `)
- sql.WriteString(` WHERE alert_notification.org_id = ?`)
- params = append(params, query.OrgId)
- if query.Name != "" || query.Id != 0 {
- if query.Name != "" {
- sql.WriteString(` AND alert_notification.name = ?`)
- params = append(params, query.Name)
- }
- if query.Id != 0 {
- sql.WriteString(` AND alert_notification.id = ?`)
- params = append(params, query.Id)
- }
- }
- results := make([]*m.AlertNotification, 0)
- if err := sess.SQL(sql.String(), params...).Find(&results); err != nil {
- return err
- }
- if len(results) == 0 {
- query.Result = nil
- } else {
- query.Result = results[0]
- }
- return nil
- }
- func getAlertNotificationWithUidInternal(query *m.GetAlertNotificationsWithUidQuery, sess *DBSession) error {
- 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.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)
- results := make([]*m.AlertNotification, 0)
- if err := sess.SQL(sql.String(), params...).Find(&results); err != nil {
- return err
- }
- if len(results) == 0 {
- query.Result = nil
- } else {
- query.Result = results[0]
- }
- return nil
- }
- func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error {
- return inTransaction(func(sess *DBSession) error {
- if cmd.Uid == "" {
- uid, uidGenerationErr := generateNewAlertNotificationUid(sess, cmd.OrgId)
- if uidGenerationErr != nil {
- return uidGenerationErr
- }
- cmd.Uid = uid
- }
- existingQuery := &m.GetAlertNotificationsWithUidQuery{OrgId: cmd.OrgId, Uid: cmd.Uid}
- err := getAlertNotificationWithUidInternal(existingQuery, sess)
- if err != nil {
- return err
- }
- if existingQuery.Result != nil {
- return fmt.Errorf("Alert notification uid %s already exists", cmd.Uid)
- }
- // check if name exists
- sameNameQuery := &m.GetAlertNotificationsQuery{OrgId: cmd.OrgId, Name: cmd.Name}
- if err := getAlertNotificationInternal(sameNameQuery, sess); err != nil {
- return err
- }
- if sameNameQuery.Result != nil {
- return fmt.Errorf("Alert notification name %s already exists", cmd.Name)
- }
- var frequency time.Duration
- if cmd.SendReminder {
- if cmd.Frequency == "" {
- return m.ErrNotificationFrequencyNotFound
- }
- frequency, err = time.ParseDuration(cmd.Frequency)
- if err != nil {
- return err
- }
- }
- alertNotification := &m.AlertNotification{
- Uid: cmd.Uid,
- OrgId: cmd.OrgId,
- Name: cmd.Name,
- Type: cmd.Type,
- Settings: cmd.Settings,
- SendReminder: cmd.SendReminder,
- DisableResolveMessage: cmd.DisableResolveMessage,
- Frequency: frequency,
- Created: time.Now(),
- Updated: time.Now(),
- IsDefault: cmd.IsDefault,
- }
- if _, err = sess.MustCols("send_reminder").Insert(alertNotification); err != nil {
- return err
- }
- cmd.Result = alertNotification
- return nil
- })
- }
- func generateNewAlertNotificationUid(sess *DBSession, orgId int64) (string, error) {
- for i := 0; i < 3; i++ {
- uid := util.GenerateShortUID()
- exists, err := sess.Where("org_id=? AND uid=?", orgId, uid).Get(&m.AlertNotification{})
- if err != nil {
- return "", err
- }
- if !exists {
- return uid, nil
- }
- }
- return "", m.ErrAlertNotificationFailedGenerateUniqueUid
- }
- func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
- return inTransaction(func(sess *DBSession) (err error) {
- current := m.AlertNotification{}
- if _, err = sess.ID(cmd.Id).Get(¤t); err != nil {
- return err
- }
- // check if name exists
- sameNameQuery := &m.GetAlertNotificationsQuery{OrgId: cmd.OrgId, Name: cmd.Name}
- if err := getAlertNotificationInternal(sameNameQuery, sess); err != nil {
- return err
- }
- if sameNameQuery.Result != nil && sameNameQuery.Result.Id != current.Id {
- return fmt.Errorf("Alert notification name %s already exists", cmd.Name)
- }
- current.Updated = time.Now()
- current.Settings = cmd.Settings
- current.Name = cmd.Name
- current.Type = cmd.Type
- current.IsDefault = cmd.IsDefault
- current.SendReminder = cmd.SendReminder
- current.DisableResolveMessage = cmd.DisableResolveMessage
- if cmd.Uid != "" {
- current.Uid = cmd.Uid
- }
- if current.SendReminder {
- if cmd.Frequency == "" {
- return m.ErrNotificationFrequencyNotFound
- }
- frequency, err := time.ParseDuration(cmd.Frequency)
- if err != nil {
- return err
- }
- current.Frequency = frequency
- }
- 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")
- }
- cmd.Result = ¤t
- return nil
- })
- }
- func UpdateAlertNotificationWithUid(cmd *m.UpdateAlertNotificationWithUidCommand) error {
- getAlertNotificationWithUidQuery := &m.GetAlertNotificationsWithUidQuery{OrgId: cmd.OrgId, Uid: cmd.Uid}
- if err := getAlertNotificationWithUidInternal(getAlertNotificationWithUidQuery, newSession()); err != nil {
- return err
- }
- current := getAlertNotificationWithUidQuery.Result
- if current == nil {
- return fmt.Errorf("Cannot update, alert notification uid %s doesn't exist", cmd.Uid)
- }
- if cmd.NewUid == "" {
- cmd.NewUid = cmd.Uid
- }
- updateNotification := &m.UpdateAlertNotificationCommand{
- Id: current.Id,
- Uid: cmd.NewUid,
- Name: cmd.Name,
- Type: cmd.Type,
- SendReminder: cmd.SendReminder,
- DisableResolveMessage: cmd.DisableResolveMessage,
- Frequency: cmd.Frequency,
- IsDefault: cmd.IsDefault,
- Settings: cmd.Settings,
- OrgId: cmd.OrgId,
- }
- if err := bus.Dispatch(updateNotification); err != nil {
- return err
- }
- cmd.Result = updateNotification.Result
- return nil
- }
- func SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *m.SetAlertNotificationStateToCompleteCommand) error {
- return inTransactionCtx(ctx, func(sess *DBSession) error {
- version := cmd.Version
- var current m.AlertNotificationState
- sess.ID(cmd.Id).Get(¤t)
- newVersion := cmd.Version + 1
- sql := `UPDATE alert_notification_state SET
- state = ?,
- version = ?,
- updated_at = ?
- WHERE
- id = ?`
- _, err := sess.Exec(sql, m.AlertNotificationStateCompleted, newVersion, timeNow().Unix(), cmd.Id)
- if err != nil {
- return err
- }
- if current.Version != version {
- sqlog.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 SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *m.SetAlertNotificationStateToPendingCommand) error {
- return withDbSession(ctx, func(sess *DBSession) error {
- newVersion := cmd.Version + 1
- sql := `UPDATE alert_notification_state SET
- state = ?,
- version = ?,
- updated_at = ?,
- alert_rule_state_updated_version = ?
- WHERE
- id = ? AND
- (version = ? OR alert_rule_state_updated_version < ?)`
- res, err := sess.Exec(sql,
- m.AlertNotificationStatePending,
- newVersion,
- timeNow().Unix(),
- cmd.AlertRuleStateUpdatedVersion,
- cmd.Id,
- cmd.Version,
- cmd.AlertRuleStateUpdatedVersion)
- if err != nil {
- return err
- }
- affected, _ := res.RowsAffected()
- if affected == 0 {
- return m.ErrAlertNotificationStateVersionConflict
- }
- cmd.ResultVersion = newVersion
- return nil
- })
- }
- func GetOrCreateAlertNotificationState(ctx context.Context, cmd *m.GetOrCreateNotificationStateQuery) error {
- return inTransactionCtx(ctx, func(sess *DBSession) error {
- nj := &m.AlertNotificationState{}
- exist, err := getAlertNotificationState(sess, cmd, nj)
- // if exists, return it, otherwise create it with default values
- if err != nil {
- return err
- }
- if exist {
- cmd.Result = nj
- return nil
- }
- notificationState := &m.AlertNotificationState{
- OrgId: cmd.OrgId,
- AlertId: cmd.AlertId,
- NotifierId: cmd.NotifierId,
- State: m.AlertNotificationStateUnknown,
- UpdatedAt: timeNow().Unix(),
- }
- if _, err := sess.Insert(notificationState); err != nil {
- if dialect.IsUniqueConstraintViolation(err) {
- exist, err = getAlertNotificationState(sess, cmd, nj)
- if err != nil {
- return err
- }
- if !exist {
- return errors.New("Should not happen")
- }
- cmd.Result = nj
- return nil
- }
- return err
- }
- cmd.Result = notificationState
- return nil
- })
- }
- func getAlertNotificationState(sess *DBSession, cmd *m.GetOrCreateNotificationStateQuery, nj *m.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)
- }
|