Alerting: Allow administrators delete rules permanently via UI (#101974)
* add query parameter to existing APIs to control the permanent deletion of rules
* add GUID to gettable rule
* add new endpoint /ruler/grafana/api/v1/trash/rule/guid/{RuleGUID} to delete rules from trash permanently
---------
Signed-off-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
This commit is contained in:
@@ -78,6 +78,14 @@ var ignoreFieldsForValidate = [...]string{"RuleGroupIndex"}
|
||||
// Returns http.StatusForbidden if user does not have access to any of the rules that match the filter.
|
||||
// Returns http.StatusBadRequest if all rules that match the filter and the user is authorized to delete are provisioned.
|
||||
func (srv RulerSrv) RouteDeleteAlertRules(c *contextmodel.ReqContext, namespaceUID string, group string) response.Response {
|
||||
var permanently bool
|
||||
if c.QueryBool("deletePermanently") {
|
||||
if !c.SignedInUser.HasRole(identity.RoleAdmin) {
|
||||
return ErrResp(http.StatusForbidden, errors.New("only administrators can delete rules permanently"), "")
|
||||
}
|
||||
permanently = true
|
||||
}
|
||||
|
||||
namespace, err := srv.store.GetNamespaceByUID(c.Req.Context(), namespaceUID, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return toNamespaceErrorResponse(err)
|
||||
@@ -161,7 +169,7 @@ func (srv RulerSrv) RouteDeleteAlertRules(c *contextmodel.ReqContext, namespaceU
|
||||
rulesToDelete = append(rulesToDelete, uid...)
|
||||
}
|
||||
if len(rulesToDelete) > 0 {
|
||||
err := srv.store.DeleteAlertRulesByUID(ctx, c.SignedInUser.GetOrgID(), ngmodels.NewUserUID(c.SignedInUser), rulesToDelete...)
|
||||
err := srv.store.DeleteAlertRulesByUID(ctx, c.SignedInUser.GetOrgID(), ngmodels.NewUserUID(c.SignedInUser), permanently, rulesToDelete...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -385,6 +393,14 @@ func (srv RulerSrv) RouteGetRuleVersionsByUID(c *contextmodel.ReqContext, ruleUI
|
||||
}
|
||||
|
||||
func (srv RulerSrv) RoutePostNameRulesConfig(c *contextmodel.ReqContext, ruleGroupConfig apimodels.PostableRuleGroupConfig, namespaceUID string) response.Response {
|
||||
var deletePermanently bool
|
||||
if c.QueryBool("deletePermanently") {
|
||||
if !c.SignedInUser.HasRole(identity.RoleAdmin) {
|
||||
return ErrResp(http.StatusForbidden, errors.New("only administrators can delete rules permanently"), "")
|
||||
}
|
||||
deletePermanently = true
|
||||
}
|
||||
|
||||
namespace, err := srv.store.GetNamespaceByUID(c.Req.Context(), namespaceUID, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return toNamespaceErrorResponse(err)
|
||||
@@ -405,7 +421,18 @@ func (srv RulerSrv) RoutePostNameRulesConfig(c *contextmodel.ReqContext, ruleGro
|
||||
RuleGroup: ruleGroupConfig.Name,
|
||||
}
|
||||
|
||||
return srv.updateAlertRulesInGroup(c, groupKey, rules)
|
||||
return srv.updateAlertRulesInGroup(c, groupKey, rules, deletePermanently)
|
||||
}
|
||||
|
||||
func (srv RulerSrv) RouteDeleteAlertRuleFromTrashByGUID(ctx *contextmodel.ReqContext, guid string) response.Response {
|
||||
deleted, err := srv.store.DeleteRuleFromTrashByGUID(ctx.Req.Context(), ctx.SignedInUser.GetOrgID(), guid)
|
||||
if err != nil {
|
||||
return ErrResp(http.StatusInternalServerError, err, "failed to delete rule from trash")
|
||||
}
|
||||
if deleted == 0 {
|
||||
return response.Empty(http.StatusNotFound)
|
||||
}
|
||||
return response.Empty(http.StatusOK)
|
||||
}
|
||||
|
||||
func (srv RulerSrv) checkGroupLimits(group apimodels.PostableRuleGroupConfig) error {
|
||||
@@ -424,7 +451,7 @@ func (srv RulerSrv) checkGroupLimits(group apimodels.PostableRuleGroupConfig) er
|
||||
// All operations are performed in a single transaction
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (srv RulerSrv) updateAlertRulesInGroup(c *contextmodel.ReqContext, groupKey ngmodels.AlertRuleGroupKey, rules []*ngmodels.AlertRuleWithOptionals) response.Response {
|
||||
func (srv RulerSrv) updateAlertRulesInGroup(c *contextmodel.ReqContext, groupKey ngmodels.AlertRuleGroupKey, rules []*ngmodels.AlertRuleWithOptionals, deletePermanently bool) response.Response {
|
||||
var finalChanges *store.GroupDelta
|
||||
var dbConfig *ngmodels.AlertConfiguration
|
||||
err := srv.xactManager.InTransaction(c.Req.Context(), func(tranCtx context.Context) error {
|
||||
@@ -485,7 +512,7 @@ func (srv RulerSrv) updateAlertRulesInGroup(c *contextmodel.ReqContext, groupKey
|
||||
UIDs = append(UIDs, rule.UID)
|
||||
}
|
||||
|
||||
if err = srv.store.DeleteAlertRulesByUID(tranCtx, c.SignedInUser.GetOrgID(), ngmodels.NewUserUID(c.SignedInUser), UIDs...); err != nil {
|
||||
if err = srv.store.DeleteAlertRulesByUID(tranCtx, c.SignedInUser.GetOrgID(), ngmodels.NewUserUID(c.SignedInUser), deletePermanently, UIDs...); err != nil {
|
||||
return fmt.Errorf("failed to delete rules: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -631,6 +658,7 @@ func toGettableExtendedRuleNode(r ngmodels.AlertRule, provenanceRecords map[stri
|
||||
NotificationSettings: AlertRuleNotificationSettingsFromNotificationSettings(r.NotificationSettings),
|
||||
Record: ApiRecordFromModelRecord(r.Record),
|
||||
Metadata: AlertRuleMetadataFromModelMetadata(r.Metadata),
|
||||
GUID: r.GUID,
|
||||
},
|
||||
}
|
||||
forDuration := model.Duration(r.For)
|
||||
|
||||
Reference in New Issue
Block a user