Skip to content

Commit

Permalink
Rule group detect rule name conflicts (#1610)
Browse files Browse the repository at this point in the history
* grafana_rule_group: Detect rule name conflicts

* update grafana_rule_group unit test

* revert alert group name check

* Fix undeclared variables

* fix resource_alerting_rule_group unit test
  • Loading branch information
WeberKuo authored Jun 5, 2024
1 parent 8c78dfc commit 5ab97ee
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 17 deletions.
30 changes: 23 additions & 7 deletions internal/resources/grafana/resource_alerting_rule_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand All @@ -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)
}

Expand Down
93 changes: 83 additions & 10 deletions internal/resources/grafana/resource_alerting_rule_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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")

Expand Down

0 comments on commit 5ab97ee

Please sign in to comment.