Skip to content

Commit 6f3ae99

Browse files
committed
Add support for rule group labels
Signed-off-by: Mustafain Ali Khan <mustalik@amazon.com>
1 parent 92787cb commit 6f3ae99

File tree

5 files changed

+212
-40
lines changed

5 files changed

+212
-40
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* [FEATURE] Querier/Ruler: Add `query_partial_data` and `rules_partial_data` limits to allow queries/rules to be evaluated with data from a single zone, if other zones are not available. #6526
77
* [FEATURE] Update prometheus alertmanager version to v0.28.0 and add new integration msteamsv2, jira, and rocketchat. #6590
88
* [FEATURE] Ingester: Support out-of-order native histogram ingestion. It automatically enabled when `-ingester.out-of-order-time-window > 0` and `-blocks-storage.tsdb.enable-native-histograms=true`. #6626 #6663
9+
* [FEATURE] Ruler: Add support for group labels. #6665
910
* [ENHANCEMENT] Query Frontend: Add new limit `-frontend.max-query-response-size` for total query response size after decompression in query frontend. #6607
1011
* [ENHANCEMENT] Alertmanager: Add nflog and silences maintenance metrics. #6659
1112
* [ENHANCEMENT] Querier: limit label APIs to query only ingesters if `start` param is not been specified. #6618

integration/ruler_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,6 +1739,106 @@ func TestRulerEvalWithQueryFrontend(t *testing.T) {
17391739
}
17401740
}
17411741

