Skip to content

Commit 4418ae9

Browse files
committed
support v1 rules, update changelog, address review comments
Signed-off-by: Jacob Lisi <[email protected]>
1 parent 4f4ee76 commit 4418ae9

File tree

11 files changed

+210
-118
lines changed

11 files changed

+210
-118
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ require (
4141
github.com/hashicorp/go-cleanhttp v0.5.1
4242
github.com/hashicorp/go-sockaddr v1.0.2
4343
github.com/hashicorp/memberlist v0.1.4
44-
github.com/jonboulle/clockwork v0.1.0
4544
github.com/json-iterator/go v1.1.7
4645
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
4746
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 // indirect

pkg/configs/client/client.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
"github.com/cortexproject/cortex/pkg/util/flagext"
1515
"github.com/go-kit/kit/log/level"
1616
"github.com/prometheus/client_golang/prometheus"
17-
"github.com/prometheus/client_golang/prometheus/promauto"
17+
"github.com/weaveworks/common/instrument"
1818
)
1919

2020
// Config says where we can find the ruler configs.
@@ -29,12 +29,12 @@ func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) {
2929
f.DurationVar(&cfg.ClientTimeout, prefix+"configs.client-timeout", 5*time.Second, "Timeout for requests to Weave Cloud configs service.")
3030
}
3131

32-
var configsRequestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
32+
var configsRequestDuration = instrument.NewHistogramCollector(prometheus.NewHistogramVec(prometheus.HistogramOpts{
3333
Namespace: "cortex",
3434
Name: "configs_request_duration_seconds",
3535
Help: "Time spent requesting configs.",
3636
Buckets: prometheus.DefBuckets,
37-
}, []string{"operation", "status_code"})
37+
}, []string{"operation", "status_code"}))
3838

