mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: rules delete API to check data source authorization (#46906)
* merge RuleSrv rule delete methods * remove unused store methods * implement delete by uid for fake store * add scheduler mock * implement tests for RouteDeleteAlertRules
This commit is contained in:
@@ -36,8 +36,6 @@ type UpsertRule struct {
|
||||
// Store is the interface for persisting alert rules and instances
|
||||
type RuleStore interface {
|
||||
DeleteAlertRulesByUID(ctx context.Context, orgID int64, ruleUID ...string) error
|
||||
DeleteNamespaceAlertRules(ctx context.Context, orgID int64, namespaceUID string) ([]string, error)
|
||||
DeleteRuleGroupAlertRules(ctx context.Context, orgID int64, namespaceUID string, ruleGroup string) ([]string, error)
|
||||
DeleteAlertInstancesByRuleUID(ctx context.Context, orgID int64, ruleUID string) error
|
||||
GetAlertRuleByUID(ctx context.Context, query *ngmodels.GetAlertRuleByUIDQuery) error
|
||||
GetAlertRulesForScheduling(ctx context.Context, query *ngmodels.ListAlertRulesQuery) error
|
||||
@@ -88,76 +86,6 @@ func (st DBstore) DeleteAlertRulesByUID(ctx context.Context, orgID int64, ruleUI
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteNamespaceAlertRules is a handler for deleting namespace alert rules. A list of deleted rule UIDs are returned.
|
||||
func (st DBstore) DeleteNamespaceAlertRules(ctx context.Context, orgID int64, namespaceUID string) ([]string, error) {
|
||||
ruleUIDs := []string{}
|
||||
|
||||
err := st.SQLStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
if err := sess.SQL("SELECT uid FROM alert_rule WHERE org_id = ? and namespace_uid = ?", orgID, namespaceUID).Find(&ruleUIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.Exec("DELETE FROM alert_rule WHERE org_id = ? and namespace_uid = ?", orgID, namespaceUID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.Exec("DELETE FROM alert_rule WHERE org_id = ? and namespace_uid = ?", orgID, namespaceUID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.Exec("DELETE FROM alert_rule_version WHERE rule_org_id = ? and rule_namespace_uid = ?", orgID, namespaceUID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.Exec(`DELETE FROM alert_instance WHERE rule_org_id = ? AND rule_uid NOT IN (
|
||||
SELECT uid FROM alert_rule where org_id = ?
|
||||
)`, orgID, orgID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return ruleUIDs, err
|
||||
}
|
||||
|
||||
// DeleteRuleGroupAlertRules is a handler for deleting rule group alert rules. A list of deleted rule UIDs are returned.
|
||||
func (st DBstore) DeleteRuleGroupAlertRules(ctx context.Context, orgID int64, namespaceUID string, ruleGroup string) ([]string, error) {
|
||||
ruleUIDs := []string{}
|
||||
|
||||
err := st.SQLStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
if err := sess.SQL("SELECT uid FROM alert_rule WHERE org_id = ? and namespace_uid = ? and rule_group = ?",
|
||||
orgID, namespaceUID, ruleGroup).Find(&ruleUIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
exist, err := sess.Exist(&ngmodels.AlertRule{OrgID: orgID, NamespaceUID: namespaceUID, RuleGroup: ruleGroup})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !exist {
|
||||
return ngmodels.ErrRuleGroupNamespaceNotFound
|
||||
}
|
||||
|
||||
if _, err := sess.Exec("DELETE FROM alert_rule WHERE org_id = ? and namespace_uid = ? and rule_group = ?", orgID, namespaceUID, ruleGroup); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.Exec("DELETE FROM alert_rule_version WHERE rule_org_id = ? and rule_namespace_uid = ? and rule_group = ?", orgID, namespaceUID, ruleGroup); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.Exec(`DELETE FROM alert_instance WHERE rule_org_id = ? AND rule_uid NOT IN (
|
||||
SELECT uid FROM alert_rule where org_id = ?
|
||||
)`, orgID, orgID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return ruleUIDs, err
|
||||
}
|
||||
|
||||
// DeleteAlertInstanceByRuleUID is a handler for deleting alert instances by alert rule UID when a rule has been updated
|
||||
func (st DBstore) DeleteAlertInstancesByRuleUID(ctx context.Context, orgID int64, ruleUID string) error {
|
||||
return st.SQLStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
|
||||
@@ -3,13 +3,16 @@ package store
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
|
||||
models2 "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
@@ -27,6 +30,7 @@ func NewFakeRuleStore(t *testing.T) *FakeRuleStore {
|
||||
Hook: func(interface{}) error {
|
||||
return nil
|
||||
},
|
||||
Folders: map[int64][]*models2.Folder{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +42,12 @@ type FakeRuleStore struct {
|
||||
Rules map[int64][]*models.AlertRule
|
||||
Hook func(cmd interface{}) error // use Hook if you need to intercept some query and return an error
|
||||
RecordedOps []interface{}
|
||||
Folders map[int64][]*models2.Folder
|
||||
}
|
||||
|
||||
type GenericRecordedQuery struct {
|
||||
Name string
|
||||
Params []interface{}
|
||||
}
|
||||
|
||||
// PutRule puts the rule in the Rules map. If there are existing rule in the same namespace, they will be overwritten
|
||||
@@ -55,6 +65,23 @@ mainloop:
|
||||
}
|
||||
rgs = append(rgs, r)
|
||||
f.Rules[r.OrgID] = rgs
|
||||
|
||||
var existing *models2.Folder
|
||||
folders := f.Folders[r.OrgID]
|
||||
for _, folder := range folders {
|
||||
if folder.Uid == r.NamespaceUID {
|
||||
existing = folder
|
||||
break
|
||||
}
|
||||
}
|
||||
if existing == nil {
|
||||
folders = append(folders, &models2.Folder{
|
||||
Id: rand.Int63(),
|
||||
Uid: r.NamespaceUID,
|
||||
Title: "TEST-FOLDER-" + util.GenerateShortUID(),
|
||||
})
|
||||
f.Folders[r.OrgID] = folders
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,15 +101,33 @@ func (f *FakeRuleStore) GetRecordedCommands(predicate func(cmd interface{}) (int
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *FakeRuleStore) DeleteAlertRulesByUID(_ context.Context, _ int64, _ ...string) error {
|
||||
func (f *FakeRuleStore) DeleteAlertRulesByUID(_ context.Context, orgID int64, UIDs ...string) error {
|
||||
f.RecordedOps = append(f.RecordedOps, GenericRecordedQuery{
|
||||
Name: "DeleteAlertRulesByUID",
|
||||
Params: []interface{}{orgID, UIDs},
|
||||
})
|
||||
|
||||
rules := f.Rules[orgID]
|
||||
|
||||
var result = make([]*models.AlertRule, 0, len(rules))
|
||||
|
||||
for _, rule := range rules {
|
||||
add := true
|
||||
for _, UID := range UIDs {
|
||||
if rule.UID == UID {
|
||||
add = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if add {
|
||||
result = append(result, rule)
|
||||
}
|
||||
}
|
||||
|
||||
f.Rules[orgID] = result
|
||||
return nil
|
||||
}
|
||||
func (f *FakeRuleStore) DeleteNamespaceAlertRules(_ context.Context, _ int64, _ string) ([]string, error) {
|
||||
return []string{}, nil
|
||||
}
|
||||
func (f *FakeRuleStore) DeleteRuleGroupAlertRules(_ context.Context, _ int64, _ string, _ string) ([]string, error) {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
func (f *FakeRuleStore) DeleteAlertInstancesByRuleUID(_ context.Context, _ int64, _ string) error {
|
||||
return nil
|
||||
}
|
||||
@@ -179,8 +224,14 @@ func (f *FakeRuleStore) GetNamespaces(_ context.Context, orgID int64, _ *models2
|
||||
}
|
||||
return namespacesMap, nil
|
||||
}
|
||||
func (f *FakeRuleStore) GetNamespaceByTitle(_ context.Context, _ string, _ int64, _ *models2.SignedInUser, _ bool) (*models2.Folder, error) {
|
||||
return nil, nil
|
||||
func (f *FakeRuleStore) GetNamespaceByTitle(_ context.Context, title string, orgID int64, _ *models2.SignedInUser, _ bool) (*models2.Folder, error) {
|
||||
folders := f.Folders[orgID]
|
||||
for _, folder := range folders {
|
||||
if folder.Title == title {
|
||||
return folder, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("not found")
|
||||
}
|
||||
func (f *FakeRuleStore) GetOrgRuleGroups(_ context.Context, q *models.ListOrgRuleGroupsQuery) error {
|
||||
f.mtx.Lock()
|
||||
|
||||
Reference in New Issue
Block a user