1742+
func TestRulerGroupLabels(t *testing.T) {
1743+
s, err := e2e.NewScenario(networkName)
1744+
require.NoError(t, err)
1745+
defer s.Close()
1746+
1747+
// Start dependencies.
1748+
consul := e2edb.NewConsul()
1749+
minio := e2edb.NewMinio(9000, bucketName, rulestoreBucketName)
1750+
require.NoError(t, s.StartAndWaitReady(consul, minio))
1751+
1752+
// Configure the ruler.
1753+
flags := mergeFlags(
1754+
BlocksStorageFlags(),
1755+
RulerFlags(),
1756+
map[string]string{
1757+
// Since we're not going to run any rule (our only rule is invalid), we don't need the
1758+
// store-gateway to be configured to a valid address.
1759+
"-querier.store-gateway-addresses": "localhost:12345",
1760+
// Enable the bucket index so we can skip the initial bucket scan.
1761+
"-blocks-storage.bucket-store.bucket-index.enabled": "true",
1762+
// Evaluate rules often, so that we don't need to wait for metrics to show up.
1763+
"-ruler.evaluation-interval": "2s",
1764+
"-ruler.poll-interval": "2s",
1765+
1766+
"-blocks-storage.tsdb.block-ranges-period": "1h",
1767+
"-blocks-storage.bucket-store.sync-interval": "1s",
1768+
"-blocks-storage.tsdb.retention-period": "2h",
1769+
1770+
// We run single ingester only, no replication.
1771+
"-distributor.replication-factor": "1",
1772+
},
1773+
)
1774+
1775+
const namespace = "test"
1776+
const user = "user"
1777+
1778+
distributor := e2ecortex.NewDistributor("distributor", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), flags, "")
1779+
ruler := e2ecortex.NewRuler("ruler", consul.NetworkHTTPEndpoint(), flags, "")
1780+
ingester := e2ecortex.NewIngester("ingester", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), flags, "")
1781+
require.NoError(t, s.StartAndWaitReady(distributor, ingester, ruler))
1782+
1783+
// Wait until both the distributor and ruler have updated the ring. The querier will also watch
1784+
// the store-gateway ring if blocks sharding is enabled.
1785+
require.NoError(t, distributor.WaitSumMetrics(e2e.Equals(512), "cortex_ring_tokens_total"))
1786+
require.NoError(t, ruler.WaitSumMetrics(e2e.Equals(512), "cortex_ring_tokens_total"))
1787+
1788+
c, err := e2ecortex.NewClient(distributor.HTTPEndpoint(), "", "", ruler.HTTPEndpoint(), user)
1789+
require.NoError(t, err)
1790+
1791+
groupLabels := map[string]string{
1792+
"group_label_1": "val1",
1793+
"group_label_2": "val2",
1794+
"duplicate_label": "group_val",
1795+
}
1796+
ruleLabels := map[string]string{
1797+
"rule_label_1": "val1",
1798+
"rule_label_2": "val2",
1799+
"duplicate_label": "rule_val",
1800+
}
1801+
var recordNode = yaml.Node{}
1802+
var exprNode = yaml.Node{}
1803+
recordNode.SetString("ruleName")
1804+
exprNode.SetString("vector(1) > 0")
1805+
groupName := "rulegrouptest"
1806+
1807+
rg := rulefmt.RuleGroup{
1808+
Name: groupName,
1809+
Labels: groupLabels,
1810+
Interval: 10,
1811+
Rules: []rulefmt.RuleNode{{
1812+
Alert: recordNode,
1813+
Expr: exprNode,
1814+
Labels: ruleLabels,
1815+
}},
1816+
}
1817+
require.NoError(t, c.SetRuleGroup(rg, namespace))
1818+
1819+
m := ruleGroupMatcher(user, namespace, groupName)
1820+
1821+
// Wait until ruler has loaded the group.
1822+
require.NoError(t, ruler.WaitSumMetricsWithOptions(e2e.Equals(1), []string{"cortex_prometheus_rule_group_rules"}, e2e.WithLabelMatchers(m), e2e.WaitMissingMetrics))
1823+
1824+
groups, _, err := c.GetPrometheusRules(e2ecortex.RuleFilter{
1825+
RuleGroupNames: []string{groupName},
1826+
})
1827+
1828+
require.NoError(t, err)
1829+
require.NotEmpty(t, groups)
1830+
require.Equal(t, 1, len(groups))
1831+
require.Equal(t, 1, len(groups[0].Rules))
1832+
ar := parseAlertFromRule(t, groups[0].Rules[0])
1833+
require.Equal(t, 5, len(ar.Labels))
1834+
for _, label := range ar.Labels {
1835+
if label.Name == "duplicate_label" {
1836+
// rule label should override group label
1837+
require.Equal(t, ruleLabels["duplicate_label"], label.Value)
1838+
}
1839+
}
1840+
}
1841+
17421842
func parseAlertFromRule(t *testing.T, rules interface{}) *alertingRule {
17431843
responseJson, err := json.Marshal(rules)
17441844
require.NoError(t, err)

pkg/ruler/rulespb/compat.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func ToProto(user string, namespace string, rl rulefmt.RuleGroup) *RuleGroupDesc
2626
User: user,
2727
Limit: int64(rl.Limit),
2828
QueryOffset: queryOffset,
29+
Labels: cortexpb.FromLabelsToLabelAdapters(labels.FromMap(rl.Labels)),
2930
}
3031
return &rg
3132
}
@@ -60,6 +61,7 @@ func FromProto(rg *RuleGroupDesc) rulefmt.RuleGroup {
6061
Rules: make([]rulefmt.RuleNode, len(rg.GetRules())),
6162
Limit: int(rg.Limit),
6263
QueryOffset: queryOffset,
64+
Labels: cortexpb.FromLabelAdaptersToLabels(rg.Labels).Map(),
6365
}
6466

6567
for i, rl := range rg.GetRules() {

pkg/ruler/rulespb/rules.pb.go

Lines changed: 105 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ruler/rulespb/rules.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ message RuleGroupDesc {
3030
int64 limit =10;
3131
google.protobuf.Duration queryOffset = 11
3232
[(gogoproto.nullable) = true, (gogoproto.stdduration) = true];
33+
repeated cortexpb.LabelPair labels = 12 [
34+
(gogoproto.nullable) = false,
35+
(gogoproto.customtype) = "github.com/cortexproject/cortex/pkg/cortexpb.LabelAdapter"
36+
];
3337
}
3438

3539
// RuleDesc is a proto representation of a Prometheus Rule

0 commit comments

Comments
 (0)