Alerting: Update rule provisioning service to accept user (#84480)

This commit is contained in:
Yuri Tseretyan
2024-03-14 12:04:10 -04:00
committed by GitHub
parent 6d19894a7d
commit f7d836feed
4 changed files with 156 additions and 142 deletions

View File

@ -58,17 +58,17 @@ type MuteTimingService interface {
}
type AlertRuleService interface {
GetAlertRules(ctx context.Context, orgID int64) ([]*alerting_models.AlertRule, map[string]alerting_models.Provenance, error)
GetAlertRule(ctx context.Context, orgID int64, ruleUID string) (alerting_models.AlertRule, alerting_models.Provenance, error)
GetAlertRules(ctx context.Context, user identity.Requester) ([]*alerting_models.AlertRule, map[string]alerting_models.Provenance, error)
GetAlertRule(ctx context.Context, user identity.Requester, ruleUID string) (alerting_models.AlertRule, alerting_models.Provenance, error)
CreateAlertRule(ctx context.Context, user identity.Requester, rule alerting_models.AlertRule, provenance alerting_models.Provenance) (alerting_models.AlertRule, error)
UpdateAlertRule(ctx context.Context, rule alerting_models.AlertRule, provenance alerting_models.Provenance) (alerting_models.AlertRule, error)
DeleteAlertRule(ctx context.Context, orgID int64, ruleUID string, provenance alerting_models.Provenance) error
GetRuleGroup(ctx context.Context, orgID int64, folder, group string) (alerting_models.AlertRuleGroup, error)
ReplaceRuleGroup(ctx context.Context, orgID int64, group alerting_models.AlertRuleGroup, userID int64, provenance alerting_models.Provenance) error
DeleteRuleGroup(ctx context.Context, orgID int64, folder, group string, provenance alerting_models.Provenance) error
GetAlertRuleWithFolderTitle(ctx context.Context, orgID int64, ruleUID string) (provisioning.AlertRuleWithFolderTitle, error)
GetAlertRuleGroupWithFolderTitle(ctx context.Context, orgID int64, folder, group string) (alerting_models.AlertRuleGroupWithFolderTitle, error)
GetAlertGroupsWithFolderTitle(ctx context.Context, orgID int64, folderUIDs []string) ([]alerting_models.AlertRuleGroupWithFolderTitle, error)
UpdateAlertRule(ctx context.Context, user identity.Requester, rule alerting_models.AlertRule, provenance alerting_models.Provenance) (alerting_models.AlertRule, error)
DeleteAlertRule(ctx context.Context, user identity.Requester, ruleUID string, provenance alerting_models.Provenance) error
GetRuleGroup(ctx context.Context, user identity.Requester, folder, group string) (alerting_models.AlertRuleGroup, error)
ReplaceRuleGroup(ctx context.Context, user identity.Requester, group alerting_models.AlertRuleGroup, provenance alerting_models.Provenance) error
DeleteRuleGroup(ctx context.Context, user identity.Requester, folder, group string, provenance alerting_models.Provenance) error
GetAlertRuleWithFolderTitle(ctx context.Context, user identity.Requester, ruleUID string) (provisioning.AlertRuleWithFolderTitle, error)
GetAlertRuleGroupWithFolderTitle(ctx context.Context, user identity.Requester, folder, group string) (alerting_models.AlertRuleGroupWithFolderTitle, error)
GetAlertGroupsWithFolderTitle(ctx context.Context, user identity.Requester, folderUIDs []string) ([]alerting_models.AlertRuleGroupWithFolderTitle, error)
}
func (srv *ProvisioningSrv) RouteGetPolicyTree(c *contextmodel.ReqContext) response.Response {
@ -309,7 +309,7 @@ func (srv *ProvisioningSrv) RouteDeleteMuteTiming(c *contextmodel.ReqContext, na
}
func (srv *ProvisioningSrv) RouteGetAlertRules(c *contextmodel.ReqContext) response.Response {
rules, provenances, err := srv.alertRules.GetAlertRules(c.Req.Context(), c.SignedInUser.GetOrgID())
rules, provenances, err := srv.alertRules.GetAlertRules(c.Req.Context(), c.SignedInUser)
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
@ -317,7 +317,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRules(c *contextmodel.ReqContext) respo
}
func (srv *ProvisioningSrv) RouteRouteGetAlertRule(c *contextmodel.ReqContext, UID string) response.Response {
rule, provenace, err := srv.alertRules.GetAlertRule(c.Req.Context(), c.SignedInUser.GetOrgID(), UID)
rule, provenace, err := srv.alertRules.GetAlertRule(c.Req.Context(), c.SignedInUser, UID)
if err != nil {
if errors.Is(err, alerting_models.ErrAlertRuleNotFound) {
return response.Empty(http.StatusNotFound)
@ -363,7 +363,7 @@ func (srv *ProvisioningSrv) RoutePutAlertRule(c *contextmodel.ReqContext, ar def
updated.OrgID = c.SignedInUser.GetOrgID()
updated.UID = UID
provenance := determineProvenance(c)
updatedAlertRule, err := srv.alertRules.UpdateAlertRule(c.Req.Context(), updated, alerting_models.Provenance(provenance))
updatedAlertRule, err := srv.alertRules.UpdateAlertRule(c.Req.Context(), c.SignedInUser, updated, alerting_models.Provenance(provenance))
if errors.Is(err, alerting_models.ErrAlertRuleUniqueConstraintViolation) {
return ErrResp(http.StatusBadRequest, err, "")
}
@ -386,7 +386,7 @@ func (srv *ProvisioningSrv) RoutePutAlertRule(c *contextmodel.ReqContext, ar def
func (srv *ProvisioningSrv) RouteDeleteAlertRule(c *contextmodel.ReqContext, UID string) response.Response {
provenance := determineProvenance(c)
err := srv.alertRules.DeleteAlertRule(c.Req.Context(), c.SignedInUser.GetOrgID(), UID, alerting_models.Provenance(provenance))
err := srv.alertRules.DeleteAlertRule(c.Req.Context(), c.SignedInUser, UID, alerting_models.Provenance(provenance))
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
@ -394,7 +394,7 @@ func (srv *ProvisioningSrv) RouteDeleteAlertRule(c *contextmodel.ReqContext, UID
}
func (srv *ProvisioningSrv) RouteGetAlertRuleGroup(c *contextmodel.ReqContext, folder string, group string) response.Response {
g, err := srv.alertRules.GetRuleGroup(c.Req.Context(), c.SignedInUser.GetOrgID(), folder, group)
g, err := srv.alertRules.GetRuleGroup(c.Req.Context(), c.SignedInUser, folder, group)
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "", err)
}
@ -422,7 +422,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRulesExport(c *contextmodel.ReqContext)
return srv.RouteGetAlertRuleGroupExport(c, folderUIDs[0], group)
}
groupsWithTitle, err := srv.alertRules.GetAlertGroupsWithFolderTitle(c.Req.Context(), c.SignedInUser.GetOrgID(), folderUIDs)
groupsWithTitle, err := srv.alertRules.GetAlertGroupsWithFolderTitle(c.Req.Context(), c.SignedInUser, folderUIDs)
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "failed to get alert rules")
}
@ -440,7 +440,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRulesExport(c *contextmodel.ReqContext)
// RouteGetAlertRuleGroupExport retrieves the given alert rule group in a format compatible with file provisioning.
func (srv *ProvisioningSrv) RouteGetAlertRuleGroupExport(c *contextmodel.ReqContext, folder string, group string) response.Response {
g, err := srv.alertRules.GetAlertRuleGroupWithFolderTitle(c.Req.Context(), c.SignedInUser.GetOrgID(), folder, group)
g, err := srv.alertRules.GetAlertRuleGroupWithFolderTitle(c.Req.Context(), c.SignedInUser, folder, group)
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "failed to get alert rule group", err)
}
@ -455,7 +455,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRuleGroupExport(c *contextmodel.ReqCont
// RouteGetAlertRuleExport retrieves the given alert rule in a format compatible with file provisioning.
func (srv *ProvisioningSrv) RouteGetAlertRuleExport(c *contextmodel.ReqContext, UID string) response.Response {
rule, err := srv.alertRules.GetAlertRuleWithFolderTitle(c.Req.Context(), c.SignedInUser.GetOrgID(), UID)
rule, err := srv.alertRules.GetAlertRuleWithFolderTitle(c.Req.Context(), c.SignedInUser, UID)
if err != nil {
if errors.Is(err, alerting_models.ErrAlertRuleNotFound) {
return ErrResp(http.StatusNotFound, err, "")
@ -481,9 +481,7 @@ func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *contextmodel.ReqContext, a
ErrResp(http.StatusBadRequest, err, "")
}
provenance := determineProvenance(c)
userID, _ := identity.UserIdentifier(c.SignedInUser.GetNamespacedID())
err = srv.alertRules.ReplaceRuleGroup(c.Req.Context(), c.SignedInUser.GetOrgID(), groupModel, userID, alerting_models.Provenance(provenance))
err = srv.alertRules.ReplaceRuleGroup(c.Req.Context(), c.SignedInUser, groupModel, alerting_models.Provenance(provenance))
if errors.Is(err, alerting_models.ErrAlertRuleUniqueConstraintViolation) {
return ErrResp(http.StatusBadRequest, err, "")
}
@ -501,7 +499,7 @@ func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *contextmodel.ReqContext, a
func (srv *ProvisioningSrv) RouteDeleteAlertRuleGroup(c *contextmodel.ReqContext, folderUID string, group string) response.Response {
provenance := determineProvenance(c)
err := srv.alertRules.DeleteRuleGroup(c.Req.Context(), c.SignedInUser.GetOrgID(), folderUID, group, alerting_models.Provenance(provenance))
err := srv.alertRules.DeleteRuleGroup(c.Req.Context(), c.SignedInUser, folderUID, group, alerting_models.Provenance(provenance))
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "", err)
}

View File

@ -62,9 +62,9 @@ func NewAlertRuleService(ruleStore RuleStore,
}
}
func (service *AlertRuleService) GetAlertRules(ctx context.Context, orgID int64) ([]*models.AlertRule, map[string]models.Provenance, error) {
func (service *AlertRuleService) GetAlertRules(ctx context.Context, user identity.Requester) ([]*models.AlertRule, map[string]models.Provenance, error) {
q := models.ListAlertRulesQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
}
rules, err := service.ruleStore.ListAlertRules(ctx, &q)
if err != nil {
@ -73,7 +73,7 @@ func (service *AlertRuleService) GetAlertRules(ctx context.Context, orgID int64)
provenances := make(map[string]models.Provenance)
if len(rules) > 0 {
resourceType := rules[0].ResourceType()
provenances, err = service.provenanceStore.GetProvenances(ctx, orgID, resourceType)
provenances, err = service.provenanceStore.GetProvenances(ctx, user.GetOrgID(), resourceType)
if err != nil {
return nil, nil, err
}
@ -81,16 +81,16 @@ func (service *AlertRuleService) GetAlertRules(ctx context.Context, orgID int64)
return rules, provenances, nil
}
func (service *AlertRuleService) GetAlertRule(ctx context.Context, orgID int64, ruleUID string) (models.AlertRule, models.Provenance, error) {
func (service *AlertRuleService) GetAlertRule(ctx context.Context, user identity.Requester, ruleUID string) (models.AlertRule, models.Provenance, error) {
query := &models.GetAlertRuleByUIDQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
UID: ruleUID,
}
rule, err := service.ruleStore.GetAlertRuleByUID(ctx, query)
if err != nil {
return models.AlertRule{}, models.ProvenanceNone, err
}
provenance, err := service.provenanceStore.GetProvenance(ctx, rule, orgID)
provenance, err := service.provenanceStore.GetProvenance(ctx, rule, user.GetOrgID())
if err != nil {
return models.AlertRule{}, models.ProvenanceNone, err
}
@ -103,9 +103,9 @@ type AlertRuleWithFolderTitle struct {
}
// GetAlertRuleWithFolderTitle returns a single alert rule with its folder title.
func (service *AlertRuleService) GetAlertRuleWithFolderTitle(ctx context.Context, orgID int64, ruleUID string) (AlertRuleWithFolderTitle, error) {
func (service *AlertRuleService) GetAlertRuleWithFolderTitle(ctx context.Context, user identity.Requester, ruleUID string) (AlertRuleWithFolderTitle, error) {
query := &models.GetAlertRuleByUIDQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
UID: ruleUID,
}
rule, err := service.ruleStore.GetAlertRuleByUID(ctx, query)
@ -114,7 +114,7 @@ func (service *AlertRuleService) GetAlertRuleWithFolderTitle(ctx context.Context
}
dq := dashboards.GetDashboardQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
UID: rule.NamespaceUID,
}
@ -184,12 +184,7 @@ func (service *AlertRuleService) CreateAlertRule(ctx context.Context, user ident
return errors.New("couldn't find newly created id")
}
// default to 0 if there is no user
userID := int64(0)
if user != nil {
userID, _ = identity.UserIdentifier(user.GetNamespacedID())
}
if err = service.checkLimitsTransactionCtx(ctx, rule.OrgID, userID); err != nil {
if err = service.checkLimitsTransactionCtx(ctx, user); err != nil {
return err
}
@ -201,9 +196,9 @@ func (service *AlertRuleService) CreateAlertRule(ctx context.Context, user ident
return rule, nil
}
func (service *AlertRuleService) GetRuleGroup(ctx context.Context, orgID int64, namespaceUID, group string) (models.AlertRuleGroup, error) {
func (service *AlertRuleService) GetRuleGroup(ctx context.Context, user identity.Requester, namespaceUID, group string) (models.AlertRuleGroup, error) {
q := models.ListAlertRulesQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
NamespaceUIDs: []string{namespaceUID},
RuleGroup: group,
}
@ -229,13 +224,13 @@ func (service *AlertRuleService) GetRuleGroup(ctx context.Context, orgID int64,
}
// UpdateRuleGroup will update the interval for all rules in the group.
func (service *AlertRuleService) UpdateRuleGroup(ctx context.Context, orgID int64, namespaceUID string, ruleGroup string, intervalSeconds int64) error {
func (service *AlertRuleService) UpdateRuleGroup(ctx context.Context, user identity.Requester, namespaceUID string, ruleGroup string, intervalSeconds int64) error {
if err := models.ValidateRuleGroupInterval(intervalSeconds, service.baseIntervalSeconds); err != nil {
return err
}
return service.xact.InTransaction(ctx, func(ctx context.Context) error {
query := &models.ListAlertRulesQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
NamespaceUIDs: []string{namespaceUID},
RuleGroup: ruleGroup,
}
@ -259,12 +254,12 @@ func (service *AlertRuleService) UpdateRuleGroup(ctx context.Context, orgID int6
})
}
func (service *AlertRuleService) ReplaceRuleGroup(ctx context.Context, orgID int64, group models.AlertRuleGroup, userID int64, provenance models.Provenance) error {
func (service *AlertRuleService) ReplaceRuleGroup(ctx context.Context, user identity.Requester, group models.AlertRuleGroup, provenance models.Provenance) error {
if err := models.ValidateRuleGroupInterval(group.Interval, service.baseIntervalSeconds); err != nil {
return err
}
delta, err := service.calcDelta(ctx, orgID, group)
delta, err := service.calcDelta(ctx, user, group)
if err != nil {
return err
}
@ -286,13 +281,13 @@ func (service *AlertRuleService) ReplaceRuleGroup(ctx context.Context, orgID int
}
}
return service.persistDelta(ctx, orgID, delta, userID, provenance)
return service.persistDelta(ctx, user, delta, provenance)
}
func (service *AlertRuleService) DeleteRuleGroup(ctx context.Context, orgID int64, namespaceUID, group string, provenance models.Provenance) error {
func (service *AlertRuleService) DeleteRuleGroup(ctx context.Context, user identity.Requester, namespaceUID, group string, provenance models.Provenance) error {
// List all rules in the group.
q := models.ListAlertRulesQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
NamespaceUIDs: []string{namespaceUID},
RuleGroup: group,
}
@ -317,16 +312,16 @@ func (service *AlertRuleService) DeleteRuleGroup(ctx context.Context, orgID int6
// Delete all rules.
return service.xact.InTransaction(ctx, func(ctx context.Context) error {
return service.deleteRules(ctx, orgID, ruleList...)
return service.deleteRules(ctx, user.GetOrgID(), ruleList...)
})
}
func (service *AlertRuleService) calcDelta(ctx context.Context, orgID int64, group models.AlertRuleGroup) (*store.GroupDelta, error) {
func (service *AlertRuleService) calcDelta(ctx context.Context, user identity.Requester, group models.AlertRuleGroup) (*store.GroupDelta, error) {
// 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,
OrgID: user.GetOrgID(),
NamespaceUIDs: []string{group.FolderUID},
RuleGroup: group.Title,
}
@ -347,12 +342,12 @@ func (service *AlertRuleService) calcDelta(ctx context.Context, orgID int64, gro
}
key := models.AlertRuleGroupKey{
OrgID: orgID,
OrgID: user.GetOrgID(),
NamespaceUID: group.FolderUID,
RuleGroup: group.Title,
}
rules := make([]*models.AlertRuleWithOptionals, len(group.Rules))
group = *syncGroupRuleFields(&group, orgID)
group = *syncGroupRuleFields(&group, user.GetOrgID())
for i := range group.Rules {
if err := group.Rules[i].SetDashboardAndPanelFromAnnotations(); err != nil {
return nil, err
@ -368,13 +363,13 @@ func (service *AlertRuleService) calcDelta(ctx context.Context, orgID int64, gro
return store.UpdateCalculatedRuleFields(delta), nil
}
func (service *AlertRuleService) persistDelta(ctx context.Context, orgID int64, delta *store.GroupDelta, userID int64, provenance models.Provenance) error {
func (service *AlertRuleService) persistDelta(ctx context.Context, user identity.Requester, delta *store.GroupDelta, provenance models.Provenance) error {
return service.xact.InTransaction(ctx, func(ctx context.Context) error {
// 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)
storedProvenance, err := service.provenanceStore.GetProvenance(ctx, del, user.GetOrgID())
if err != nil {
return err
}
@ -382,7 +377,7 @@ func (service *AlertRuleService) persistDelta(ctx context.Context, orgID int64,
return fmt.Errorf("cannot update with provided provenance '%s', needs '%s'", provenance, storedProvenance)
}
}
if err := service.deleteRules(ctx, orgID, delta.Delete...); err != nil {
if err := service.deleteRules(ctx, user.GetOrgID(), delta.Delete...); err != nil {
return err
}
}
@ -391,7 +386,7 @@ func (service *AlertRuleService) persistDelta(ctx context.Context, orgID int64,
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)
storedProvenance, err := service.provenanceStore.GetProvenance(ctx, update.New, user.GetOrgID())
if err != nil {
return err
}
@ -407,7 +402,7 @@ func (service *AlertRuleService) persistDelta(ctx context.Context, orgID int64,
return fmt.Errorf("failed to update alert rules: %w", err)
}
for _, update := range delta.Update {
if err := service.provenanceStore.SetProvenance(ctx, update.New, orgID, provenance); err != nil {
if err := service.provenanceStore.SetProvenance(ctx, update.New, user.GetOrgID(), provenance); err != nil {
return err
}
}
@ -419,13 +414,13 @@ func (service *AlertRuleService) persistDelta(ctx context.Context, orgID int64,
return fmt.Errorf("failed to insert alert rules: %w", err)
}
for _, key := range uids {
if err := service.provenanceStore.SetProvenance(ctx, &models.AlertRule{UID: key.UID}, orgID, provenance); err != nil {
if err := service.provenanceStore.SetProvenance(ctx, &models.AlertRule{UID: key.UID}, user.GetOrgID(), provenance); err != nil {
return err
}
}
}
if err := service.checkLimitsTransactionCtx(ctx, orgID, userID); err != nil {
if err := service.checkLimitsTransactionCtx(ctx, user); err != nil {
return err
}
@ -434,8 +429,8 @@ func (service *AlertRuleService) persistDelta(ctx context.Context, orgID int64,
}
// UpdateAlertRule updates an alert rule.
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)
func (service *AlertRuleService) UpdateAlertRule(ctx context.Context, user identity.Requester, rule models.AlertRule, provenance models.Provenance) (models.AlertRule, error) {
storedRule, storedProvenance, err := service.GetAlertRule(ctx, user, rule.UID)
if err != nil {
return models.AlertRule{}, err
}
@ -478,9 +473,9 @@ func (service *AlertRuleService) UpdateAlertRule(ctx context.Context, rule model
return rule, err
}
func (service *AlertRuleService) DeleteAlertRule(ctx context.Context, orgID int64, ruleUID string, provenance models.Provenance) error {
func (service *AlertRuleService) DeleteAlertRule(ctx context.Context, user identity.Requester, ruleUID string, provenance models.Provenance) error {
rule := &models.AlertRule{
OrgID: orgID,
OrgID: user.GetOrgID(),
UID: ruleUID,
}
// check that provenance is not changed in an invalid way
@ -492,14 +487,22 @@ func (service *AlertRuleService) DeleteAlertRule(ctx context.Context, orgID int6
return fmt.Errorf("cannot delete with provided provenance '%s', needs '%s'", provenance, storedProvenance)
}
return service.xact.InTransaction(ctx, func(ctx context.Context) error {
return service.deleteRules(ctx, orgID, rule)
return service.deleteRules(ctx, user.GetOrgID(), 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 {
func (service *AlertRuleService) checkLimitsTransactionCtx(ctx context.Context, user identity.Requester) error {
// default to 0 if there is no user
userID := int64(0)
u, err := identity.UserIdentifier(user.GetNamespacedID())
if err != nil {
return fmt.Errorf("failed to check alert rule quota: %w", err)
}
userID = u
limitReached, err := service.quotas.CheckQuotaReached(ctx, models.QuotaTargetSrv, &quota.ScopeParameters{
OrgID: orgID,
OrgID: user.GetOrgID(),
UserID: userID,
})
if err != nil {
@ -532,9 +535,9 @@ func (service *AlertRuleService) deleteRules(ctx context.Context, orgID int64, t
}
// GetAlertRuleGroupWithFolderTitle returns the alert rule group with folder title.
func (service *AlertRuleService) GetAlertRuleGroupWithFolderTitle(ctx context.Context, orgID int64, namespaceUID, group string) (models.AlertRuleGroupWithFolderTitle, error) {
func (service *AlertRuleService) GetAlertRuleGroupWithFolderTitle(ctx context.Context, user identity.Requester, namespaceUID, group string) (models.AlertRuleGroupWithFolderTitle, error) {
q := models.ListAlertRulesQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
NamespaceUIDs: []string{namespaceUID},
RuleGroup: group,
}
@ -547,7 +550,7 @@ func (service *AlertRuleService) GetAlertRuleGroupWithFolderTitle(ctx context.Co
}
dq := dashboards.GetDashboardQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
UID: namespaceUID,
}
dash, err := service.dashboardService.GetDashboard(ctx, &dq)
@ -560,9 +563,9 @@ func (service *AlertRuleService) GetAlertRuleGroupWithFolderTitle(ctx context.Co
}
// 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) {
func (service *AlertRuleService) GetAlertGroupsWithFolderTitle(ctx context.Context, user identity.Requester, folderUIDs []string) ([]models.AlertRuleGroupWithFolderTitle, error) {
q := models.ListAlertRulesQuery{
OrgID: orgID,
OrgID: user.GetOrgID(),
}
if len(folderUIDs) > 0 {

View File

@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/infra/db"
@ -25,17 +26,21 @@ import (
func TestAlertRuleService(t *testing.T) {
ruleService := createAlertRuleService(t)
var orgID int64 = 1
u := &user.SignedInUser{
UserID: 1,
OrgID: orgID,
}
t.Run("group creation should set the right provenance", func(t *testing.T) {
group := createDummyGroup("group-test-1", orgID)
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "group-test-1")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "group-test-1")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
for _, rule := range readGroup.Rules {
_, provenance, err := ruleService.GetAlertRule(context.Background(), orgID, rule.UID)
_, provenance, err := ruleService.GetAlertRule(context.Background(), u, rule.UID)
require.NoError(t, err)
require.Equal(t, models.ProvenanceAPI, provenance)
}
@ -44,15 +49,15 @@ func TestAlertRuleService(t *testing.T) {
t.Run("alert rule group should be updated correctly", func(t *testing.T) {
rule := dummyRule("test#3", orgID)
rule.RuleGroup = "a"
rule, err := ruleService.CreateAlertRule(context.Background(), nil, rule, models.ProvenanceNone)
rule, err := ruleService.CreateAlertRule(context.Background(), u, rule, models.ProvenanceNone)
require.NoError(t, err)
require.Equal(t, int64(60), rule.IntervalSeconds)
var interval int64 = 120
err = ruleService.UpdateRuleGroup(context.Background(), orgID, rule.NamespaceUID, rule.RuleGroup, 120)
err = ruleService.UpdateRuleGroup(context.Background(), u, rule.NamespaceUID, rule.RuleGroup, 120)
require.NoError(t, err)
rule, _, err = ruleService.GetAlertRule(context.Background(), orgID, rule.UID)
rule, _, err = ruleService.GetAlertRule(context.Background(), u, rule.UID)
require.NoError(t, err)
require.Equal(t, interval, rule.IntervalSeconds)
})
@ -61,24 +66,24 @@ func TestAlertRuleService(t *testing.T) {
var orgID int64 = 2
rule := dummyRule("test#1", orgID)
rule.NamespaceUID = "123abc"
rule, err := ruleService.CreateAlertRule(context.Background(), nil, rule, models.ProvenanceNone)
u := &user.SignedInUser{OrgID: orgID}
rule, err := ruleService.CreateAlertRule(context.Background(), u, rule, models.ProvenanceNone)
require.NoError(t, err)
rule.NamespaceUID = "abc123"
_, err = ruleService.UpdateAlertRule(context.Background(),
rule, models.ProvenanceNone)
_, err = ruleService.UpdateAlertRule(context.Background(), u, rule, models.ProvenanceNone)
require.NoError(t, err)
})
t.Run("group update should propagate folderUID from group to rules", func(t *testing.T) {
ruleService := createAlertRuleService(t)
group := createDummyGroup("namespace-test", 1)
group := createDummyGroup("namespace-test", orgID)
group.Rules[0].NamespaceUID = ""
err := ruleService.ReplaceRuleGroup(context.Background(), 1, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "namespace-test")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "namespace-test")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
require.Equal(t, "my-namespace", readGroup.Rules[0].NamespaceUID)
@ -88,10 +93,10 @@ func TestAlertRuleService(t *testing.T) {
group := createDummyGroup("group-test-3", orgID)
group.Rules[0].RuleGroup = "something different"
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "group-test-3")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "group-test-3")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
for _, rule := range readGroup.Rules {
@ -102,16 +107,16 @@ func TestAlertRuleService(t *testing.T) {
t.Run("alert rule should get interval from existing rule group", func(t *testing.T) {
rule := dummyRule("test#4", orgID)
rule.RuleGroup = "b"
rule, err := ruleService.CreateAlertRule(context.Background(), nil, rule, models.ProvenanceNone)
rule, err := ruleService.CreateAlertRule(context.Background(), u, rule, models.ProvenanceNone)
require.NoError(t, err)
var interval int64 = 120
err = ruleService.UpdateRuleGroup(context.Background(), orgID, rule.NamespaceUID, rule.RuleGroup, 120)
err = ruleService.UpdateRuleGroup(context.Background(), u, rule.NamespaceUID, rule.RuleGroup, 120)
require.NoError(t, err)
rule = dummyRule("test#4-1", orgID)
rule.RuleGroup = "b"
rule, err = ruleService.CreateAlertRule(context.Background(), nil, rule, models.ProvenanceNone)
rule, err = ruleService.CreateAlertRule(context.Background(), u, rule, models.ProvenanceNone)
require.NoError(t, err)
require.Equal(t, interval, rule.IntervalSeconds)
})
@ -124,22 +129,23 @@ func TestAlertRuleService(t *testing.T) {
ruleGroup = "abc"
newInterval int64 = 120
)
u := &user.SignedInUser{OrgID: orgID}
rule := dummyRule("my_rule", orgID)
rule.UID = ruleUID
rule.RuleGroup = ruleGroup
rule.NamespaceUID = namespaceUID
_, err := ruleService.CreateAlertRule(context.Background(), nil, rule, models.ProvenanceNone)
_, err := ruleService.CreateAlertRule(context.Background(), u, rule, models.ProvenanceNone)
require.NoError(t, err)
rule, _, err = ruleService.GetAlertRule(context.Background(), orgID, ruleUID)
rule, _, err = ruleService.GetAlertRule(context.Background(), u, ruleUID)
require.NoError(t, err)
require.Equal(t, int64(1), rule.Version)
require.Equal(t, int64(60), rule.IntervalSeconds)
err = ruleService.UpdateRuleGroup(context.Background(), orgID, namespaceUID, ruleGroup, newInterval)
err = ruleService.UpdateRuleGroup(context.Background(), u, namespaceUID, ruleGroup, newInterval)
require.NoError(t, err)
rule, _, err = ruleService.GetAlertRule(context.Background(), orgID, ruleUID)
rule, _, err = ruleService.GetAlertRule(context.Background(), u, ruleUID)
require.NoError(t, err)
require.Equal(t, int64(2), rule.Version)
require.Equal(t, newInterval, rule.IntervalSeconds)
@ -147,16 +153,16 @@ func TestAlertRuleService(t *testing.T) {
t.Run("updating a group by updating a rule should bump that rule's data and version number", func(t *testing.T) {
group := createDummyGroup("group-test-5", orgID)
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "group-test-5")
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "group-test-5")
require.NoError(t, err)
updatedGroup.Rules[0].Title = "some-other-title-asdf"
err = ruleService.ReplaceRuleGroup(context.Background(), orgID, updatedGroup, 0, models.ProvenanceAPI)
err = ruleService.ReplaceRuleGroup(context.Background(), u, updatedGroup, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "group-test-5")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "group-test-5")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
require.Len(t, readGroup.Rules, 1)
@ -175,17 +181,17 @@ func TestAlertRuleService(t *testing.T) {
dummyRule("overlap-test-rule-2", orgID),
},
}
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "overlap-test")
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "overlap-test")
require.NoError(t, err)
updatedGroup.Rules[0].Title = "overlap-test-rule-2"
updatedGroup.Rules[1].Title = "overlap-test-rule-3"
err = ruleService.ReplaceRuleGroup(context.Background(), orgID, updatedGroup, 0, models.ProvenanceAPI)
err = ruleService.ReplaceRuleGroup(context.Background(), u, updatedGroup, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "overlap-test")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "overlap-test")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
require.Len(t, readGroup.Rules, 2)
@ -206,17 +212,17 @@ func TestAlertRuleService(t *testing.T) {
dummyRule("swap-test-rule-2", orgID),
},
}
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "swap-test")
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "swap-test")
require.NoError(t, err)
updatedGroup.Rules[0].Title = "swap-test-rule-2"
updatedGroup.Rules[1].Title = "swap-test-rule-1"
err = ruleService.ReplaceRuleGroup(context.Background(), orgID, updatedGroup, 0, models.ProvenanceAPI)
err = ruleService.ReplaceRuleGroup(context.Background(), u, updatedGroup, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "swap-test")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "swap-test")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
require.Len(t, readGroup.Rules, 2)
@ -238,18 +244,18 @@ func TestAlertRuleService(t *testing.T) {
dummyRule("cycle-test-rule-3", orgID),
},
}
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "cycle-test")
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "cycle-test")
require.NoError(t, err)
updatedGroup.Rules[0].Title = "cycle-test-rule-2"
updatedGroup.Rules[1].Title = "cycle-test-rule-3"
updatedGroup.Rules[2].Title = "cycle-test-rule-1"
err = ruleService.ReplaceRuleGroup(context.Background(), orgID, updatedGroup, 0, models.ProvenanceAPI)
err = ruleService.ReplaceRuleGroup(context.Background(), u, updatedGroup, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "cycle-test")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "cycle-test")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
require.Len(t, readGroup.Rules, 3)
@ -276,9 +282,9 @@ func TestAlertRuleService(t *testing.T) {
dummyRule("multi-cycle-test-rule-5", orgID),
},
}
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "multi-cycle-test")
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "multi-cycle-test")
require.NoError(t, err)
updatedGroup.Rules[0].Title = "multi-cycle-test-rule-2"
@ -288,10 +294,10 @@ func TestAlertRuleService(t *testing.T) {
updatedGroup.Rules[3].Title = "multi-cycle-test-rule-5"
updatedGroup.Rules[4].Title = "multi-cycle-test-rule-3"
err = ruleService.ReplaceRuleGroup(context.Background(), orgID, updatedGroup, 0, models.ProvenanceAPI)
err = ruleService.ReplaceRuleGroup(context.Background(), u, updatedGroup, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "multi-cycle-test")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "multi-cycle-test")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
require.Len(t, readGroup.Rules, 5)
@ -317,7 +323,7 @@ func TestAlertRuleService(t *testing.T) {
dummyRule("recreate-test-rule-1", orgID),
},
}
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
updatedGroup := models.AlertRuleGroup{
Title: "recreate-test",
@ -327,10 +333,10 @@ func TestAlertRuleService(t *testing.T) {
dummyRule("recreate-test-rule-1", orgID),
},
}
err = ruleService.ReplaceRuleGroup(context.Background(), orgID, updatedGroup, 0, models.ProvenanceAPI)
err = ruleService.ReplaceRuleGroup(context.Background(), u, updatedGroup, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "recreate-test")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "recreate-test")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
require.Len(t, readGroup.Rules, 1)
@ -348,17 +354,17 @@ func TestAlertRuleService(t *testing.T) {
dummyRule("create-overlap-test-rule-1", orgID),
},
}
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "create-overlap-test")
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "create-overlap-test")
require.NoError(t, err)
updatedGroup.Rules[0].Title = "create-overlap-test-rule-2"
updatedGroup.Rules = append(updatedGroup.Rules, dummyRule("create-overlap-test-rule-1", orgID))
err = ruleService.ReplaceRuleGroup(context.Background(), orgID, updatedGroup, 0, models.ProvenanceAPI)
err = ruleService.ReplaceRuleGroup(context.Background(), u, updatedGroup, models.ProvenanceAPI)
require.NoError(t, err)
readGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "create-overlap-test")
readGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "create-overlap-test")
require.NoError(t, err)
require.NotEmpty(t, readGroup.Rules)
require.Len(t, readGroup.Rules, 2)
@ -377,9 +383,9 @@ func TestAlertRuleService(t *testing.T) {
models.PanelIDAnnotation: strconv.FormatInt(panelId, 10),
}
err := ruleService.ReplaceRuleGroup(context.Background(), orgID, group, 0, models.ProvenanceAPI)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.NoError(t, err)
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), orgID, "my-namespace", "group-test-5")
updatedGroup, err := ruleService.GetRuleGroup(context.Background(), u, "my-namespace", "group-test-5")
require.NoError(t, err)
require.NotNil(t, updatedGroup.Rules[0].DashboardUID)
@ -434,12 +440,11 @@ func TestAlertRuleService(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var orgID int64 = 1
rule := dummyRule(t.Name(), orgID)
rule, err := ruleService.CreateAlertRule(context.Background(), nil, rule, test.from)
rule, err := ruleService.CreateAlertRule(context.Background(), u, rule, test.from)
require.NoError(t, err)
_, err = ruleService.UpdateAlertRule(context.Background(), rule, test.to)
_, err = ruleService.UpdateAlertRule(context.Background(), u, rule, test.to)
if test.errNil {
require.NoError(t, err)
} else {
@ -497,11 +502,11 @@ func TestAlertRuleService(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
var orgID int64 = 1
group := createDummyGroup(t.Name(), orgID)
err := ruleService.ReplaceRuleGroup(context.Background(), 1, group, 0, test.from)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, test.from)
require.NoError(t, err)
group.Rules[0].Title = t.Name()
err = ruleService.ReplaceRuleGroup(context.Background(), 1, group, 0, test.to)
err = ruleService.ReplaceRuleGroup(context.Background(), u, group, test.to)
if test.errNil {
require.NoError(t, err)
} else {
@ -517,7 +522,7 @@ func TestAlertRuleService(t *testing.T) {
checker.EXPECT().LimitExceeded()
ruleService.quotas = checker
_, err := ruleService.CreateAlertRule(context.Background(), nil, dummyRule("test#1", orgID), models.ProvenanceNone)
_, err := ruleService.CreateAlertRule(context.Background(), u, dummyRule("test#1", orgID), models.ProvenanceNone)
require.ErrorIs(t, err, models.ErrQuotaReached)
})
@ -528,8 +533,8 @@ func TestAlertRuleService(t *testing.T) {
checker.EXPECT().LimitExceeded()
ruleService.quotas = checker
group := createDummyGroup("quota-reached", 1)
err := ruleService.ReplaceRuleGroup(context.Background(), 1, group, 0, models.ProvenanceAPI)
group := createDummyGroup("quota-reached", orgID)
err := ruleService.ReplaceRuleGroup(context.Background(), u, group, models.ProvenanceAPI)
require.ErrorIs(t, err, models.ErrQuotaReached)
})
@ -538,18 +543,19 @@ func TestAlertRuleService(t *testing.T) {
func TestCreateAlertRule(t *testing.T) {
ruleService := createAlertRuleService(t)
var orgID int64 = 1
u := &user.SignedInUser{OrgID: orgID}
t.Run("should return the created id", func(t *testing.T) {
rule, err := ruleService.CreateAlertRule(context.Background(), nil, dummyRule("test#1", orgID), models.ProvenanceNone)
rule, err := ruleService.CreateAlertRule(context.Background(), u, dummyRule("test#1", orgID), models.ProvenanceNone)
require.NoError(t, err)
require.NotEqual(t, 0, rule.ID, "expected to get the created id and not the zero value")
})
t.Run("should set the right provenance", func(t *testing.T) {
rule, err := ruleService.CreateAlertRule(context.Background(), nil, dummyRule("test#2", orgID), models.ProvenanceAPI)
rule, err := ruleService.CreateAlertRule(context.Background(), u, dummyRule("test#2", orgID), models.ProvenanceAPI)
require.NoError(t, err)
_, provenance, err := ruleService.GetAlertRule(context.Background(), orgID, rule.UID)
_, provenance, err := ruleService.GetAlertRule(context.Background(), u, rule.UID)
require.NoError(t, err)
require.Equal(t, models.ProvenanceAPI, provenance)
})
@ -558,17 +564,17 @@ func TestCreateAlertRule(t *testing.T) {
t.Run("return error if it is not valid UID", func(t *testing.T) {
rule := dummyRule("test#3", orgID)
rule.UID = strings.Repeat("1", util.MaxUIDLength+1)
rule, err := ruleService.CreateAlertRule(context.Background(), nil, rule, models.ProvenanceNone)
rule, err := ruleService.CreateAlertRule(context.Background(), u, rule, models.ProvenanceNone)
require.ErrorIs(t, err, models.ErrAlertRuleFailedValidation)
})
t.Run("should create a new rule with this UID", func(t *testing.T) {
rule := dummyRule("test#3", orgID)
uid := util.GenerateShortUID()
rule.UID = uid
created, err := ruleService.CreateAlertRule(context.Background(), nil, rule, models.ProvenanceNone)
created, err := ruleService.CreateAlertRule(context.Background(), u, rule, models.ProvenanceNone)
require.NoError(t, err)
require.Equal(t, uid, created.UID)
_, _, err = ruleService.GetAlertRule(context.Background(), orgID, uid)
_, _, err = ruleService.GetAlertRule(context.Background(), u, uid)
require.NoError(t, err)
})
})

View File

@ -7,10 +7,12 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
alert_models "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/provisioning"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
)
@ -42,6 +44,7 @@ func (prov *defaultAlertRuleProvisioner) Provision(ctx context.Context,
files []*AlertingFile) error {
for _, file := range files {
for _, group := range file.Groups {
u := provisionerUser(group.OrgID)
folderUID, err := prov.getOrCreateFolderUID(ctx, group.FolderTitle, group.OrgID)
if err != nil {
return err
@ -54,19 +57,18 @@ func (prov *defaultAlertRuleProvisioner) Provision(ctx context.Context,
for _, rule := range group.Rules {
rule.NamespaceUID = folderUID
rule.RuleGroup = group.Title
err = prov.provisionRule(ctx, group.OrgID, rule)
err = prov.provisionRule(ctx, u, rule)
if err != nil {
return err
}
}
err = prov.ruleService.UpdateRuleGroup(ctx, group.OrgID, folderUID, group.Title, group.Interval)
err = prov.ruleService.UpdateRuleGroup(ctx, u, folderUID, group.Title, group.Interval)
if err != nil {
return err
}
}
for _, deleteRule := range file.DeleteRules {
err := prov.ruleService.DeleteAlertRule(ctx, deleteRule.OrgID,
deleteRule.UID, alert_models.ProvenanceFile)
err := prov.ruleService.DeleteAlertRule(ctx, provisionerUser(deleteRule.OrgID), deleteRule.UID, alert_models.ProvenanceFile)
if err != nil {
return err
}
@ -77,20 +79,20 @@ func (prov *defaultAlertRuleProvisioner) Provision(ctx context.Context,
func (prov *defaultAlertRuleProvisioner) provisionRule(
ctx context.Context,
orgID int64,
user identity.Requester,
rule alert_models.AlertRule) error {
prov.logger.Debug("provisioning alert rule", "uid", rule.UID, "org", rule.OrgID)
_, _, err := prov.ruleService.GetAlertRule(ctx, orgID, rule.UID)
_, _, err := prov.ruleService.GetAlertRule(ctx, user, rule.UID)
if err != nil && !errors.Is(err, alert_models.ErrAlertRuleNotFound) {
return err
} else if err != nil {
prov.logger.Debug("creating rule", "uid", rule.UID, "org", rule.OrgID)
// a nil user is passed in as then the quota logic will only check for
// the organization quota since we don't have any user scope here.
_, err = prov.ruleService.CreateAlertRule(ctx, nil, rule, alert_models.ProvenanceFile)
_, err = prov.ruleService.CreateAlertRule(ctx, user, rule, alert_models.ProvenanceFile)
} else {
prov.logger.Debug("updating rule", "uid", rule.UID, "org", rule.OrgID)
_, err = prov.ruleService.UpdateAlertRule(ctx, rule, alert_models.ProvenanceFile)
_, err = prov.ruleService.UpdateAlertRule(ctx, user, rule, alert_models.ProvenanceFile)
}
return err
}
@ -129,3 +131,8 @@ func (prov *defaultAlertRuleProvisioner) getOrCreateFolderUID(
return cmdResult.UID, nil
}
// UserID is 0 to use org quota
var provisionerUser = func(orgID int64) identity.Requester {
return &user.SignedInUser{UserID: 0, Login: "alert_provisioner", OrgID: orgID}
}