Rules API: Allow filtering by rule name
Introduces support for a new query parameter in the `/rules` API endpoint that allows filtering by rule names. If all the rules of a group are filtered, we skip the group entirely. Signed-off-by: gotjosh <josue.abreu@gmail.com>
This commit is contained in:
parent
7309ac2721
commit
f3394bf7a1
|
@ -673,7 +673,9 @@ GET /api/v1/rules
|
|||
```
|
||||
|
||||
URL query parameters:
|
||||
|
||||
- `type=alert|record`: return only the alerting rules (e.g. `type=alert`) or the recording rules (e.g. `type=record`). When the parameter is absent or empty, no filtering is done.
|
||||
- `rules=alertName,RuleName`: return only the alerting and recording rules with the specified names. If we've filtered out all the rules of a group, the group is not returned. When the parameter is absent or empty, no filtering is done.
|
||||
|
||||
```json
|
||||
$ curl http://localhost:9090/api/v1/rules
|
||||
|
|
|
@ -1296,6 +1296,16 @@ func (api *API) rules(r *http.Request) apiFuncResult {
|
|||
res := &RuleDiscovery{RuleGroups: make([]*RuleGroup, len(ruleGroups))}
|
||||
typ := strings.ToLower(r.URL.Query().Get("type"))
|
||||
|
||||
// Parse the rule names into a comma separated list of rule names, then create a set.
|
||||
rulesQuery := r.URL.Query().Get("rules")
|
||||
ruleNamesSet := map[string]struct{}{}
|
||||
if rulesQuery != "" {
|
||||
names := strings.Split(rulesQuery, ",")
|
||||
for _, rn := range names {
|
||||
ruleNamesSet[strings.TrimSpace(rn)] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if typ != "" && typ != "alert" && typ != "record" {
|
||||
return invalidParamError(errors.Errorf("not supported value %q", typ), "type")
|
||||
}
|
||||
|
@ -1313,14 +1323,20 @@ func (api *API) rules(r *http.Request) apiFuncResult {
|
|||
EvaluationTime: grp.GetEvaluationTime().Seconds(),
|
||||
LastEvaluation: grp.GetLastEvaluation(),
|
||||
}
|
||||
for _, r := range grp.Rules() {
|
||||
for _, rr := range grp.Rules() {
|
||||
var enrichedRule Rule
|
||||
|
||||
lastError := ""
|
||||
if r.LastError() != nil {
|
||||
lastError = r.LastError().Error()
|
||||
if len(ruleNamesSet) > 0 {
|
||||
if _, ok := ruleNamesSet[rr.Name()]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
switch rule := r.(type) {
|
||||
|
||||
lastError := ""
|
||||
if rr.LastError() != nil {
|
||||
lastError = rr.LastError().Error()
|
||||
}
|
||||
switch rule := rr.(type) {
|
||||
case *rules.AlertingRule:
|
||||
if !returnAlerts {
|
||||
break
|
||||
|
@ -1358,11 +1374,16 @@ func (api *API) rules(r *http.Request) apiFuncResult {
|
|||
err := errors.Errorf("failed to assert type of rule '%v'", rule.Name())
|
||||
return apiFuncResult{nil, &apiError{errorInternal, err}, nil, nil}
|
||||
}
|
||||
|
||||
if enrichedRule != nil {
|
||||
apiRuleGroup.Rules = append(apiRuleGroup.Rules, enrichedRule)
|
||||
}
|
||||
}
|
||||
res.RuleGroups[i] = apiRuleGroup
|
||||
|
||||
// If the rule group response has no rules, skip it - this means we filtered all the rules of this group.
|
||||
if len(apiRuleGroup.Rules) > 0 {
|
||||
res.RuleGroups[i] = apiRuleGroup
|
||||
}
|
||||
}
|
||||
return apiFuncResult{res, nil, nil, nil}
|
||||
}
|
||||
|
|
|
@ -1973,6 +1973,33 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
endpoint: api.rules,
|
||||
query: url.Values{"rules": []string{"test_metric4"}},
|
||||
response: &RuleDiscovery{
|
||||
RuleGroups: []*RuleGroup{
|
||||
{
|
||||
Name: "grp",
|
||||
File: "/path/to/file",
|
||||
Interval: 1,
|
||||
Limit: 0,
|
||||
Rules: []Rule{
|
||||
AlertingRule{
|
||||
State: "inactive",
|
||||
Name: "test_metric4",
|
||||
Query: "up == 1",
|
||||
Duration: 1,
|
||||
Labels: labels.Labels{},
|
||||
Annotations: labels.Labels{},
|
||||
Alerts: []*Alert{},
|
||||
Health: "unknown",
|
||||
Type: "alerting",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
endpoint: api.queryExemplars,
|
||||
query: url.Values{
|
||||
|
|
Loading…
Reference in New Issue