Skip to content

Commit f2f00f0

Browse files
Adding support to filter rules
Signed-off-by: Anand Rajagopal <[email protected]>
1 parent 6f570e0 commit f2f00f0

File tree

4 files changed

+47
-27
lines changed

4 files changed

+47
-27
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* [ENHANCEMENT] Store Gateway: Add new metrics `cortex_bucket_store_sent_chunk_size_bytes`, `cortex_bucket_store_postings_size_bytes` and `cortex_bucket_store_empty_postings_total`. #5397
3131
* [ENHANCEMENT] Add jitter to lifecycler heartbeat. #5404
3232
* [ENHANCEMENT] Store Gateway: Add config `estimated_max_series_size_bytes` and `estimated_max_chunk_size_bytes` to address data overfetch. #5401
33-
* [ENHANCEMENT] Ruler: Support for filtering rules. #5417
33+
* [ENHANCEMENT] Ruler: Support for filtering rules in the API. #5417
3434
* [BUGFIX] Ruler: Validate if rule group can be safely converted back to rule group yaml from protobuf message #5265
3535
* [BUGFIX] Querier: Convert gRPC `ResourceExhausted` status code from store gateway to 422 limit error. #5286
3636
* [BUGFIX] Alertmanager: Route web-ui requests to the alertmanager distributor when sharding is enabled. #5293

pkg/ruler/api.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,6 @@ type recordingRule struct {
100100
EvaluationTime float64 `json:"evaluationTime"`
101101
}
102102

