Skip to content

Commit

Permalink
Alerting Rule Groups: Fix provisioning in non-default org (#1124)
Browse files Browse the repository at this point in the history
Closes #1120
Use the same pattern as other org-scoped resources to create the client
  • Loading branch information
julienduchesne authored Nov 3, 2023
1 parent 0f123f7 commit f3b1845
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 19 deletions.
5 changes: 4 additions & 1 deletion docs/resources/rule_group.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,12 @@ EOT
- `folder_uid` (String) The UID of the folder that the group belongs to.
- `interval_seconds` (Number) The interval, in seconds, at which all rules in the group are evaluated. If a group contains many rules, the rules are evaluated sequentially.
- `name` (String) The name of the rule group.
- `org_id` (String) The ID of the org to which the group belongs.
- `rule` (Block List, Min: 1) The rules within the group. (see [below for nested schema](#nestedblock--rule))

### Optional

- `org_id` (String) The Organization ID. If not set, the Org ID defined in the provider block will be used.

### Read-Only

- `id` (String) The ID of this resource.
Expand Down
25 changes: 9 additions & 16 deletions internal/resources/grafana/resource_alerting_rule_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ This resource requires Grafana 9.1.0 or later.

SchemaVersion: 0,
Schema: map[string]*schema.Schema{
"org_id": orgIDAttribute(),
"name": {
Type: schema.TypeString,
Required: true,
Expand All @@ -54,12 +55,6 @@ This resource requires Grafana 9.1.0 or later.
Required: true,
Description: "The interval, in seconds, at which all rules in the group are evaluated. If a group contains many rules, the rules are evaluated sequentially.",
},
"org_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The ID of the org to which the group belongs.",
},
"rule": {
Type: schema.TypeList,
Required: true,
Expand Down Expand Up @@ -192,9 +187,9 @@ This resource requires Grafana 9.1.0 or later.
}

func readAlertRuleGroup(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*common.Client).GrafanaAPI
client, orgID, idStr := ClientFromExistingOrgResource(meta, data.Id())

key := UnpackGroupID(data.Id())
key := UnpackGroupID(idStr)

group, err := client.AlertRuleGroup(key.FolderUID, key.Name)
if err, shouldReturn := common.CheckReadError("rule group", data, err); shouldReturn {
Expand All @@ -204,13 +199,13 @@ func readAlertRuleGroup(ctx context.Context, data *schema.ResourceData, meta int
if err := packRuleGroup(group, data); err != nil {
return diag.FromErr(err)
}
data.SetId(packGroupID(ruleKeyFromGroup(group)))
data.SetId(MakeOrgResourceID(orgID, packGroupID(ruleKeyFromGroup(group))))

return nil
}

func createAlertRuleGroup(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*common.Client).GrafanaAPI
client, orgID := ClientFromNewOrgResource(meta, data)

group, err := unpackRuleGroup(data)
if err != nil {
Expand All @@ -222,31 +217,29 @@ func createAlertRuleGroup(ctx context.Context, data *schema.ResourceData, meta i
return diag.FromErr(err)
}

data.SetId(packGroupID(key))
data.SetId(MakeOrgResourceID(orgID, packGroupID(key)))
return readAlertRuleGroup(ctx, data, meta)
}

func updateAlertRuleGroup(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*common.Client).GrafanaAPI
client, _, _ := ClientFromExistingOrgResource(meta, data.Id())

group, err := unpackRuleGroup(data)
if err != nil {
return diag.FromErr(err)
}
key := ruleKeyFromGroup(group)

if err = client.SetAlertRuleGroup(group); err != nil {
return diag.FromErr(err)
}

data.SetId(packGroupID(key))
return readAlertRuleGroup(ctx, data, meta)
}

func deleteAlertRuleGroup(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*common.Client).GrafanaAPI
client, _, idStr := ClientFromExistingOrgResource(meta, data.Id())

key := UnpackGroupID(data.Id())
key := UnpackGroupID(idStr)

group, err := client.AlertRuleGroup(key.FolderUID, key.Name)
if err != nil {
Expand Down
100 changes: 98 additions & 2 deletions internal/resources/grafana/resource_alerting_rule_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/grafana/terraform-provider-grafana/internal/common"
"github.com/grafana/terraform-provider-grafana/internal/resources/grafana"
"github.com/grafana/terraform-provider-grafana/internal/testutils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
Expand Down Expand Up @@ -212,6 +213,54 @@ func TestAccAlertRule_compound(t *testing.T) {
})
}

func TestAccAlertRule_inOrg(t *testing.T) {
testutils.CheckOSSTestsEnabled(t, ">=9.1.0")

var group gapi.RuleGroup
var org gapi.Org
name := acctest.RandString(10)

resource.ParallelTest(t, resource.TestCase{
ProviderFactories: testutils.ProviderFactories,
// Implicitly tests deletion.
CheckDestroy: testAlertRuleCheckDestroy(&group),
Steps: []resource.TestStep{
// Test creation.
{
Config: testAccAlertRuleGroupInOrgConfig(name, 240),
Check: resource.ComposeTestCheckFunc(
testRuleGroupCheckExists("grafana_rule_group.test", &group),
testAccOrganizationCheckExists("grafana_organization.test", &org),
checkResourceIsInOrg("grafana_rule_group.test", "grafana_organization.test"),
resource.TestCheckResourceAttr("grafana_rule_group.test", "name", name),
resource.TestCheckResourceAttr("grafana_rule_group.test", "interval_seconds", "240"),
resource.TestCheckResourceAttr("grafana_rule_group.test", "rule.#", "1"),
resource.TestCheckResourceAttr("grafana_rule_group.test", "rule.0.data.0.model", "{\"hide\":false,\"refId\":\"A\"}"),
),
},
// Test update content.
{
Config: testAccAlertRuleGroupInOrgConfig(name, 360),
Check: resource.ComposeTestCheckFunc(
testRuleGroupCheckExists("grafana_rule_group.test", &group),
testAccOrganizationCheckExists("grafana_organization.test", &org),
checkResourceIsInOrg("grafana_rule_group.test", "grafana_organization.test"),
resource.TestCheckResourceAttr("grafana_rule_group.test", "name", name),
resource.TestCheckResourceAttr("grafana_rule_group.test", "interval_seconds", "360"),
resource.TestCheckResourceAttr("grafana_rule_group.test", "rule.#", "1"),
resource.TestCheckResourceAttr("grafana_rule_group.test", "rule.0.data.0.model", "{\"hide\":false,\"refId\":\"A\"}"),
),
},
// Test import.
{
ResourceName: "grafana_rule_group.test",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testRuleGroupCheckExists(rname string, g *gapi.RuleGroup) resource.TestCheckFunc {
return func(s *terraform.State) error {
resource, ok := s.RootModule().Resources[rname]
Expand All @@ -223,8 +272,9 @@ func testRuleGroupCheckExists(rname string, g *gapi.RuleGroup) resource.TestChec
return fmt.Errorf("resource id not set")
}

client := testutils.Provider.Meta().(*common.Client).GrafanaAPI
key := grafana.UnpackGroupID(resource.Primary.ID)
orgID, idStr := grafana.SplitOrgResourceID(resource.Primary.ID)
key := grafana.UnpackGroupID(idStr)
client := testutils.Provider.Meta().(*common.Client).GrafanaAPI.WithOrgID(orgID)
grp, err := client.AlertRuleGroup(key.FolderUID, key.Name)
if err != nil {
return fmt.Errorf("error getting resource: %s", err)
Expand All @@ -238,10 +288,56 @@ func testRuleGroupCheckExists(rname string, g *gapi.RuleGroup) resource.TestChec
func testAlertRuleCheckDestroy(group *gapi.RuleGroup) resource.TestCheckFunc {
return func(s *terraform.State) error {
client := testutils.Provider.Meta().(*common.Client).GrafanaAPI
if len(group.Rules) > 0 {
client = client.WithOrgID(group.Rules[0].OrgID)
}
_, err := client.AlertRuleGroup(group.FolderUID, group.Title)
if err == nil && strings.HasPrefix(err.Error(), "status: 404") {
return fmt.Errorf("rule group still exists on the server")
}
return nil
}
}

func testAccAlertRuleGroupInOrgConfig(name string, interval int) string {
return fmt.Sprintf(`
resource "grafana_organization" "test" {
name = "%[1]s"
}
resource "grafana_folder" "test" {
org_id = grafana_organization.test.id
title = "%[1]s"
}
resource "grafana_rule_group" "test" {
org_id = grafana_organization.test.id
name = "%[1]s"
folder_uid = grafana_folder.test.uid
interval_seconds = %[2]d
rule {
name = "My Alert Rule 1"
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, interval)
}

0 comments on commit f3b1845

Please sign in to comment.