Skip to content

Commit 3771a51

Browse files
fix for #5989
Signed-off-by: Anand Rajagopal <[email protected]>
1 parent ebaf4a4 commit 3771a51

File tree

8 files changed

+181
-68
lines changed

8 files changed

+181
-68
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* [CHANGE] Server: Instrument `cortex_request_duration_seconds` metric with native histogram. If `native-histograms` feature is enabled in monitoring Prometheus then the metric name needs to be updated in your dashboards. #6056
77
* [CHANGE] Distributor/Ingester: Change `cortex_distributor_ingester_appends_total`, `cortex_distributor_ingester_append_failures_total`, `cortex_distributor_ingester_queries_total`, and `cortex_distributor_ingester_query_failures_total` metrics to use the ingester ID instead of its IP as the label value. #6078
88
* [FEATURE] Ingester: Experimental: Enable native histogram ingestion via `-blocks-storage.tsdb.enable-native-histograms` flag. #5986
9+
* [FEATURE] Ruler: Add support for filtering out alerts in ListRules API. #6011
910
* [FEATURE] Query Frontend: Added a query rejection mechanism to block resource-intensive queries. #6005
1011
* [FEATURE] OTLP: Support ingesting OTLP exponential metrics as native histograms. #6071
1112
* [FEATURE] Ingester: Add `ingester.instance-limits.max-inflight-query-requests` to allow limiting ingester concurrent queries. #6081

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ VERSION=$(shell cat "./VERSION" 2> /dev/null)
1010
GOPROXY_VALUE=$(shell go env GOPROXY)
1111

1212
# ARCHS
13-
ARCHS = amd64 arm64
13+
ARCHS = amd64 #arm64
1414

1515
# Boiler plate for building Docker containers.
1616
# All this must go at top of file I'm afraid.
@@ -229,7 +229,7 @@ shell:
229229
bash
230230

231231
configs-integration-test:
232-
/bin/bash -c "go test -v -tags 'netgo integration' -timeout 30s ./pkg/configs/... ./pkg/ruler/..."
232+
/bin/bash -c "go test -v -tags 'netgo integration' -timeout 60s ./pkg/configs/... ./pkg/ruler/..."
233233

234234
mod-check:
235235
GO111MODULE=on go mod download

integration/e2ecortex/client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ type RuleFilter struct {
526526
RuleGroupNames []string
527527
RuleNames []string
528528
RuleType string
529+
ExcludeAlerts string
529530
}
530531

