diff --git a/internal/resources/grafana/resource_alerting_mute_timing.go b/internal/resources/grafana/resource_alerting_mute_timing.go index 62b787cd2..7938c852d 100644 --- a/internal/resources/grafana/resource_alerting_mute_timing.go +++ b/internal/resources/grafana/resource_alerting_mute_timing.go @@ -5,12 +5,15 @@ import ( "fmt" "strconv" "strings" + "time" + "github.com/go-openapi/runtime" goapi "github.com/grafana/grafana-openapi-client-go/client" "github.com/grafana/grafana-openapi-client-go/client/provisioning" "github.com/grafana/grafana-openapi-client-go/models" "github.com/grafana/terraform-provider-grafana/v2/internal/common" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -185,10 +188,24 @@ func createMuteTiming(ctx context.Context, data *schema.ResourceData, meta inter params.SetXDisableProvenance(&provenanceDisabled) } - resp, err := client.Provisioning.PostMuteTiming(params) + var resp *provisioning.PostMuteTimingCreated + err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError { + var postErr error + resp, postErr = client.Provisioning.PostMuteTiming(params) + if orgID > 1 && postErr != nil { + if apiError, ok := postErr.(*runtime.APIError); ok && (apiError.IsCode(500) || apiError.IsCode(404)) { + return retry.RetryableError(postErr) + } + } + if postErr != nil { + return retry.NonRetryableError(postErr) + } + return nil + }) if err != nil { return diag.FromErr(err) } + data.SetId(MakeOrgResourceID(orgID, resp.Payload.Name)) return readMuteTiming(ctx, data, meta) } @@ -218,11 +235,44 @@ func updateMuteTiming(ctx context.Context, data *schema.ResourceData, meta inter func deleteMuteTiming(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { client, _, name := OAPIClientFromExistingOrgResource(meta, data.Id()) - _, err := client.Provisioning.DeleteMuteTiming(name) + // Remove the mute timing from all notification policies + policyResp, err := client.Provisioning.GetPolicyTree() + if err != nil { + return diag.FromErr(err) + } + policy := policyResp.Payload + modified := false + policy, modified = removeMuteTimingFromRoute(name, policy) + if modified { + _, err = client.Provisioning.PutPolicyTree(provisioning.NewPutPolicyTreeParams().WithBody(policy)) + if err != nil { + return diag.FromErr(err) + } + } + + _, err = client.Provisioning.DeleteMuteTiming(name) diag, _ := common.CheckReadError("mute timing", data, err) return diag } +func removeMuteTimingFromRoute(name string, route *models.Route) (*models.Route, bool) { + modified := false + for i, m := range route.MuteTimeIntervals { + if m == name { + route.MuteTimeIntervals = append(route.MuteTimeIntervals[:i], route.MuteTimeIntervals[i+1:]...) + modified = true + break + } + } + for j, p := range route.Routes { + var subRouteModified bool + route.Routes[j], subRouteModified = removeMuteTimingFromRoute(name, p) + modified = modified || subRouteModified + } + + return route, modified +} + func suppressMonthDiff(k, oldValue, newValue string, d *schema.ResourceData) bool { monthNums := map[string]int{ "january": 1, diff --git a/internal/resources/grafana/resource_alerting_mute_timing_test.go b/internal/resources/grafana/resource_alerting_mute_timing_test.go index b79807453..28cdd3f6a 100644 --- a/internal/resources/grafana/resource_alerting_mute_timing_test.go +++ b/internal/resources/grafana/resource_alerting_mute_timing_test.go @@ -107,3 +107,59 @@ resource "grafana_mute_timing" "my_mute_timing" { }, }) } + +func TestAccMuteTiming_RemoveInUse(t *testing.T) { + testutils.CheckOSSTestsEnabled(t, ">9.0.0") + + config := func(mute bool) string { + return fmt.Sprintf(` + locals { + use_mute = %t + } + + resource "grafana_organization" "my_org" { + name = "mute-timing-test" + } + + resource "grafana_contact_point" "default_policy" { + org_id = grafana_organization.my_org.id + name = "default-policy" + email { + addresses = ["test@example.com"] + } + } + + resource "grafana_notification_policy" "org_policy" { + org_id = grafana_organization.my_org.id + group_by = ["..."] + group_wait = "45s" + group_interval = "6m" + repeat_interval = "3h" + contact_point = grafana_contact_point.default_policy.name + + policy { + mute_timings = local.use_mute ? [grafana_mute_timing.test[0].name] : [] + contact_point = grafana_contact_point.default_policy.name + } + } + + resource "grafana_mute_timing" "test" { + count = local.use_mute ? 1 : 0 + org_id = grafana_organization.my_org.id + name = "test-mute-timing" + intervals {} + }`, mute) + } + + resource.ParallelTest(t, resource.TestCase{ + ProtoV5ProviderFactories: testutils.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: config(true), + }, + { + Config: config(false), + }, + }, + }) +}