3939
// Client is what the ruler and altermanger needs from a config store to process rules.
4040
type Client interface {
@@ -67,7 +67,12 @@ func (c ConfigDBClient) GetRules(ctx context.Context, since configs.ID) (map[str
6767
suffix = fmt.Sprintf("?since=%d", since)
6868
}
6969
endpoint := fmt.Sprintf("%s/private/api/prom/configs/rules%s", c.URL.String(), suffix)
70-
response, err := doRequest(endpoint, c.Timeout, since, "GetRules")
70+
var response *ConfigsResponse
71+
err := instrument.CollectedRequest(ctx, "GetRules", configsRequestDuration, instrument.ErrorCode, func(ctx context.Context) error {
72+
var err error
73+
response, err = doRequest(endpoint, c.Timeout, since)
74+
return err
75+
})
7176
if err != nil {
7277
return nil, err
7378
}
@@ -88,23 +93,27 @@ func (c ConfigDBClient) GetAlerts(ctx context.Context, since configs.ID) (*Confi
8893
suffix = fmt.Sprintf("?since=%d", since)
8994
}
9095
endpoint := fmt.Sprintf("%s/private/api/prom/configs/alertmanager%s", c.URL.String(), suffix)
91-
return doRequest(endpoint, c.Timeout, since, "GetAlerts")
96+
var response *ConfigsResponse
97+
err := instrument.CollectedRequest(ctx, "GetAlerts", configsRequestDuration, instrument.ErrorCode, func(ctx context.Context) error {
98+
var err error
99+
response, err = doRequest(endpoint, c.Timeout, since)
100+
return err
101+
})
102+
return response, err
92103
}
93104

94-
func doRequest(endpoint string, timeout time.Duration, since configs.ID, operation string) (*ConfigsResponse, error) {
105+
func doRequest(endpoint string, timeout time.Duration, since configs.ID) (*ConfigsResponse, error) {
95106
req, err := http.NewRequest("GET", endpoint, nil)
96107
if err != nil {
97108
return nil, err
98109
}
99110

100111
client := &http.Client{Timeout: timeout}
101112

102-
start := time.Now()
103113
resp, err := client.Do(req)
104114
if err != nil {
105115
return nil, err
106116
}
107-
configsRequestDuration.WithLabelValues(operation, resp.Status).Observe(time.Since(start).Seconds())
108117
defer resp.Body.Close()
109118

110119
if resp.StatusCode != http.StatusOK {

pkg/configs/client/config.go

Lines changed: 0 additions & 66 deletions
This file was deleted.

pkg/configs/client/configs_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func TestDoRequest(t *testing.T) {
3434
}))
3535
defer server.Close()
3636

37-
resp, err := doRequest(server.URL, 1*time.Second, 0, "TestDoRequest")
37+
resp, err := doRequest(server.URL, 1*time.Second, 0)
3838
assert.Nil(t, err)
3939

4040
expected := ConfigsResponse{Configs: map[string]configs.View{

pkg/configs/configs.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
"github.com/go-kit/kit/log"
9+
"github.com/prometheus/common/model"
910
"github.com/prometheus/prometheus/pkg/labels"
1011
"github.com/prometheus/prometheus/pkg/rulefmt"
1112
"github.com/prometheus/prometheus/promql"
@@ -185,7 +186,21 @@ func (c RulesConfig) Parse() (map[string][]rules.Rule, error) {
185186
// ParseFormatted returns the rulefmt map of a users rules configs. It allows
186187
// for rules to be mapped to disk and read by the prometheus rules manager.
187188
func (c RulesConfig) ParseFormatted() (map[string]rulefmt.RuleGroups, error) {
189+
switch c.FormatVersion {
190+
case RuleFormatV1:
191+
return c.parseV1Formatted()
192+
case RuleFormatV2:
193+
return c.parseV2Formatted()
194+
default:
195+
return nil, fmt.Errorf("unknown rule format version %v", c.FormatVersion)
196+
}
197+
}
198+
199+
// parseV2 parses and validates the content of the rule files in a RulesConfig
200+
// according to the Prometheus 2.x rule format.
201+
func (c RulesConfig) parseV2Formatted() (map[string]rulefmt.RuleGroups, error) {
188202
ruleMap := map[string]rulefmt.RuleGroups{}
203+
189204
for fn, content := range c.Files {
190205
rgs, errs := rulefmt.Parse([]byte(content))
191206
if errs != nil {
@@ -199,6 +214,63 @@ func (c RulesConfig) ParseFormatted() (map[string]rulefmt.RuleGroups, error) {
199214
return ruleMap, nil
200215
}
201216

217+
// parseV1 parses and validates the content of the rule files in a RulesConfig
218+
// according to the Prometheus 1.x rule format.
219+
func (c RulesConfig) parseV1Formatted() (map[string]rulefmt.RuleGroups, error) {
220+
result := map[string]rulefmt.RuleGroups{}
221+
for fn, content := range c.Files {
222+
stmts, err := legacy_promql.ParseStmts(content)
223+
if err != nil {
224+
return nil, fmt.Errorf("error parsing %s: %s", fn, err)
225+
}
226+
227+
ra := []rulefmt.Rule{}
228+
for _, stmt := range stmts {
229+
var rule rulefmt.Rule
230+
switch r := stmt.(type) {
231+
case *legacy_promql.AlertStmt:
232+
_, err := promql.ParseExpr(r.Expr.String())
233+
if err != nil {
234+
return nil, err
235+
}
236+
237+
rule = rulefmt.Rule{
238+
Alert: r.Name,
239+
Expr: r.Expr.String(),
240+
For: model.Duration(r.Duration),
241+
Labels: r.Labels.Map(),
242+
Annotations: r.Annotations.Map(),
243+
}
244+
245+
case *legacy_promql.RecordStmt:
246+
_, err := promql.ParseExpr(r.Expr.String())
247+
if err != nil {
248+
return nil, err
249+
}
250+
251+
rule = rulefmt.Rule{
252+
Record: r.Name,
253+
Expr: r.Expr.String(),
254+
Labels: r.Labels.Map(),
255+
}
256+
257+
default:
258+
return nil, fmt.Errorf("ruler.GetRules: unknown statement type")
259+
}
260+
ra = append(ra, rule)
261+
}
262+
result[fn] = rulefmt.RuleGroups{
263+
Groups: []rulefmt.RuleGroup{
264+
{
265+
Name: "rg:" + fn,
266+
Rules: ra,
267+
},
268+
},
269+
}
270+
}
271+
return result, nil
272+
}
273+
202274
// parseV2 parses and validates the content of the rule files in a RulesConfig
203275
// according to the Prometheus 2.x rule format.
204276
//

pkg/configs/configs_test.go

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,36 @@ import (
66
"testing"
77
"time"
88

9+
"github.com/cortexproject/cortex/pkg/util"
910
"github.com/go-kit/kit/log"
11+
"github.com/prometheus/common/model"
1012
"github.com/prometheus/prometheus/pkg/labels"
13+
"github.com/prometheus/prometheus/pkg/rulefmt"
1114
"github.com/prometheus/prometheus/promql"
1215
"github.com/prometheus/prometheus/rules"
1316
"github.com/stretchr/testify/assert"
1417
"github.com/stretchr/testify/require"
15-
16-
"github.com/cortexproject/cortex/pkg/util"
1718
)
1819

20+
var legacyRulesFile = `ALERT TestAlert
21+
IF up == 0
22+
FOR 5m
23+
LABELS { severity = "critical" }
24+
ANNOTATIONS {
25+
message = "I am a message"
26+
}`
27+
28+
var ruleFile = `groups:
29+
- name: example
30+
rules:
31+
- alert: TestAlert
32+
expr: up == 0
33+
for: 5m
34+
labels:
35+
severity: critical
36+
annotations:
37+
message: I am a message`
38+
1939
func TestUnmarshalLegacyConfigWithMissingRuleFormatVersionSucceeds(t *testing.T) {
2040
actual := Config{}
2141
buf := []byte(`{"rules_files": {"a": "b"}}`)
@@ -104,3 +124,70 @@ groups:
104124
})
105125
}
106126
}
127+
128+
func TestParseFormatted(t *testing.T) {
129+
dur, err := model.ParseDuration("5m")
130+
require.NoError(t, err)
131+
132+
rules := []rulefmt.Rule{
133+
{
134+
Alert: "TestAlert",
135+
Expr: "up == 0",
136+
For: dur,
137+
Labels: map[string]string{
138+
"severity": "critical",
139+
},
140+
Annotations: map[string]string{
141+
"message": "I am a message",
142+
},
143+
},
144+
}
145+
146+
for i, tc := range []struct {
147+
cfg RulesConfig
148+
expected map[string]rulefmt.RuleGroups
149+
}{
150+
{
151+
cfg: RulesConfig{
152+
FormatVersion: RuleFormatV1,
153+
Files: map[string]string{
154+
"legacy.rules": legacyRulesFile,
155+
},
156+
},
157+
expected: map[string]rulefmt.RuleGroups{
158+
"legacy.rules": {
159+
Groups: []rulefmt.RuleGroup{
160+
{
161+
Name: "rg:legacy.rules",
162+
Rules: rules,
163+
},
164+
},
165+
},
166+
},
167+
},
168+
{
169+
cfg: RulesConfig{
170+
FormatVersion: RuleFormatV2,
171+
Files: map[string]string{
172+
"alerts.yaml": ruleFile,
173+
},
174+
},
175+
expected: map[string]rulefmt.RuleGroups{
176+
"alerts.yaml": {
177+
Groups: []rulefmt.RuleGroup{
178+
{
179+
Name: "example",
180+
Rules: rules,
181+
},
182+
},
183+
},
184+
},
185+
},
186+
} {
187+
t.Run(strconv.Itoa(i), func(t *testing.T) {
188+
rules, err := tc.cfg.ParseFormatted()
189+
require.NoError(t, err)
190+
require.Equal(t, tc.expected, rules)
191+
})
192+
}
193+
}

pkg/cortex/cortex.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ type Config struct {
7474
Encoding encoding.Config `yaml:"-"` // No yaml for this, it only works with flags.
7575
TSDB tsdb.Config `yaml:"tsdb"`
7676

77-
ConfigDB db.Config `yaml:"configdb,omitempty"`
7877
Ruler ruler.Config `yaml:"ruler,omitempty"`
7978
ConfigDB db.Config `yaml:"configdb,omitempty"`
8079
ConfigStore config_client.Config `yaml:"config_store,omitempty"`

0 commit comments

Comments
 (0)