2022-06-02 07:48:53 -05:00
package provisioning
import (
"context"
"errors"
"fmt"
"time"
"github.com/grafana/grafana/pkg/infra/log"
2023-01-27 10:39:16 -06:00
"github.com/grafana/grafana/pkg/services/dashboards"
2022-06-02 07:48:53 -05:00
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
2022-07-13 17:36:17 -05:00
"github.com/grafana/grafana/pkg/services/quota"
2022-06-02 07:48:53 -05:00
"github.com/grafana/grafana/pkg/util"
)
type AlertRuleService struct {
2022-06-09 02:28:32 -05:00
defaultIntervalSeconds int64
baseIntervalSeconds int64
2022-06-09 03:38:46 -05:00
ruleStore RuleStore
2022-06-09 02:28:32 -05:00
provenanceStore ProvisioningStore
2023-01-27 10:39:16 -06:00
dashboardService dashboards . DashboardService
2022-07-13 17:36:17 -05:00
quotas QuotaChecker
2022-06-09 02:28:32 -05:00
xact TransactionManager
log log . Logger
2022-06-02 07:48:53 -05:00
}
2022-06-09 03:38:46 -05:00
func NewAlertRuleService ( ruleStore RuleStore ,
2022-06-02 07:48:53 -05:00
provenanceStore ProvisioningStore ,
2023-01-27 10:39:16 -06:00
dashboardService dashboards . DashboardService ,
2022-07-13 17:36:17 -05:00
quotas QuotaChecker ,
2022-06-02 07:48:53 -05:00
xact TransactionManager ,
2022-06-09 02:28:32 -05:00
defaultIntervalSeconds int64 ,
baseIntervalSeconds int64 ,
2022-06-02 07:48:53 -05:00
log log . Logger ) * AlertRuleService {
return & AlertRuleService {
2022-06-09 02:28:32 -05:00
defaultIntervalSeconds : defaultIntervalSeconds ,
baseIntervalSeconds : baseIntervalSeconds ,
ruleStore : ruleStore ,
provenanceStore : provenanceStore ,
2023-01-27 10:39:16 -06:00
dashboardService : dashboardService ,
2022-07-13 17:36:17 -05:00
quotas : quotas ,
2022-06-09 02:28:32 -05:00
xact : xact ,
log : log ,
2022-06-02 07:48:53 -05:00
}
}
2023-10-11 08:51:20 -05:00
func ( service * AlertRuleService ) GetAlertRules ( ctx context . Context , orgID int64 ) ( [ ] * models . AlertRule , map [ string ] models . Provenance , error ) {
2022-12-13 04:54:08 -06:00
q := models . ListAlertRulesQuery {
OrgID : orgID ,
}
2023-03-28 03:34:35 -05:00
rules , err := service . ruleStore . ListAlertRules ( ctx , & q )
2022-12-13 04:54:08 -06:00
if err != nil {
2023-10-11 08:51:20 -05:00
return nil , nil , err
2022-12-13 04:54:08 -06:00
}
2023-10-11 08:51:20 -05:00
provenances := make ( map [ string ] models . Provenance )
if len ( rules ) > 0 {
resourceType := rules [ 0 ] . ResourceType ( )
provenances , err = service . provenanceStore . GetProvenances ( ctx , orgID , resourceType )
if err != nil {
return nil , nil , err
}
}
return rules , provenances , nil
2022-12-13 04:54:08 -06:00
}
2022-06-02 07:48:53 -05:00
func ( service * AlertRuleService ) GetAlertRule ( ctx context . Context , orgID int64 , ruleUID string ) ( models . AlertRule , models . Provenance , error ) {
query := & models . GetAlertRuleByUIDQuery {
OrgID : orgID ,
UID : ruleUID ,
}
2023-10-11 08:51:20 -05:00
rule , err := service . ruleStore . GetAlertRuleByUID ( ctx , query )
2022-06-02 07:48:53 -05:00
if err != nil {
return models . AlertRule { } , models . ProvenanceNone , err
}
2023-10-11 08:51:20 -05:00
provenance , err := service . provenanceStore . GetProvenance ( ctx , rule , orgID )
2022-06-02 07:48:53 -05:00
if err != nil {
return models . AlertRule { } , models . ProvenanceNone , err
}
2023-10-11 08:51:20 -05:00
return * rule , provenance , nil
2022-06-02 07:48:53 -05:00
}
2023-01-27 10:39:16 -06:00
type AlertRuleWithFolderTitle struct {
AlertRule models . AlertRule
FolderTitle string
}
// GetAlertRuleWithFolderTitle returns a single alert rule with its folder title.
func ( service * AlertRuleService ) GetAlertRuleWithFolderTitle ( ctx context . Context , orgID int64 , ruleUID string ) ( AlertRuleWithFolderTitle , error ) {
query := & models . GetAlertRuleByUIDQuery {
OrgID : orgID ,
UID : ruleUID ,
}
2023-03-28 03:34:35 -05:00
rule , err := service . ruleStore . GetAlertRuleByUID ( ctx , query )
2023-01-27 10:39:16 -06:00
if err != nil {
return AlertRuleWithFolderTitle { } , err
}
dq := dashboards . GetDashboardQuery {
OrgID : orgID ,
2023-03-28 03:34:35 -05:00
UID : rule . NamespaceUID ,
2023-01-27 10:39:16 -06:00
}
dash , err := service . dashboardService . GetDashboard ( ctx , & dq )
if err != nil {
return AlertRuleWithFolderTitle { } , err
}
return AlertRuleWithFolderTitle {
2023-03-28 03:34:35 -05:00
AlertRule : * rule ,
2023-01-27 10:39:16 -06:00
FolderTitle : dash . Title ,
} , nil
}
2022-06-10 09:25:15 -05:00
// CreateAlertRule creates a new alert rule. This function will ignore any
// interval that is set in the rule struct and use the already existing group
// interval or the default one.
2022-07-13 17:36:17 -05:00
func ( service * AlertRuleService ) CreateAlertRule ( ctx context . Context , rule models . AlertRule , provenance models . Provenance , userID int64 ) ( models . AlertRule , error ) {
2022-06-02 07:48:53 -05:00
if rule . UID == "" {
rule . UID = util . GenerateShortUID ( )
2023-09-08 14:09:35 -05:00
} else if err := util . ValidateUID ( rule . UID ) ; err != nil {
return models . AlertRule { } , errors . Join ( models . ErrAlertRuleFailedValidation , fmt . Errorf ( "cannot create rule with UID '%s': %w" , rule . UID , err ) )
2022-06-02 07:48:53 -05:00
}
interval , err := service . ruleStore . GetRuleGroupInterval ( ctx , rule . OrgID , rule . NamespaceUID , rule . RuleGroup )
// if the alert group does not exists we just use the default interval
if err != nil && errors . Is ( err , store . ErrAlertRuleGroupNotFound ) {
2022-06-09 02:28:32 -05:00
interval = service . defaultIntervalSeconds
2022-06-02 07:48:53 -05:00
} else if err != nil {
return models . AlertRule { } , err
}
rule . IntervalSeconds = interval
2022-12-16 04:47:25 -06:00
err = rule . SetDashboardAndPanelFromAnnotations ( )
2022-08-03 09:05:32 -05:00
if err != nil {
return models . AlertRule { } , err
}
2022-06-02 07:48:53 -05:00
rule . Updated = time . Now ( )
err = service . xact . InTransaction ( ctx , func ( ctx context . Context ) error {
ids , err := service . ruleStore . InsertAlertRules ( ctx , [ ] models . AlertRule {
rule ,
} )
if err != nil {
return err
}
2023-10-06 17:11:24 -05:00
var fixed bool
for _ , key := range ids {
if key . UID == rule . UID {
rule . ID = key . ID
fixed = true
break
}
}
if ! fixed {
2022-06-02 07:48:53 -05:00
return errors . New ( "couldn't find newly created id" )
}
2022-07-13 17:36:17 -05:00
2022-08-10 12:33:41 -05:00
if err = service . checkLimitsTransactionCtx ( ctx , rule . OrgID , userID ) ; err != nil {
return err
2022-07-13 17:36:17 -05:00
}
2022-06-02 07:48:53 -05:00
return service . provenanceStore . SetProvenance ( ctx , & rule , rule . OrgID , provenance )
} )
if err != nil {
return models . AlertRule { } , err
}
return rule , nil
}
2023-01-27 10:39:16 -06:00
func ( service * AlertRuleService ) GetRuleGroup ( ctx context . Context , orgID int64 , namespaceUID , group string ) ( models . AlertRuleGroup , error ) {
2022-07-05 11:53:50 -05:00
q := models . ListAlertRulesQuery {
OrgID : orgID ,
2023-01-27 10:39:16 -06:00
NamespaceUIDs : [ ] string { namespaceUID } ,
2022-07-05 11:53:50 -05:00
RuleGroup : group ,
}
2023-03-28 03:34:35 -05:00
ruleList , err := service . ruleStore . ListAlertRules ( ctx , & q )
if err != nil {
2022-08-12 16:36:50 -05:00
return models . AlertRuleGroup { } , err
2022-07-05 11:53:50 -05:00
}
2023-03-28 03:34:35 -05:00
if len ( ruleList ) == 0 {
2022-08-12 16:36:50 -05:00
return models . AlertRuleGroup { } , store . ErrAlertRuleGroupNotFound
2022-07-05 11:53:50 -05:00
}
2022-08-12 16:36:50 -05:00
res := models . AlertRuleGroup {
2023-03-28 03:34:35 -05:00
Title : ruleList [ 0 ] . RuleGroup ,
FolderUID : ruleList [ 0 ] . NamespaceUID ,
Interval : ruleList [ 0 ] . IntervalSeconds ,
2022-07-05 11:53:50 -05:00
Rules : [ ] models . AlertRule { } ,
}
2023-03-28 03:34:35 -05:00
for _ , r := range ruleList {
2022-07-05 11:53:50 -05:00
if r != nil {
res . Rules = append ( res . Rules , * r )
}
}
return res , nil
}
2022-06-09 02:28:32 -05:00
// UpdateRuleGroup will update the interval for all rules in the group.
2022-07-14 16:53:13 -05:00
func ( service * AlertRuleService ) UpdateRuleGroup ( ctx context . Context , orgID int64 , namespaceUID string , ruleGroup string , intervalSeconds int64 ) error {
if err := models . ValidateRuleGroupInterval ( intervalSeconds , service . baseIntervalSeconds ) ; err != nil {
2022-06-09 02:28:32 -05:00
return err
}
return service . xact . InTransaction ( ctx , func ( ctx context . Context ) error {
query := & models . ListAlertRulesQuery {
OrgID : orgID ,
NamespaceUIDs : [ ] string { namespaceUID } ,
RuleGroup : ruleGroup ,
}
2023-03-28 03:34:35 -05:00
ruleList , err := service . ruleStore . ListAlertRules ( ctx , query )
2022-06-09 02:28:32 -05:00
if err != nil {
return fmt . Errorf ( "failed to list alert rules: %w" , err )
}
2023-03-28 03:34:35 -05:00
updateRules := make ( [ ] models . UpdateRule , 0 , len ( ruleList ) )
for _ , rule := range ruleList {
2022-07-14 16:53:13 -05:00
if rule . IntervalSeconds == intervalSeconds {
2022-06-09 02:28:32 -05:00
continue
}
newRule := * rule
2022-07-14 16:53:13 -05:00
newRule . IntervalSeconds = intervalSeconds
2022-09-29 15:47:56 -05:00
updateRules = append ( updateRules , models . UpdateRule {
2022-06-09 02:28:32 -05:00
Existing : rule ,
New : newRule ,
} )
}
return service . ruleStore . UpdateAlertRules ( ctx , updateRules )
} )
}
2022-08-12 16:36:50 -05:00
func ( service * AlertRuleService ) ReplaceRuleGroup ( ctx context . Context , orgID int64 , group models . AlertRuleGroup , userID int64 , provenance models . Provenance ) error {
2022-08-10 12:33:41 -05:00
if err := models . ValidateRuleGroupInterval ( group . Interval , service . baseIntervalSeconds ) ; err != nil {
return err
}
// If the provided request did not provide the rules list at all, treat it as though it does not wish to change rules.
// This is done for backwards compatibility. Requests which specify only the interval must update only the interval.
if group . Rules == nil {
listRulesQuery := models . ListAlertRulesQuery {
OrgID : orgID ,
NamespaceUIDs : [ ] string { group . FolderUID } ,
RuleGroup : group . Title ,
}
2023-03-28 03:34:35 -05:00
ruleList , err := service . ruleStore . ListAlertRules ( ctx , & listRulesQuery )
if err != nil {
2022-08-10 12:33:41 -05:00
return fmt . Errorf ( "failed to list alert rules: %w" , err )
}
2023-03-28 03:34:35 -05:00
group . Rules = make ( [ ] models . AlertRule , 0 , len ( ruleList ) )
for _ , r := range ruleList {
2022-08-10 12:33:41 -05:00
if r != nil {
group . Rules = append ( group . Rules , * r )
}
}
}
key := models . AlertRuleGroupKey {
OrgID : orgID ,
NamespaceUID : group . FolderUID ,
RuleGroup : group . Title ,
}
2023-02-01 06:15:03 -06:00
rules := make ( [ ] * models . AlertRuleWithOptionals , len ( group . Rules ) )
2022-08-10 12:33:41 -05:00
group = * syncGroupRuleFields ( & group , orgID )
for i := range group . Rules {
2022-12-16 04:47:25 -06:00
if err := group . Rules [ i ] . SetDashboardAndPanelFromAnnotations ( ) ; err != nil {
return err
}
2023-02-01 06:15:03 -06:00
rules = append ( rules , & models . AlertRuleWithOptionals { AlertRule : group . Rules [ i ] , HasPause : true } )
2022-08-10 12:33:41 -05:00
}
delta , err := store . CalculateChanges ( ctx , service . ruleStore , key , rules )
if err != nil {
return fmt . Errorf ( "failed to calculate diff for alert rules: %w" , err )
}
// Refresh all calculated fields across all rules.
delta = store . UpdateCalculatedRuleFields ( delta )
if len ( delta . New ) == 0 && len ( delta . Update ) == 0 && len ( delta . Delete ) == 0 {
return nil
}
return service . xact . InTransaction ( ctx , func ( ctx context . Context ) error {
2023-06-08 17:51:50 -05:00
// Delete first as this could prevent future unique constraint violations.
if len ( delta . Delete ) > 0 {
for _ , del := range delta . Delete {
// check that provenance is not changed in an invalid way
storedProvenance , err := service . provenanceStore . GetProvenance ( ctx , del , orgID )
if err != nil {
return err
}
if canUpdate := canUpdateProvenanceInRuleGroup ( storedProvenance , provenance ) ; ! canUpdate {
return fmt . Errorf ( "cannot update with provided provenance '%s', needs '%s'" , provenance , storedProvenance )
}
}
if err := service . deleteRules ( ctx , orgID , delta . Delete ... ) ; err != nil {
2022-08-10 12:33:41 -05:00
return err
}
}
2023-06-08 17:51:50 -05:00
if len ( delta . Update ) > 0 {
updates := make ( [ ] models . UpdateRule , 0 , len ( delta . Update ) )
for _ , update := range delta . Update {
// check that provenance is not changed in an invalid way
storedProvenance , err := service . provenanceStore . GetProvenance ( ctx , update . New , orgID )
if err != nil {
return err
}
if canUpdate := canUpdateProvenanceInRuleGroup ( storedProvenance , provenance ) ; ! canUpdate {
return fmt . Errorf ( "cannot update with provided provenance '%s', needs '%s'" , provenance , storedProvenance )
}
updates = append ( updates , models . UpdateRule {
Existing : update . Existing ,
New : * update . New ,
} )
2022-08-10 12:33:41 -05:00
}
2023-06-08 17:51:50 -05:00
if err = service . ruleStore . UpdateAlertRules ( ctx , updates ) ; err != nil {
return fmt . Errorf ( "failed to update alert rules: %w" , err )
2022-08-10 12:33:41 -05:00
}
2023-06-08 17:51:50 -05:00
for _ , update := range delta . Update {
if err := service . provenanceStore . SetProvenance ( ctx , update . New , orgID , provenance ) ; err != nil {
return err
}
2022-08-10 12:33:41 -05:00
}
}
2023-06-08 17:51:50 -05:00
if len ( delta . New ) > 0 {
uids , err := service . ruleStore . InsertAlertRules ( ctx , withoutNilAlertRules ( delta . New ) )
2022-08-10 12:33:41 -05:00
if err != nil {
2023-06-08 17:51:50 -05:00
return fmt . Errorf ( "failed to insert alert rules: %w" , err )
2022-08-10 12:33:41 -05:00
}
2023-10-06 17:11:24 -05:00
for _ , key := range uids {
if err := service . provenanceStore . SetProvenance ( ctx , & models . AlertRule { UID : key . UID } , orgID , provenance ) ; err != nil {
2023-06-08 17:51:50 -05:00
return err
}
2022-08-10 12:33:41 -05:00
}
}
if err = service . checkLimitsTransactionCtx ( ctx , orgID , userID ) ; err != nil {
return err
}
return nil
} )
}
2023-04-18 08:10:36 -05:00
// UpdateAlertRule updates an alert rule.
2022-06-02 07:48:53 -05:00
func ( service * AlertRuleService ) UpdateAlertRule ( ctx context . Context , rule models . AlertRule , provenance models . Provenance ) ( models . AlertRule , error ) {
storedRule , storedProvenance , err := service . GetAlertRule ( ctx , rule . OrgID , rule . UID )
if err != nil {
return models . AlertRule { } , err
}
if storedProvenance != provenance && storedProvenance != models . ProvenanceNone {
2023-04-18 08:10:36 -05:00
return models . AlertRule { } , fmt . Errorf ( "cannot change provenance from '%s' to '%s'" , storedProvenance , provenance )
2022-06-02 07:48:53 -05:00
}
rule . Updated = time . Now ( )
rule . ID = storedRule . ID
2022-08-11 17:54:57 -05:00
rule . IntervalSeconds = storedRule . IntervalSeconds
2022-12-16 04:47:25 -06:00
err = rule . SetDashboardAndPanelFromAnnotations ( )
2022-08-03 09:05:32 -05:00
if err != nil {
return models . AlertRule { } , err
}
2022-06-02 07:48:53 -05:00
err = service . xact . InTransaction ( ctx , func ( ctx context . Context ) error {
2022-09-29 15:47:56 -05:00
err := service . ruleStore . UpdateAlertRules ( ctx , [ ] models . UpdateRule {
2022-06-02 07:48:53 -05:00
{
Existing : & storedRule ,
New : rule ,
} ,
} )
if err != nil {
return err
}
return service . provenanceStore . SetProvenance ( ctx , & rule , rule . OrgID , provenance )
} )
if err != nil {
return models . AlertRule { } , err
}
return rule , err
}
func ( service * AlertRuleService ) DeleteAlertRule ( ctx context . Context , orgID int64 , ruleUID string , provenance models . Provenance ) error {
rule := & models . AlertRule {
OrgID : orgID ,
UID : ruleUID ,
}
2023-04-18 08:10:36 -05:00
// check that provenance is not changed in an invalid way
2022-06-02 07:48:53 -05:00
storedProvenance , err := service . provenanceStore . GetProvenance ( ctx , rule , rule . OrgID )
if err != nil {
return err
}
if storedProvenance != provenance && storedProvenance != models . ProvenanceNone {
return fmt . Errorf ( "cannot delete with provided provenance '%s', needs '%s'" , provenance , storedProvenance )
}
return service . xact . InTransaction ( ctx , func ( ctx context . Context ) error {
2022-08-10 12:33:41 -05:00
return service . deleteRules ( ctx , orgID , rule )
} )
}
// checkLimitsTransactionCtx checks whether the current transaction (as identified by the ctx) breaches configured alert rule limits.
func ( service * AlertRuleService ) checkLimitsTransactionCtx ( ctx context . Context , orgID , userID int64 ) error {
2022-12-08 08:34:46 -06:00
limitReached , err := service . quotas . CheckQuotaReached ( ctx , models . QuotaTargetSrv , & quota . ScopeParameters {
2022-08-10 12:33:41 -05:00
OrgID : orgID ,
UserID : userID ,
2022-06-02 07:48:53 -05:00
} )
2022-08-10 12:33:41 -05:00
if err != nil {
return fmt . Errorf ( "failed to check alert rule quota: %w" , err )
}
if limitReached {
return models . ErrQuotaReached
}
return nil
}
// deleteRules deletes a set of target rules and associated data, while checking for database consistency.
func ( service * AlertRuleService ) deleteRules ( ctx context . Context , orgID int64 , targets ... * models . AlertRule ) error {
uids := make ( [ ] string , 0 , len ( targets ) )
for _ , tgt := range targets {
if tgt != nil {
uids = append ( uids , tgt . UID )
}
}
if err := service . ruleStore . DeleteAlertRulesByUID ( ctx , orgID , uids ... ) ; err != nil {
return err
}
for _ , uid := range uids {
if err := service . provenanceStore . DeleteProvenance ( ctx , & models . AlertRule { UID : uid } , orgID ) ; err != nil {
// We failed to clean up the record, but this doesn't break things. Log it and move on.
2023-09-04 11:46:34 -05:00
service . log . Warn ( "Failed to delete provenance record for rule: %w" , err )
2022-08-10 12:33:41 -05:00
}
}
return nil
}
2023-01-27 10:39:16 -06:00
// GetAlertRuleGroupWithFolderTitle returns the alert rule group with folder title.
2023-03-29 12:34:59 -05:00
func ( service * AlertRuleService ) GetAlertRuleGroupWithFolderTitle ( ctx context . Context , orgID int64 , namespaceUID , group string ) ( models . AlertRuleGroupWithFolderTitle , error ) {
2023-01-27 10:39:16 -06:00
q := models . ListAlertRulesQuery {
OrgID : orgID ,
NamespaceUIDs : [ ] string { namespaceUID } ,
RuleGroup : group ,
}
2023-03-28 03:34:35 -05:00
ruleList , err := service . ruleStore . ListAlertRules ( ctx , & q )
if err != nil {
2023-03-29 12:34:59 -05:00
return models . AlertRuleGroupWithFolderTitle { } , err
2023-01-27 10:39:16 -06:00
}
2023-03-28 03:34:35 -05:00
if len ( ruleList ) == 0 {
2023-03-29 12:34:59 -05:00
return models . AlertRuleGroupWithFolderTitle { } , store . ErrAlertRuleGroupNotFound
2023-01-27 10:39:16 -06:00
}
dq := dashboards . GetDashboardQuery {
OrgID : orgID ,
UID : namespaceUID ,
}
dash , err := service . dashboardService . GetDashboard ( ctx , & dq )
if err != nil {
2023-03-29 12:34:59 -05:00
return models . AlertRuleGroupWithFolderTitle { } , err
2023-01-27 10:39:16 -06:00
}
2023-10-02 10:47:59 -05:00
res := models . NewAlertRuleGroupWithFolderTitleFromRulesGroup ( ruleList [ 0 ] . GetGroupKey ( ) , ruleList , dash . Title )
2023-01-27 10:39:16 -06:00
return res , nil
}
2023-09-11 12:13:02 -05:00
// GetAlertGroupsWithFolderTitle returns all groups with folder title in the folders identified by folderUID that have at least one alert. If argument folderUIDs is nil or empty - returns groups in all folders.
func ( service * AlertRuleService ) GetAlertGroupsWithFolderTitle ( ctx context . Context , orgID int64 , folderUIDs [ ] string ) ( [ ] models . AlertRuleGroupWithFolderTitle , error ) {
2023-01-27 10:39:16 -06:00
q := models . ListAlertRulesQuery {
OrgID : orgID ,
}
2023-09-11 12:13:02 -05:00
if len ( folderUIDs ) > 0 {
q . NamespaceUIDs = folderUIDs
2023-09-07 16:34:32 -05:00
}
2023-01-27 10:39:16 -06:00
2023-03-28 03:34:35 -05:00
ruleList , err := service . ruleStore . ListAlertRules ( ctx , & q )
if err != nil {
2023-01-27 10:39:16 -06:00
return nil , err
}
groups := make ( map [ models . AlertRuleGroupKey ] [ ] models . AlertRule )
namespaces := make ( map [ string ] [ ] * models . AlertRuleGroupKey )
2023-03-28 03:34:35 -05:00
for _ , r := range ruleList {
2023-01-27 10:39:16 -06:00
groupKey := r . GetGroupKey ( )
group := groups [ groupKey ]
group = append ( group , * r )
groups [ groupKey ] = group
namespaces [ r . NamespaceUID ] = append ( namespaces [ r . NamespaceUID ] , & groupKey )
}
2023-05-25 07:12:18 -05:00
if len ( namespaces ) == 0 {
return [ ] models . AlertRuleGroupWithFolderTitle { } , nil
}
2023-01-27 10:39:16 -06:00
dq := dashboards . GetDashboardsQuery {
DashboardUIDs : nil ,
}
for uid := range namespaces {
dq . DashboardUIDs = append ( dq . DashboardUIDs , uid )
}
// We need folder titles for the provisioning file format. We do it this way instead of using GetUserVisibleNamespaces to avoid folder:read permissions that should not apply to those with alert.provisioning:read.
dashes , err := service . dashboardService . GetDashboards ( ctx , & dq )
if err != nil {
return nil , err
}
folderUidToTitle := make ( map [ string ] string )
for _ , dash := range dashes {
folderUidToTitle [ dash . UID ] = dash . Title
}
2023-03-29 12:34:59 -05:00
result := make ( [ ] models . AlertRuleGroupWithFolderTitle , 0 )
2023-01-27 10:39:16 -06:00
for groupKey , rules := range groups {
title , ok := folderUidToTitle [ groupKey . NamespaceUID ]
if ! ok {
return nil , fmt . Errorf ( "cannot find title for folder with uid '%s'" , groupKey . NamespaceUID )
}
2023-10-02 10:47:59 -05:00
result = append ( result , models . NewAlertRuleGroupWithFolderTitle ( groupKey , rules , title ) )
2023-01-27 10:39:16 -06:00
}
// Return results in a stable manner.
2023-10-02 10:47:59 -05:00
models . SortAlertRuleGroupWithFolderTitle ( result )
2023-01-27 10:39:16 -06:00
return result , nil
}
2022-08-10 12:33:41 -05:00
// syncRuleGroupFields synchronizes calculated fields across multiple rules in a group.
2022-08-12 16:36:50 -05:00
func syncGroupRuleFields ( group * models . AlertRuleGroup , orgID int64 ) * models . AlertRuleGroup {
2022-08-10 12:33:41 -05:00
for i := range group . Rules {
group . Rules [ i ] . IntervalSeconds = group . Interval
group . Rules [ i ] . RuleGroup = group . Title
group . Rules [ i ] . NamespaceUID = group . FolderUID
group . Rules [ i ] . OrgID = orgID
}
return group
}
func withoutNilAlertRules ( ptrs [ ] * models . AlertRule ) [ ] models . AlertRule {
result := make ( [ ] models . AlertRule , 0 , len ( ptrs ) )
for _ , ptr := range ptrs {
if ptr != nil {
result = append ( result , * ptr )
}
}
return result
2022-06-02 07:48:53 -05:00
}