Alerting: Add search.rule_group to search rules by rule group name (#113680)
Co-authored-by: Konrad Lalik <konradlalik@gmail.com>
This commit is contained in:
co-authored by
Konrad Lalik
parent
9d928a3ac6
commit
da5af29218
@@ -480,6 +480,7 @@ func PrepareRuleGroupStatusesV2(log log.Logger, store ListAlertRulesStoreV2, opt
|
||||
|
||||
receiverName := opts.Query.Get("receiver_name")
|
||||
title := opts.Query.Get("search.rule_name")
|
||||
searchRuleGroup := opts.Query.Get("search.rule_group")
|
||||
|
||||
var ruleType ngmodels.RuleTypeFilter
|
||||
switch ngmodels.RuleType(opts.Query.Get("rule_type")) {
|
||||
@@ -500,13 +501,14 @@ func PrepareRuleGroupStatusesV2(log log.Logger, store ListAlertRulesStoreV2, opt
|
||||
|
||||
byGroupQuery := ngmodels.ListAlertRulesExtendedQuery{
|
||||
ListAlertRulesQuery: ngmodels.ListAlertRulesQuery{
|
||||
OrgID: opts.OrgID,
|
||||
NamespaceUIDs: namespaceUIDs,
|
||||
DashboardUID: dashboardUID,
|
||||
PanelID: panelID,
|
||||
RuleGroups: ruleGroups,
|
||||
ReceiverName: receiverName,
|
||||
SearchTitle: title,
|
||||
OrgID: opts.OrgID,
|
||||
NamespaceUIDs: namespaceUIDs,
|
||||
DashboardUID: dashboardUID,
|
||||
PanelID: panelID,
|
||||
RuleGroups: ruleGroups,
|
||||
ReceiverName: receiverName,
|
||||
SearchTitle: title,
|
||||
SearchRuleGroup: searchRuleGroup,
|
||||
},
|
||||
RuleType: ruleType,
|
||||
Limit: maxGroups,
|
||||
@@ -638,15 +640,17 @@ func PrepareRuleGroupStatuses(log log.Logger, store ListAlertRulesStore, opts Ru
|
||||
|
||||
receiverName := opts.Query.Get("receiver_name")
|
||||
title := opts.Query.Get("search.rule_name")
|
||||
searchRuleGroup := opts.Query.Get("search.rule_group")
|
||||
|
||||
alertRuleQuery := ngmodels.ListAlertRulesQuery{
|
||||
OrgID: opts.OrgID,
|
||||
NamespaceUIDs: namespaceUIDs,
|
||||
DashboardUID: dashboardUID,
|
||||
PanelID: panelID,
|
||||
RuleGroups: ruleGroups,
|
||||
ReceiverName: receiverName,
|
||||
SearchTitle: title,
|
||||
OrgID: opts.OrgID,
|
||||
NamespaceUIDs: namespaceUIDs,
|
||||
DashboardUID: dashboardUID,
|
||||
PanelID: panelID,
|
||||
RuleGroups: ruleGroups,
|
||||
ReceiverName: receiverName,
|
||||
SearchTitle: title,
|
||||
SearchRuleGroup: searchRuleGroup,
|
||||
}
|
||||
ruleList, err := store.ListAlertRules(opts.Ctx, &alertRuleQuery)
|
||||
if err != nil {
|
||||
|
||||
@@ -981,6 +981,9 @@ type ListAlertRulesQuery struct {
|
||||
// SearchTitle allows searching for alert rules that contain
|
||||
// the given string in their title (case insensitive)
|
||||
SearchTitle string
|
||||
// SearchRuleGroup allows searching for alert rules in groups that contain
|
||||
// the given string in their name (case insensitive)
|
||||
SearchRuleGroup string
|
||||
|
||||
HasPrometheusRuleDefinition *bool
|
||||
}
|
||||
|
||||
@@ -865,6 +865,18 @@ func (st DBstore) buildListAlertRulesQuery(sess *db.Session, query *ngmodels.Lis
|
||||
}
|
||||
}
|
||||
|
||||
if query.SearchRuleGroup != "" {
|
||||
normalizedInput := strings.ToLower(query.SearchRuleGroup)
|
||||
words := strings.Fields(normalizedInput)
|
||||
|
||||
if len(words) > 0 {
|
||||
pattern := "%" + strings.Join(words, "%") + "%"
|
||||
// In MySQL rule_group field has case-sensitive collation by default,
|
||||
// so we need to use LOWER to perform case-insensitive search.
|
||||
q = q.And("LOWER(rule_group) LIKE ?", pattern)
|
||||
}
|
||||
}
|
||||
|
||||
if query.HasPrometheusRuleDefinition != nil {
|
||||
q, err = st.filterWithPrometheusRuleDefinition(*query.HasPrometheusRuleDefinition, q)
|
||||
if err != nil {
|
||||
|
||||
@@ -2141,6 +2141,75 @@ func TestIntegration_ListAlertRules(t *testing.T) {
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("filter by SearchRuleGroup", func(t *testing.T) {
|
||||
sqlStore := db.InitTestDB(t)
|
||||
folderService := setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
store := createTestStore(sqlStore, folderService, &logtest.Fake{}, cfg.UnifiedAlerting, b)
|
||||
rule1 := createRule(t, store, ruleGen.With(models.RuleMuts.WithGroupName("database-alerts")))
|
||||
rule2 := createRule(t, store, ruleGen.With(models.RuleMuts.WithGroupName("application-alerts")))
|
||||
rule3 := createRule(t, store, ruleGen.With(models.RuleMuts.WithGroupName("network-alerts")))
|
||||
rule4 := createRule(t, store, ruleGen.With(models.RuleMuts.WithGroupName("critical-monitoring")))
|
||||
|
||||
tc := []struct {
|
||||
name string
|
||||
groupSearch string
|
||||
expectedRules []*models.AlertRule
|
||||
}{
|
||||
{
|
||||
name: "should find rules",
|
||||
groupSearch: "alerts",
|
||||
expectedRules: []*models.AlertRule{rule1, rule2, rule3},
|
||||
},
|
||||
{
|
||||
name: "should find rule with partial match",
|
||||
groupSearch: "mOnItOrInG",
|
||||
expectedRules: []*models.AlertRule{rule4},
|
||||
},
|
||||
{
|
||||
name: "should return no rules when no match",
|
||||
groupSearch: "nonexistent",
|
||||
expectedRules: []*models.AlertRule{},
|
||||
},
|
||||
{
|
||||
name: "should return all rules when empty",
|
||||
groupSearch: "",
|
||||
expectedRules: []*models.AlertRule{rule1, rule2, rule3, rule4},
|
||||
},
|
||||
{
|
||||
name: "should not find rules when word order is reversed",
|
||||
groupSearch: "alerts database",
|
||||
expectedRules: []*models.AlertRule{},
|
||||
},
|
||||
{
|
||||
name: "should find multiple rules matching sequential words",
|
||||
groupSearch: "database alert",
|
||||
expectedRules: []*models.AlertRule{rule1},
|
||||
},
|
||||
{
|
||||
name: "should handle extra whitespace between words",
|
||||
groupSearch: " network alerts ",
|
||||
expectedRules: []*models.AlertRule{rule3},
|
||||
},
|
||||
{
|
||||
name: "should handle multiple words with partial matches",
|
||||
groupSearch: "crit mon",
|
||||
expectedRules: []*models.AlertRule{rule4},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tc {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
query := &models.ListAlertRulesQuery{
|
||||
OrgID: orgID,
|
||||
SearchRuleGroup: tt.groupSearch,
|
||||
}
|
||||
result, err := store.ListAlertRules(context.Background(), query)
|
||||
require.NoError(t, err)
|
||||
require.ElementsMatch(t, tt.expectedRules, result)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntegration_ListAlertRulesPaginated(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user