Skip to content

Commit 7352367

Browse files
filter rules
Signed-off-by: Anand Rajagopal <[email protected]>
1 parent a307fc0 commit 7352367

File tree

5 files changed

+472
-68
lines changed

5 files changed

+472
-68
lines changed

pkg/ruler/api.go

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ruler
22

33
import (
44
"encoding/json"
5+
"fmt"
56
io "io"
67
"net/http"
78
"net/url"
@@ -99,6 +100,11 @@ type recordingRule struct {
99100
EvaluationTime float64 `json:"evaluationTime"`
100101
}
101102

103+
const (
104+
AlertingRuleFilter string = "alert"
105+
RecordingRuleFilter string = "record"
106+
)
107+
102108
func respondError(logger log.Logger, w http.ResponseWriter, msg string) {
103109
b, err := json.Marshal(&response{
104110
Status: "error",
@@ -119,6 +125,26 @@ func respondError(logger log.Logger, w http.ResponseWriter, msg string) {
119125
}
120126
}
121127

128+
func respondClientError(logger log.Logger, w http.ResponseWriter, msg string) {
129+
b, err := json.Marshal(&response{
130+
Status: "error",
131+
ErrorType: v1.ErrServer,
132+
Error: msg,
133+
Data: nil,
134+
})
135+
136+
if err != nil {
137+
level.Error(logger).Log("msg", "error marshaling json response", "err", err)
138+
http.Error(w, err.Error(), http.StatusInternalServerError)
139+
return
140+
}
141+
142+
w.WriteHeader(http.StatusBadRequest)
143+
if n, err := w.Write(b); err != nil {
144+
level.Error(logger).Log("msg", "error writing response", "bytesWritten", n, "err", err)
145+
}
146+
}
147+
122148
// API is used to handle HTTP requests for the ruler service
123149
type API struct {
124150
ruler *Ruler
@@ -145,8 +171,27 @@ func (a *API) PrometheusRules(w http.ResponseWriter, req *http.Request) {
145171
return
146172
}
147173

174+
if err := req.ParseForm(); err != nil {
175+
level.Error(logger).Log("msg", "error parsing form/query params", "err", err)
176+
respondClientError(logger, w, err.Error())
177+
return
178+
}
179+
180+
typ := strings.ToLower(req.URL.Query().Get("type"))
181+
if typ != "" && typ != AlertingRuleFilter && typ != RecordingRuleFilter {
182+
respondClientError(logger, w, fmt.Sprintf("not supported value %q", typ))
183+
return
184+
}
185+
186+
rulesRequest := RulesRequest{
187+
RuleNames: req.Form["rule_name[]"],
188+
RuleGroupNames: req.Form["rule_group[]"],
189+
Files: req.Form["files[]"],
190+
Type: typ,
191+
}
192+
148193
w.Header().Set("Content-Type", "application/json")
149-
rgs, err := a.ruler.GetRules(req.Context())
194+
rgs, err := a.ruler.GetRules(req.Context(), rulesRequest)
150195

151196
if err != nil {
152197
respondError(logger, w, err.Error())
@@ -238,7 +283,10 @@ func (a *API) PrometheusAlerts(w http.ResponseWriter, req *http.Request) {
238283
}
239284

240285
w.Header().Set("Content-Type", "application/json")
241-
rgs, err := a.ruler.GetRules(req.Context())
286+
rulesRequest := RulesRequest{
287+
//Type: AlertingRuleFilter,
288+
}
289+
rgs, err := a.ruler.GetRules(req.Context(), rulesRequest)
242290

243291
if err != nil {
244292
respondError(logger, w, err.Error())

pkg/ruler/ruler.go

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -645,26 +645,53 @@ func filterRuleGroups(userID string, ruleGroups []*rulespb.RuleGroupDesc, ring r
645645

646646
// GetRules retrieves the running rules from this ruler and all running rulers in the ring if
647647
// sharding is enabled
648-
func (r *Ruler) GetRules(ctx context.Context) ([]*GroupStateDesc, error) {
648+
func (r *Ruler) GetRules(ctx context.Context, rulesRequest RulesRequest) ([]*GroupStateDesc, error) {
649649
userID, err := tenant.TenantID(ctx)
650650
if err != nil {
651651
return nil, fmt.Errorf("no user id found in context")
652652
}
653653

654654
if r.cfg.EnableSharding {
655-
return r.getShardedRules(ctx, userID)
655+
return r.getShardedRules(ctx, userID, rulesRequest)
656656
}
657657

658-
return r.getLocalRules(userID)
658+
return r.getLocalRules(userID, rulesRequest)
659659
}
660660

661-
func (r *Ruler) getLocalRules(userID string) ([]*GroupStateDesc, error) {
661+
func (r *Ruler) getLocalRules(userID string, rulesRequest RulesRequest) ([]*GroupStateDesc, error) {
662662
groups := r.manager.GetRules(userID)
663663

664664
groupDescs := make([]*GroupStateDesc, 0, len(groups))
665665
prefix := filepath.Join(r.cfg.RulePath, userID) + "/"
666666

667+
sliceToSet := func(values []string) map[string]struct{} {
668+
set := make(map[string]struct{}, len(values))
669+
for _, v := range values {
670+
set[v] = struct{}{}
671+
}
672+
return set
673+
}
674+
675+
ruleNameSet := sliceToSet(rulesRequest.RuleNames)
676+
ruleGroupNameSet := sliceToSet(rulesRequest.RuleGroupNames)
677+
fileSet := sliceToSet(rulesRequest.Files)
678+
ruleType := rulesRequest.Type
679+
680+
returnAlerts := ruleType == "" || ruleType == "alert"
681+
returnRecording := ruleType == "" || ruleType == "record"
682+
667683
for _, group := range groups {
684+
if len(fileSet) > 0 {
685+
if _, OK := fileSet[group.File()]; !OK {
686+
continue
687+
}
688+
}
689+
690+
if len(ruleGroupNameSet) > 0 {
691+
if _, OK := ruleGroupNameSet[group.Name()]; !OK {
692+
continue
693+
}
694+
}
668695
interval := group.Interval()
669696

670697
// The mapped filename is url path escaped encoded to make handling `/` characters easier
@@ -685,6 +712,11 @@ func (r *Ruler) getLocalRules(userID string) ([]*GroupStateDesc, error) {
685712
EvaluationDuration: group.GetEvaluationTime(),
686713
}
687714
for _, r := range group.Rules() {
715+
if len(ruleNameSet) > 0 {
716+
if _, OK := ruleNameSet[r.Name()]; !OK {
717+
continue
718+
}
719+
}
688720
lastError := ""
689721
if r.LastError() != nil {
690722
lastError = r.LastError().Error()
@@ -693,7 +725,9 @@ func (r *Ruler) getLocalRules(userID string) ([]*GroupStateDesc, error) {
693725
var ruleDesc *RuleStateDesc
694726
switch rule := r.(type) {
695727
case *promRules.AlertingRule:
696-
rule.ActiveAlerts()
728+
if !returnAlerts {
729+
break
730+
}
697731
alerts := []*AlertStateDesc{}
698732
for _, a := range rule.ActiveAlerts() {
699733
alerts = append(alerts, &AlertStateDesc{
@@ -725,6 +759,9 @@ func (r *Ruler) getLocalRules(userID string) ([]*GroupStateDesc, error) {
725759
EvaluationDuration: rule.GetEvaluationDuration(),
726760
}
727761
case *promRules.RecordingRule:
762+
if !returnRecording {
763+
break
764+
}
728765
ruleDesc = &RuleStateDesc{
729766
Rule: &rulespb.RuleDesc{
730767
Record: rule.Name(),
@@ -741,12 +778,14 @@ func (r *Ruler) getLocalRules(userID string) ([]*GroupStateDesc, error) {
741778
}
742779
groupDesc.ActiveRules = append(groupDesc.ActiveRules, ruleDesc)
743780
}
744-
groupDescs = append(groupDescs, groupDesc)
781+
if len(groupDesc.ActiveRules) > 0 {
782+
groupDescs = append(groupDescs, groupDesc)
783+
}
745784
}
746785
return groupDescs, nil
747786
}
748787

749-
func (r *Ruler) getShardedRules(ctx context.Context, userID string) ([]*GroupStateDesc, error) {
788+
func (r *Ruler) getShardedRules(ctx context.Context, userID string, rulesRequest RulesRequest) ([]*GroupStateDesc, error) {
750789
ring := ring.ReadRing(r.ring)
751790

752791
if shardSize := r.limits.RulerTenantShardSize(userID); shardSize > 0 && r.cfg.ShardingStrategy == util.ShardingStrategyShuffle {
@@ -779,7 +818,7 @@ func (r *Ruler) getShardedRules(ctx context.Context, userID string) ([]*GroupSta
779818
return errors.Wrapf(err, "unable to get client for ruler %s", addr)
780819
}
781820

782-
newGrps, err := rulerClient.Rules(ctx, &RulesRequest{})
821+
newGrps, err := rulerClient.Rules(ctx, &rulesRequest)
783822
if err != nil {
784823
return errors.Wrapf(err, "unable to retrieve rules from ruler %s", addr)
785824
}
@@ -801,7 +840,7 @@ func (r *Ruler) Rules(ctx context.Context, in *RulesRequest) (*RulesResponse, er
801840
return nil, fmt.Errorf("no user id found in context")
802841
}
803842

804-
groupDescs, err := r.getLocalRules(userID)
843+
groupDescs, err := r.getLocalRules(userID, *in)
805844
if err != nil {
806845
return nil, err
807846
}

0 commit comments

Comments
 (0)