2021-03-08 14:19:21 -06:00
package store
2021-01-18 12:57:17 -06:00
import (
"context"
"fmt"
"strings"
2021-03-08 14:19:21 -06:00
"github.com/grafana/grafana/pkg/services/ngalert/models"
2021-01-18 12:57:17 -06:00
"github.com/grafana/grafana/pkg/services/sqlstore"
)
2021-05-03 06:19:15 -05:00
type InstanceStore interface {
2022-02-08 07:49:04 -06:00
GetAlertInstance ( ctx context . Context , cmd * models . GetAlertInstanceQuery ) error
ListAlertInstances ( ctx context . Context , cmd * models . ListAlertInstancesQuery ) error
SaveAlertInstance ( ctx context . Context , cmd * models . SaveAlertInstanceCommand ) error
FetchOrgIds ( ctx context . Context ) ( [ ] int64 , error )
DeleteAlertInstance ( ctx context . Context , orgID int64 , ruleUID , labelsHash string ) error
2021-05-03 06:19:15 -05:00
}
2021-03-08 14:19:21 -06:00
// GetAlertInstance is a handler for retrieving an alert instance based on OrgId, AlertDefintionID, and
2021-01-18 12:57:17 -06:00
// the hash of the labels.
2022-02-08 07:49:04 -06:00
func ( st DBstore ) GetAlertInstance ( ctx context . Context , cmd * models . GetAlertInstanceQuery ) error {
return st . SQLStore . WithDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
2021-03-08 14:19:21 -06:00
instance := models . AlertInstance { }
2021-01-18 12:57:17 -06:00
s := strings . Builder { }
s . WriteString ( ` SELECT * FROM alert_instance
WHERE
2021-05-12 06:17:43 -05:00
rule_org_id = ? AND
rule_uid = ? AND
2021-01-18 12:57:17 -06:00
labels_hash = ?
` )
_ , hash , err := cmd . Labels . StringAndHash ( )
if err != nil {
return err
}
2021-05-03 06:19:15 -05:00
params := append ( make ( [ ] interface { } , 0 ) , cmd . RuleOrgID , cmd . RuleUID , hash )
2021-01-18 12:57:17 -06:00
has , err := sess . SQL ( s . String ( ) , params ... ) . Get ( & instance )
if ! has {
2021-05-12 06:17:43 -05:00
return fmt . Errorf ( "instance not found for labels %v (hash: %v), alert rule %v (org %v)" , cmd . Labels , hash , cmd . RuleUID , cmd . RuleOrgID )
2021-01-18 12:57:17 -06:00
}
if err != nil {
return err
}
cmd . Result = & instance
return nil
} )
}
2021-03-08 14:19:21 -06:00
// ListAlertInstances is a handler for retrieving alert instances within specific organisation
2021-01-18 12:57:17 -06:00
// based on various filters.
2022-02-08 07:49:04 -06:00
func ( st DBstore ) ListAlertInstances ( ctx context . Context , cmd * models . ListAlertInstancesQuery ) error {
return st . SQLStore . WithDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
2021-03-08 14:19:21 -06:00
alertInstances := make ( [ ] * models . ListAlertInstancesQueryResult , 0 )
2021-01-18 12:57:17 -06:00
s := strings . Builder { }
params := make ( [ ] interface { } , 0 )
addToQuery := func ( stmt string , p ... interface { } ) {
s . WriteString ( stmt )
params = append ( params , p ... )
}
2021-05-12 06:17:43 -05:00
addToQuery ( "SELECT alert_instance.*, alert_rule.title AS rule_title FROM alert_instance LEFT JOIN alert_rule ON alert_instance.rule_org_id = alert_rule.org_id AND alert_instance.rule_uid = alert_rule.uid WHERE rule_org_id = ?" , cmd . RuleOrgID )
2021-01-18 12:57:17 -06:00
2021-05-03 06:19:15 -05:00
if cmd . RuleUID != "" {
2021-05-12 06:17:43 -05:00
addToQuery ( ` AND rule_uid = ? ` , cmd . RuleUID )
2021-01-18 12:57:17 -06:00
}
if cmd . State != "" {
addToQuery ( ` AND current_state = ? ` , cmd . State )
}
if err := sess . SQL ( s . String ( ) , params ... ) . Find ( & alertInstances ) ; err != nil {
return err
}
cmd . Result = alertInstances
return nil
} )
}
2021-03-08 14:19:21 -06:00
// SaveAlertInstance is a handler for saving a new alert instance.
2022-02-08 07:49:04 -06:00
func ( st DBstore ) SaveAlertInstance ( ctx context . Context , cmd * models . SaveAlertInstanceCommand ) error {
return st . SQLStore . WithDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
2021-01-18 12:57:17 -06:00
labelTupleJSON , labelsHash , err := cmd . Labels . StringAndHash ( )
if err != nil {
return err
}
2021-03-08 14:19:21 -06:00
alertInstance := & models . AlertInstance {
2021-05-03 06:19:15 -05:00
RuleOrgID : cmd . RuleOrgID ,
RuleUID : cmd . RuleUID ,
2021-01-18 12:57:17 -06:00
Labels : cmd . Labels ,
LabelsHash : labelsHash ,
CurrentState : cmd . State ,
2021-04-02 10:11:33 -05:00
CurrentStateSince : cmd . CurrentStateSince ,
CurrentStateEnd : cmd . CurrentStateEnd ,
2021-01-18 12:57:17 -06:00
LastEvalTime : cmd . LastEvalTime ,
}
2021-03-08 14:19:21 -06:00
if err := models . ValidateAlertInstance ( alertInstance ) ; err != nil {
2021-01-18 12:57:17 -06:00
return err
}
2021-04-30 13:23:12 -05:00
params := append ( make ( [ ] interface { } , 0 ) , alertInstance . RuleOrgID , alertInstance . RuleUID , labelTupleJSON , alertInstance . LabelsHash , alertInstance . CurrentState , alertInstance . CurrentStateSince . Unix ( ) , alertInstance . CurrentStateEnd . Unix ( ) , alertInstance . LastEvalTime . Unix ( ) )
2021-01-18 12:57:17 -06:00
2021-03-03 09:52:19 -06:00
upsertSQL := st . SQLStore . Dialect . UpsertSQL (
2021-01-18 12:57:17 -06:00
"alert_instance" ,
2021-05-12 06:17:43 -05:00
[ ] string { "rule_org_id" , "rule_uid" , "labels_hash" } ,
[ ] string { "rule_org_id" , "rule_uid" , "labels" , "labels_hash" , "current_state" , "current_state_since" , "current_state_end" , "last_eval_time" } )
2021-01-18 12:57:17 -06:00
_ , err = sess . SQL ( upsertSQL , params ... ) . Query ( )
if err != nil {
return err
}
return nil
} )
}
2021-04-02 10:11:33 -05:00
2022-02-08 07:49:04 -06:00
func ( st DBstore ) FetchOrgIds ( ctx context . Context ) ( [ ] int64 , error ) {
2021-05-12 06:17:43 -05:00
orgIds := [ ] int64 { }
2021-04-02 10:11:33 -05:00
2022-02-08 07:49:04 -06:00
err := st . SQLStore . WithDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
2021-04-02 10:11:33 -05:00
s := strings . Builder { }
params := make ( [ ] interface { } , 0 )
addToQuery := func ( stmt string , p ... interface { } ) {
s . WriteString ( stmt )
params = append ( params , p ... )
}
2021-05-12 06:17:43 -05:00
addToQuery ( "SELECT DISTINCT rule_org_id FROM alert_instance" )
2021-04-02 10:11:33 -05:00
if err := sess . SQL ( s . String ( ) , params ... ) . Find ( & orgIds ) ; err != nil {
return err
}
return nil
} )
2021-05-12 06:17:43 -05:00
return orgIds , err
2021-04-02 10:11:33 -05:00
}
2021-07-26 11:12:04 -05:00
2022-02-08 07:49:04 -06:00
func ( st DBstore ) DeleteAlertInstance ( ctx context . Context , orgID int64 , ruleUID , labelsHash string ) error {
return st . SQLStore . WithTransactionalDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
2021-07-26 11:12:04 -05:00
_ , err := sess . Exec ( "DELETE FROM alert_instance WHERE rule_org_id = ? AND rule_uid = ? AND labels_hash = ?" , orgID , ruleUID , labelsHash )
if err != nil {
return err
}
return nil
} )
}