diff --git a/app/vmalert/alerting.go b/app/vmalert/alerting.go index 08960f031..7e11ad850 100644 --- a/app/vmalert/alerting.go +++ b/app/vmalert/alerting.go @@ -53,7 +53,7 @@ func newAlertingRule(group *Group, cfg config.Rule) *AlertingRule { RuleID: cfg.ID, Name: cfg.Alert, Expr: cfg.Expr, - For: cfg.For, + For: cfg.For.Duration(), Labels: cfg.Labels, Annotations: cfg.Annotations, GroupID: group.ID(), diff --git a/app/vmalert/config/config.go b/app/vmalert/config/config.go index cd40af7af..11f8f7eb8 100644 --- a/app/vmalert/config/config.go +++ b/app/vmalert/config/config.go @@ -94,7 +94,7 @@ type Rule struct { Record string `yaml:"record,omitempty"` Alert string `yaml:"alert,omitempty"` Expr string `yaml:"expr"` - For time.Duration `yaml:"for,omitempty"` + For PromDuration `yaml:"for,omitempty"` Labels map[string]string `yaml:"labels,omitempty"` Annotations map[string]string `yaml:"annotations,omitempty"` @@ -102,6 +102,37 @@ type Rule struct { XXX map[string]interface{} `yaml:",inline"` } +// PromDuration is Prometheus duration. +type PromDuration struct { + milliseconds int64 +} + +// NewPromDuration returns PromDuration for given d. +func NewPromDuration(d time.Duration) PromDuration { + return PromDuration{ + milliseconds: d.Milliseconds(), + } +} + +// UnmarshalYAML implements yaml.Unmarshaler interface. +func (pd *PromDuration) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + ms, err := metricsql.DurationValue(s, 0) + if err != nil { + return err + } + pd.milliseconds = ms + return nil +} + +// Duration returns duration for pd. +func (pd *PromDuration) Duration() time.Duration { + return time.Duration(pd.milliseconds) * time.Millisecond +} + // UnmarshalYAML implements the yaml.Unmarshaler interface. func (r *Rule) UnmarshalYAML(unmarshal func(interface{}) error) error { type rule Rule diff --git a/app/vmalert/config/config_test.go b/app/vmalert/config/config_test.go index d01665980..a631e6ddc 100644 --- a/app/vmalert/config/config_test.go +++ b/app/vmalert/config/config_test.go @@ -270,7 +270,7 @@ func TestHashRule(t *testing.T) { true, }, { - Rule{Alert: "alert", Expr: "up == 1", For: time.Minute}, + Rule{Alert: "alert", Expr: "up == 1", For: NewPromDuration(time.Minute)}, Rule{Alert: "alert", Expr: "up == 1"}, true, }, diff --git a/app/vmalert/config/testdata/kube-good.rules b/app/vmalert/config/testdata/kube-good.rules index a6e3e3e90..25ab513fc 100644 --- a/app/vmalert/config/testdata/kube-good.rules +++ b/app/vmalert/config/testdata/kube-good.rules @@ -665,7 +665,7 @@ / sum(rate(kube_state_metrics_list_total{job="kube-state-metrics"}[5m]))) > 0.01 - for: 15m + for: 1d labels: severity: critical - alert: KubeStateMetricsWatchErrors @@ -1724,4 +1724,4 @@ rate(prometheus_operator_node_address_lookup_errors_total{job="prometheus-operator",namespace="monitoring"}[5m]) > 0.1 for: 10m labels: - severity: warning \ No newline at end of file + severity: warning diff --git a/app/vmalert/group_test.go b/app/vmalert/group_test.go index c18f8d487..4a3246a1c 100644 --- a/app/vmalert/group_test.go +++ b/app/vmalert/group_test.go @@ -32,7 +32,7 @@ func TestUpdateWith(t *testing.T) { []config.Rule{{ Alert: "foo", Expr: "up > 0", - For: time.Second, + For: config.NewPromDuration(time.Second), Labels: map[string]string{ "bar": "baz", }, @@ -44,7 +44,7 @@ func TestUpdateWith(t *testing.T) { []config.Rule{{ Alert: "foo", Expr: "up > 10", - For: time.Second, + For: config.NewPromDuration(time.Second), Labels: map[string]string{ "baz": "bar", }, diff --git a/lib/promscrape/config_test.go b/lib/promscrape/config_test.go index fa329d5bb..e84567b40 100644 --- a/lib/promscrape/config_test.go +++ b/lib/promscrape/config_test.go @@ -93,7 +93,7 @@ scrape_configs: t.Fatalf("cannot parase data: %s", err) } sws := cfg.getStaticScrapeWork() - resetScrapeWorkIDs(sws) + resetNonEssentialFields(sws) swsExpected := []ScrapeWork{{ ScrapeURL: "http://black:9115/probe?module=dns_udp_example&target=8.8.8.8", ScrapeInterval: defaultScrapeInterval, @@ -440,9 +440,10 @@ scrape_configs: `) } -func resetScrapeWorkIDs(sws []ScrapeWork) { +func resetNonEssentialFields(sws []ScrapeWork) { for i := range sws { sws[i].ID = 0 + sws[i].OriginalLabels = nil } } @@ -453,7 +454,7 @@ func TestGetFileSDScrapeWorkSuccess(t *testing.T) { if err != nil { t.Fatalf("unexpected error: %s", err) } - resetScrapeWorkIDs(sws) + resetNonEssentialFields(sws) // Remove `__vm_filepath` label, since its value depends on the current working dir. for i := range sws { @@ -609,7 +610,7 @@ func TestGetStaticScrapeWorkSuccess(t *testing.T) { if err != nil { t.Fatalf("unexpected error: %s", err) } - resetScrapeWorkIDs(sws) + resetNonEssentialFields(sws) if !reflect.DeepEqual(sws, expectedSws) { t.Fatalf("unexpected scrapeWork; got\n%v\nwant\n%v", sws, expectedSws) }