From e414e790f7410d22b1c337be7d4b7c2473ffd039 Mon Sep 17 00:00:00 2001 From: djpnicholls <109083091+djpnicholls@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:43:51 +0100 Subject: [PATCH] Alerting Provisioning: Don't error on recording rules without conditions (#109410) * Don't error on recording rules without conditions The provisioning model doesn't include conditions for recording rules. Only return an error for a missing condition if the rule isn't a recording rule. Also, added a test case to show the failure. This resolves #109398 * Run `go fmt` to fix whitespace issues --- .../provisioning/alerting/rules_types.go | 8 ++-- .../provisioning/alerting/rules_types_test.go | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/pkg/services/provisioning/alerting/rules_types.go b/pkg/services/provisioning/alerting/rules_types.go index b5b28072beb..bac091ababa 100644 --- a/pkg/services/provisioning/alerting/rules_types.go +++ b/pkg/services/provisioning/alerting/rules_types.go @@ -151,10 +151,6 @@ func (rule *AlertRuleV1) mapToModel(orgID int64) (models.AlertRule, error) { noDataState = models.NoData } alertRule.NoDataState = noDataState - alertRule.Condition = rule.Condition.Value() - if alertRule.Condition == "" { - return models.AlertRule{}, fmt.Errorf("rule '%s' failed to parse: no condition set", alertRule.Title) - } alertRule.Annotations = rule.Annotations.Raw alertRule.Labels = rule.Labels.Value() for _, queryV1 := range rule.Data { @@ -182,6 +178,10 @@ func (rule *AlertRuleV1) mapToModel(orgID int64) (models.AlertRule, error) { } alertRule.Record = &record } + alertRule.Condition = rule.Condition.Value() + if alertRule.Condition == "" && alertRule.Record == nil { + return models.AlertRule{}, fmt.Errorf("rule '%s' failed to parse: no condition set", alertRule.Title) + } return alertRule, nil } diff --git a/pkg/services/provisioning/alerting/rules_types_test.go b/pkg/services/provisioning/alerting/rules_types_test.go index 16c510707b9..9c4e819ff73 100644 --- a/pkg/services/provisioning/alerting/rules_types_test.go +++ b/pkg/services/provisioning/alerting/rules_types_test.go @@ -202,6 +202,14 @@ func TestRules(t *testing.T) { }) } +func TestRecordingRules(t *testing.T) { + t.Run("a valid rule should not error", func(t *testing.T) { + rule := validRecordingRuleV1(t) + _, err := rule.mapToModel(1) + require.NoError(t, err) + }) +} + func TestNotificationsSettingsV1MapToModel(t *testing.T) { tests := []struct { name string @@ -347,6 +355,37 @@ func validRuleV1(t *testing.T) AlertRuleV1 { } } +func validRecordingRuleV1(t *testing.T) AlertRuleV1 { + t.Helper() + var ( + title values.StringValue + uid values.StringValue + forDuration values.StringValue + metric values.StringValue + from values.StringValue + ) + err := yaml.Unmarshal([]byte("test"), &title) + require.NoError(t, err) + err = yaml.Unmarshal([]byte("test_uid"), &uid) + require.NoError(t, err) + err = yaml.Unmarshal([]byte("10s"), &forDuration) + require.NoError(t, err) + err = yaml.Unmarshal([]byte("test_metric"), &metric) + require.NoError(t, err) + err = yaml.Unmarshal([]byte("A"), &from) + require.NoError(t, err) + return AlertRuleV1{ + Title: title, + UID: uid, + For: forDuration, + Record: &RecordV1{ + Metric: metric, + From: from, + }, + Data: []QueryV1{{}}, + } +} + func stringToStringValue(s string) values.StringValue { result := values.StringValue{} err := yaml.Unmarshal([]byte(s), &result)