531532
func addQueryParams(urlValues url.Values, paramName string, params ...string) {
@@ -551,6 +552,7 @@ func (c *Client) GetPrometheusRules(filter RuleFilter) ([]*ruler.RuleGroup, erro
551552
addQueryParams(urlValues, "rule_name[]", filter.RuleNames...)
552553
addQueryParams(urlValues, "rule_group[]", filter.RuleGroupNames...)
553554
addQueryParams(urlValues, "type", filter.RuleType)
555+
addQueryParams(urlValues, "exclude_alerts", filter.ExcludeAlerts)
554556
req.URL.RawQuery = urlValues.Encode()
555557

556558
ctx, cancel := context.WithTimeout(context.Background(), c.timeout)

integration/ruler_test.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ func testRulerAPIWithSharding(t *testing.T, enableRulesBackup bool) {
414414
ruleGroups := make([]rulefmt.RuleGroup, numRulesGroups)
415415
expectedNames := make([]string, numRulesGroups)
416416
alertCount := 0
417+
evalInterval, _ := model.ParseDuration("1s")
417418
for i := 0; i < numRulesGroups; i++ {
418419
num := random.Intn(100)
419420
var ruleNode yaml.Node
@@ -428,7 +429,7 @@ func testRulerAPIWithSharding(t *testing.T, enableRulesBackup bool) {
428429
alertCount++
429430
ruleGroups[i] = rulefmt.RuleGroup{
430431
Name: ruleName,
431-
Interval: 60,
432+
Interval: evalInterval,
432433
Rules: []rulefmt.RuleNode{{
433434
Alert: ruleNode,
434435
Expr: exprNode,
@@ -437,7 +438,7 @@ func testRulerAPIWithSharding(t *testing.T, enableRulesBackup bool) {
437438
} else {
438439
ruleGroups[i] = rulefmt.RuleGroup{
439440
Name: ruleName,
440-
Interval: 60,
441+
Interval: evalInterval,
441442
Rules: []rulefmt.RuleNode{{
442443
Record: ruleNode,
443444
Expr: exprNode,
@@ -458,6 +459,7 @@ func testRulerAPIWithSharding(t *testing.T, enableRulesBackup bool) {
458459
"-querier.store-gateway-addresses": "localhost:12345",
459460
// Enable the bucket index so we can skip the initial bucket scan.
460461
"-blocks-storage.bucket-store.bucket-index.enabled": "true",
462+
"-ruler.poll-interval": "5s",
461463
}
462464
if enableRulesBackup {
463465
overrides["-ruler.ring.replication-factor"] = "3"
@@ -553,6 +555,42 @@ func testRulerAPIWithSharding(t *testing.T, enableRulesBackup bool) {
553555
assert.Len(t, ruleNames, 3, "Expected %d rules but got %d", 3, len(ruleNames))
554556
},
555557
},
558+
"Exclude Alerts": {
559+
filter: e2ecortex.RuleFilter{
560+
ExcludeAlerts: "true",
561+
},
562+
resultCheckFn: func(t assert.TestingT, ruleGroups []*ruler.RuleGroup) {
563+
alertsCount := 0
564+
for _, ruleGroup := range ruleGroups {
565+
for _, rule := range ruleGroup.Rules {
566+
r := rule.(map[string]interface{})
567+
if v, OK := r["alerts"]; OK {
568+
alerts := v.([]interface{})
569+
alertsCount = alertsCount + len(alerts)
570+
}
571+
}
572+
}
573+
assert.Equal(t, 0, alertsCount, "Expected 0 alerts but got %d", alertsCount)
574+
},
575+
},
576+
"Include Alerts": {
577+
filter: e2ecortex.RuleFilter{
578+
ExcludeAlerts: "false",
579+
},
580+
resultCheckFn: func(t assert.TestingT, ruleGroups []*ruler.RuleGroup) {
581+
alertsCount := 0
582+
for _, ruleGroup := range ruleGroups {
583+
for _, rule := range ruleGroup.Rules {
584+
r := rule.(map[string]interface{})
585+
if v, OK := r["alerts"]; OK {
586+
alerts := v.([]interface{})
587+
alertsCount = alertsCount + len(alerts)
588+
}
589+
}
590+
}
591+
assert.Greater(t, alertsCount, 0, "Expected greater than 0 alerts but got %d", alertsCount)
592+
},
593+
},
556594
}
557595
// For each test case, fetch the rules with configured filters, and ensure the results match.
558596
if enableRulesBackup {

pkg/ruler/api.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ func (a *API) PrometheusRules(w http.ResponseWriter, req *http.Request) {
154154
return
155155
}
156156

157+
excludeAlerts, err := parseExcludeAlerts(req)
158+
if err != nil {
159+
util_api.RespondError(logger, w, v1.ErrBadData, fmt.Sprintf("invalid parameter %q: %s", "exclude_alerts", err.Error()), http.StatusBadRequest)
160+
return
161+
}
162+
157163
rulesRequest := RulesRequest{
158164
RuleNames: req.Form["rule_name[]"],
159165
RuleGroupNames: req.Form["rule_group[]"],
@@ -162,6 +168,7 @@ func (a *API) PrometheusRules(w http.ResponseWriter, req *http.Request) {
162168
State: state,
163169
Health: health,
164170
Matchers: req.Form["match[]"],
171+
ExcludeAlerts: excludeAlerts,
165172
}
166173

167174
w.Header().Set("Content-Type", "application/json")
@@ -256,6 +263,20 @@ func (a *API) PrometheusRules(w http.ResponseWriter, req *http.Request) {
256263
}
257264
}
258265

266+
func parseExcludeAlerts(r *http.Request) (bool, error) {
267+
excludeAlertsParam := strings.ToLower(r.URL.Query().Get("exclude_alerts"))
268+
269+
if excludeAlertsParam == "" {
270+
return false, nil
271+
}
272+
273+
excludeAlerts, err := strconv.ParseBool(excludeAlertsParam)
274+
if err != nil {
275+
return false, fmt.Errorf("error converting exclude_alerts: %w", err)
276+
}
277+
return excludeAlerts, nil
278+
}
279+
259280
func (a *API) PrometheusAlerts(w http.ResponseWriter, req *http.Request) {
260281
logger := util_log.WithContext(req.Context(), a.logger)
261282
userID, err := tenant.TenantID(req.Context())

pkg/ruler/ruler.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -950,19 +950,21 @@ func (r *Ruler) getLocalRules(userID string, rulesRequest RulesRequest, includeB
950950
continue
951951
}
952952
alerts := []*AlertStateDesc{}
953-
for _, a := range rule.ActiveAlerts() {
954-
alerts = append(alerts, &AlertStateDesc{
955-
State: a.State.String(),
956-
Labels: cortexpb.FromLabelsToLabelAdapters(a.Labels),
957-
Annotations: cortexpb.FromLabelsToLabelAdapters(a.Annotations),
958-
Value: a.Value,
959-
ActiveAt: a.ActiveAt,
960-
FiredAt: a.FiredAt,
961-
ResolvedAt: a.ResolvedAt,
962-
LastSentAt: a.LastSentAt,
963-
ValidUntil: a.ValidUntil,
964-
KeepFiringSince: a.KeepFiringSince,
965-
})
953+
if !rulesRequest.ExcludeAlerts {
954+
for _, a := range rule.ActiveAlerts() {
955+
alerts = append(alerts, &AlertStateDesc{
956+
State: a.State.String(),
957+
Labels: cortexpb.FromLabelsToLabelAdapters(a.Labels),
958+
Annotations: cortexpb.FromLabelsToLabelAdapters(a.Annotations),
959+
Value: a.Value,
960+
ActiveAt: a.ActiveAt,
961+
FiredAt: a.FiredAt,
962+
ResolvedAt: a.ResolvedAt,
963+
LastSentAt: a.LastSentAt,
964+
ValidUntil: a.ValidUntil,
965+
KeepFiringSince: a.KeepFiringSince,
966+
})
967+
}
966968
}
967969
ruleDesc = &RuleStateDesc{
968970
Rule: &rulespb.RuleDesc{
@@ -1174,6 +1176,7 @@ func (r *Ruler) getShardedRules(ctx context.Context, userID string, rulesRequest
11741176
RuleGroupNames: rulesRequest.GetRuleGroupNames(),
11751177
Files: rulesRequest.GetFiles(),
11761178
Type: rulesRequest.GetType(),
1179+
ExcludeAlerts: rulesRequest.GetExcludeAlerts(),
11771180
Matchers: rulesRequest.GetMatchers(),
11781181
})
11791182

0 commit comments

Comments
 (0)