103-
const (
104-
AlertingRuleFilter string = "alert"
105-
RecordingRuleFilter string = "record"
106-
)
107-
108103
func respondError(logger log.Logger, w http.ResponseWriter, msg string) {
109104
b, err := json.Marshal(&response{
110105
Status: "error",
@@ -125,10 +120,10 @@ func respondError(logger log.Logger, w http.ResponseWriter, msg string) {
125120
}
126121
}
127122

128-
func respondClientError(logger log.Logger, w http.ResponseWriter, msg string) {
123+
func respondBadRequest(logger log.Logger, w http.ResponseWriter, msg string) {
129124
b, err := json.Marshal(&response{
130125
Status: "error",
131-
ErrorType: v1.ErrServer,
126+
ErrorType: v1.ErrBadData,
132127
Error: msg,
133128
Data: nil,
134129
})
@@ -173,13 +168,13 @@ func (a *API) PrometheusRules(w http.ResponseWriter, req *http.Request) {
173168

174169
if err := req.ParseForm(); err != nil {
175170
level.Error(logger).Log("msg", "error parsing form/query params", "err", err)
176-
respondClientError(logger, w, err.Error())
171+
respondBadRequest(logger, w, "error parsing form/query params")
177172
return
178173
}
179174

180175
typ := strings.ToLower(req.URL.Query().Get("type"))
181176
if typ != "" && typ != AlertingRuleFilter && typ != RecordingRuleFilter {
182-
respondClientError(logger, w, fmt.Sprintf("not supported value %q", typ))
177+
respondBadRequest(logger, w, fmt.Sprintf("unsupported rule type %q", typ))
183178
return
184179
}
185180

pkg/ruler/ruler.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ const (
6666

6767
// errors
6868
errListAllUser = "unable to list the ruler users"
69+
70+
AlertingRuleFilter string = "alert"
71+
RecordingRuleFilter string = "record"
6972
)
7073

7174
// Config is the configuration for the recording rules server.
@@ -677,12 +680,17 @@ func (r *Ruler) getLocalRules(userID string, rulesRequest RulesRequest) ([]*Grou
677680
fileSet := sliceToSet(rulesRequest.Files)
678681
ruleType := rulesRequest.Type
679682

680-
returnAlerts := ruleType == "" || ruleType == "alert"
681-
returnRecording := ruleType == "" || ruleType == "record"
683+
returnAlerts := ruleType == "" || ruleType == AlertingRuleFilter
684+
returnRecording := ruleType == "" || ruleType == RecordingRuleFilter
682685

683686
for _, group := range groups {
687+
// The mapped filename is url path escaped encoded to make handling `/` characters easier
688+
decodedNamespace, err := url.PathUnescape(strings.TrimPrefix(group.File(), prefix))
689+
if err != nil {
690+
return nil, errors.Wrap(err, "unable to decode rule filename")
691+
}
684692
if len(fileSet) > 0 {
685-
if _, OK := fileSet[group.File()]; !OK {
693+
if _, OK := fileSet[decodedNamespace]; !OK {
686694
continue
687695
}
688696
}
@@ -694,12 +702,6 @@ func (r *Ruler) getLocalRules(userID string, rulesRequest RulesRequest) ([]*Grou
694702
}
695703
interval := group.Interval()
696704

697-
// The mapped filename is url path escaped encoded to make handling `/` characters easier
698-
decodedNamespace, err := url.PathUnescape(strings.TrimPrefix(group.File(), prefix))
699-
if err != nil {
700-
return nil, errors.Wrap(err, "unable to decode rule filename")
701-
}
702-
703705
groupDesc := &GroupStateDesc{
704706
Group: &rulespb.RuleGroupDesc{
705707
Name: group.Name(),

pkg/ruler/ruler_test.go

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,17 @@ func TestGetRules(t *testing.T) {
380380
},
381381
"ruler2-user2-rule-group2": []*rulespb.RuleDesc{
382382
{
383-
Record: "rtest_user1_1",
383+
Record: "rtest_user2_1",
384384
Expr: "sum(rate(node_cpu_seconds_total[3h:10m]))",
385385
},
386386
{
387-
Alert: "atest_user1_1",
387+
Alert: "atest_user2_1",
388+
Expr: "sum(rate(node_cpu_seconds_total[3h:10m]))",
389+
},
390+
},
391+
"ruler2-user3-rule-group1": []*rulespb.RuleDesc{
392+
{
393+
Alert: "atest_user3_1",
388394
Expr: "sum(rate(node_cpu_seconds_total[3h:10m]))",
389395
},
390396
},
@@ -438,6 +444,9 @@ func TestGetRules(t *testing.T) {
438444
&rulespb.RuleGroupDesc{User: "user2", Namespace: "namespace", Name: "first", Interval: 10 * time.Second, Rules: ruleMap["ruler2-user2-rule-group1"]},
439445
&rulespb.RuleGroupDesc{User: "user2", Namespace: "namespace", Name: "second", Interval: 10 * time.Second, Rules: ruleMap["ruler2-user2-rule-group2"]},
440446
},
447+
"user3": {
448+
&rulespb.RuleGroupDesc{User: "user3", Namespace: "latency-test", Name: "first", Interval: 10 * time.Second, Rules: ruleMap["ruler2-user3-rule-group1"]},
449+
},
441450
},
442451
"ruler3": map[string]rulespb.RuleGroupList{
443452
"user3": {
@@ -451,28 +460,28 @@ func TestGetRules(t *testing.T) {
451460
}
452461

453462
testCases := map[string]testCase{
454-
"No Sharding": {
463+
"No Sharding with Rule Type Filter": {
455464
sharding: false,
456465
rulesRequest: RulesRequest{
457466
Type: AlertingRuleFilter,
458467
},
459468
expectedCount: map[string]int{
460469
"user1": 2,
461470
"user2": 4,
462-
"user3": 1,
471+
"user3": 2,
463472
},
464473
},
465-
"Default Sharding": {
474+
"Default Sharding with No Filter": {
466475
sharding: true,
467476
shardingStrategy: util.ShardingStrategyDefault,
468-
rulesRequest: RulesRequest{},
477+
//rulesRequest: RulesRequest{},
469478
expectedCount: map[string]int{
470479
"user1": 5,
471480
"user2": 9,
472-
"user3": 2,
481+
"user3": 3,
473482
},
474483
},
475-
"Shuffle Sharding and ShardSize = 2": {
484+
"Shuffle Sharding and ShardSize = 2 with Rule Type Filter": {
476485
sharding: true,
477486
shuffleShardSize: 2,
478487
shardingStrategy: util.ShardingStrategyShuffle,
@@ -512,6 +521,20 @@ func TestGetRules(t *testing.T) {
512521
"user3": 1,
513522
},
514523
},
524+
"Shuffle Sharding and ShardSize = 2 with Rule Type and Namespace Filters": {
525+
sharding: true,
526+
shuffleShardSize: 2,
527+
shardingStrategy: util.ShardingStrategyShuffle,
528+
rulesRequest: RulesRequest{
529+
Type: AlertingRuleFilter,
530+
Files: []string{"latency-test"},
531+
},
532+
expectedCount: map[string]int{
533+
"user1": 0,
534+
"user2": 0,
535+
"user3": 1,
536+
},
537+
},
515538
}
516539

517540
for name, tc := range testCases {

0 commit comments

Comments
 (0)