From 4fa03efa2cf26434503643f3fb9330928443c7f3 Mon Sep 17 00:00:00 2001 From: Joel Takvorian Date: Mon, 28 Jul 2025 16:00:07 +0200 Subject: [PATCH] Support matchers in rules API Similar to the older change on Labels API (https://github.com/prometheus/client_golang/pull/828), this adds `matches` to the `Rules` API. This is a breaking change Signed-off-by: Joel Takvorian --- api/prometheus/v1/api.go | 11 ++++-- api/prometheus/v1/api_test.go | 66 ++++++++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/api/prometheus/v1/api.go b/api/prometheus/v1/api.go index 8a72f9bfc..ef3fb48ba 100644 --- a/api/prometheus/v1/api.go +++ b/api/prometheus/v1/api.go @@ -494,7 +494,7 @@ type API interface { // under the TSDB's data directory and returns the directory as response. Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, error) // Rules returns a list of alerting and recording rules that are currently loaded. - Rules(ctx context.Context) (RulesResult, error) + Rules(ctx context.Context, matches []string) (RulesResult, error) // Targets returns an overview of the current state of the Prometheus target discovery. Targets(ctx context.Context) (TargetsResult, error) // TargetsMetadata returns metadata about metrics currently scraped by the target. @@ -1235,8 +1235,15 @@ func (h *httpAPI) Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, return res, err } -func (h *httpAPI) Rules(ctx context.Context) (RulesResult, error) { +func (h *httpAPI) Rules(ctx context.Context, matches []string) (RulesResult, error) { u := h.client.URL(epRules, nil) + q := u.Query() + + for _, m := range matches { + q.Add("match[]", m) + } + + u.RawQuery = q.Encode() req, err := http.NewRequest(http.MethodGet, u.String(), nil) if err != nil { diff --git a/api/prometheus/v1/api_test.go b/api/prometheus/v1/api_test.go index bacf6a096..5116989a2 100644 --- a/api/prometheus/v1/api_test.go +++ b/api/prometheus/v1/api_test.go @@ -191,9 +191,9 @@ func TestAPIs(t *testing.T) { } } - doRules := func() func() (interface{}, Warnings, error) { + doRules := func(matches []string) func() (interface{}, Warnings, error) { return func() (interface{}, Warnings, error) { - v, err := promAPI.Rules(context.Background()) + v, err := promAPI.Rules(context.Background(), matches) return v, nil, err } } @@ -689,7 +689,7 @@ func TestAPIs(t *testing.T) { }, { - do: doRules(), + do: doRules(nil), reqMethod: "GET", reqPath: "/api/v1/rules", inRes: map[string]interface{}{ @@ -784,7 +784,7 @@ func TestAPIs(t *testing.T) { // This has the newer API elements like lastEvaluation, evaluationTime, etc. { - do: doRules(), + do: doRules(nil), reqMethod: "GET", reqPath: "/api/v1/rules", inRes: map[string]interface{}{ @@ -888,7 +888,63 @@ func TestAPIs(t *testing.T) { }, { - do: doRules(), + do: doRules([]string{`severity="info"`}), + reqMethod: "GET", + reqPath: "/api/v1/rules", + inRes: map[string]interface{}{ + "groups": []map[string]interface{}{ + { + "file": "/rules.yaml", + "interval": 60, + "name": "example", + "rules": []map[string]interface{}{ + { + "alerts": []map[string]interface{}{}, + "annotations": map[string]interface{}{ + "summary": "High request latency", + }, + "duration": 600, + "health": "ok", + "labels": map[string]interface{}{ + "severity": "info", + }, + "name": "HighRequestLatency", + "query": "job:request_latency_seconds:mean5m{job=\"myjob\"} > 0.5", + "type": "alerting", + }, + }, + }, + }, + }, + res: RulesResult{ + Groups: []RuleGroup{ + { + Name: "example", + File: "/rules.yaml", + Interval: 60, + Rules: []interface{}{ + AlertingRule{ + Alerts: []*Alert{}, + Annotations: model.LabelSet{ + "summary": "High request latency", + }, + Labels: model.LabelSet{ + "severity": "info", + }, + Duration: 600, + Health: RuleHealthGood, + Name: "HighRequestLatency", + Query: "job:request_latency_seconds:mean5m{job=\"myjob\"} > 0.5", + LastError: "", + }, + }, + }, + }, + }, + }, + + { + do: doRules(nil), reqMethod: "GET", reqPath: "/api/v1/rules", inErr: errors.New("some error"),