diff --git a/internal/resources/grafana/resource_alerting_rule_group.go b/internal/resources/grafana/resource_alerting_rule_group.go index 68720b53c..700d0fff9 100644 --- a/internal/resources/grafana/resource_alerting_rule_group.go +++ b/internal/resources/grafana/resource_alerting_rule_group.go @@ -340,18 +340,19 @@ func readAlertRuleGroup(ctx context.Context, data *schema.ResourceData, meta int func putAlertRuleGroup(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { client, orgID := OAPIClientFromNewOrgResource(meta, data) + respAlertRules, err := client.Provisioning.GetAlertRules() + if err != nil { + return diag.FromErr(err) + } + if data.IsNewResource() { // Check if a rule group with the same name already exists. The API either: - // - returns a 500 error if it exists in a different folder, which is not very helpful. // - overwrites the existing rule group if it exists in the same folder, which is not expected of a TF provider. - resp, err := client.Provisioning.GetAlertRules() - if err != nil { - return diag.FromErr(err) - } - for _, rule := range resp.Payload { + for _, rule := range respAlertRules.Payload { name := data.Get("name").(string) - if *rule.RuleGroup == name { + folder := data.Get("folder_uid").(string) + if *rule.RuleGroup == name && *rule.FolderUID == folder { return diag.Errorf("rule group with name %q already exists", name) } } @@ -363,11 +364,26 @@ func putAlertRuleGroup(ctx context.Context, data *schema.ResourceData, meta inte packedRules := data.Get("rule").([]interface{}) rules := make([]*models.ProvisionedAlertRule, 0, len(packedRules)) + for i := range packedRules { rule, err := unpackAlertRule(packedRules[i], group, folder, orgID) if err != nil { return diag.FromErr(err) } + + // Check if a rule with the same name already exists. + for _, r := range rules { + if *r.Title == *rule.Title { + return diag.Errorf("rule with name %q is defined more than once", *rule.Title) + } + } + + for _, r := range respAlertRules.Payload { + if r.UID != rule.UID && *r.Title == *rule.Title && *r.FolderUID == *rule.FolderUID { + return diag.Errorf("rule with name %q already exists in the alert group", *rule.Title) + } + } + rules = append(rules, rule) } diff --git a/internal/resources/grafana/resource_alerting_rule_group_test.go b/internal/resources/grafana/resource_alerting_rule_group_test.go index 307f072a3..3ee128225 100644 --- a/internal/resources/grafana/resource_alerting_rule_group_test.go +++ b/internal/resources/grafana/resource_alerting_rule_group_test.go @@ -307,15 +307,15 @@ resource "grafana_organization" "test" { name = "%[1]s" } -resource "grafana_folder" "first" { +resource "grafana_folder" "test" { org_id = grafana_organization.test.id - title = "%[1]s-first" + title = "%[1]s-test" } resource "grafana_rule_group" "first" { org_id = grafana_organization.test.id name = "%[1]s" - folder_uid = grafana_folder.first.uid + folder_uid = grafana_folder.test.uid interval_seconds = 60 rule { name = "My Alert Rule first" @@ -342,16 +342,11 @@ resource "grafana_rule_group" "first" { } } -resource "grafana_folder" "second" { - depends_on = [grafana_rule_group.first] - org_id = grafana_organization.test.id - title = "%[1]s-second" -} - resource "grafana_rule_group" "second" { + depends_on = [ grafana_rule_group.first ] org_id = grafana_organization.test.id name = "%[1]s" - folder_uid = grafana_folder.second.uid + folder_uid = grafana_folder.test.uid interval_seconds = 60 rule { name = "My Alert Rule second" @@ -384,6 +379,84 @@ resource "grafana_rule_group" "second" { }) } +func TestAccAlertRule_ruleNameConflict(t *testing.T) { + testutils.CheckOSSTestsEnabled(t, ">=9.1.0") + + name := acctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + ProtoV5ProviderFactories: testutils.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(` +resource "grafana_organization" "test" { + name = "%[1]s" +} + +resource "grafana_folder" "first" { + org_id = grafana_organization.test.id + title = "%[1]s-first" +} + +resource "grafana_rule_group" "first" { + org_id = grafana_organization.test.id + name = "alert rule group" + folder_uid = grafana_folder.first.uid + interval_seconds = 60 + rule { + name = "My Alert Rule" + for = "2m" + condition = "B" + no_data_state = "NoData" + exec_err_state = "Alerting" + is_paused = false + data { + ref_id = "A" + query_type = "" + relative_time_range { + from = 600 + to = 0 + } + datasource_uid = "PD8C576611E62080A" + model = jsonencode({ + hide = false + intervalMs = 1000 + maxDataPoints = 43200 + refId = "A" + }) + } + } + rule { + name = "My Alert Rule" + for = "2m" + condition = "B" + no_data_state = "NoData" + exec_err_state = "Alerting" + is_paused = false + data { + ref_id = "A" + query_type = "" + relative_time_range { + from = 600 + to = 0 + } + datasource_uid = "PD8C576611E62080A" + model = jsonencode({ + hide = false + intervalMs = 1000 + maxDataPoints = 43200 + refId = "A" + }) + } + } +} + `, name), + ExpectError: regexp.MustCompile(`rule with name "My Alert Rule" is defined more than once`), + }, + }, + }) +} + func TestAccAlertRule_disableProvenance(t *testing.T) { testutils.CheckOSSTestsEnabled(t, ">=9.1.0")