mirror of
https://github.com/grafana/grafana.git
synced 2025-07-31 16:13:02 +08:00
Alerting: Update rule provisioning service to accept user (#84480)
This commit is contained in:
@ -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)
|
||||
}
|
||||
|
@ -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, "a.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 {
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
@ -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}
|
||||
}
|
||||
|
Reference in New Issue
Block a user