Repository: honeycombio/terraform-provider-honeycombio
Pull request #563 (2024-10-30 23:06:16)

feat: add support for burn alert description
Adds the ability to set and update the description on a burn alert. 

codecov-commenter: ## [Codecov](https://app.codecov.io/gh/honeycombio/terraform-provider-honeycombio/pull/563?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=honeycombio) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 76.05%. Comparing base [(`15d05ae`)](https://app.codecov.io/gh/honeycombio/terraform-provider-honeycombio/commit/15d05ae52036ab0b831d323040e1536ae0b72c3c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=honeycombio) to head [(`1c08d2b`)](https://app.codecov.io/gh/honeycombio/terraform-provider-honeycombio/commit/1c08d2b371f9607b90605e7b25c567fca05e312c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=honeycombio).
> Report is 2 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #563      +/-   ##
==========================================
+ Coverage   76.00%   76.05%   +0.04%     
==========================================
  Files          86       86              
  Lines        7093     7107      +14     
==========================================
+ Hits         5391     5405      +14     
  Misses       1368     1368              
  Partials      334      334              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/honeycombio/terraform-provider-honeycombio/pull/563?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=honeycombio).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=honeycombio).


Patch:
diff --git a/client/burn_alert.go b/client/burn_alert.go
index 80bb20f..78789af 100644
--- a/client/burn_alert.go
+++ b/client/burn_alert.go
@@ -46,6 +46,7 @@ type BurnAlert struct {
 	ExhaustionMinutes                     *int                    `json:"exhaustion_minutes,omitempty"`
 	BudgetRateWindowMinutes               *int                    `json:"budget_rate_window_minutes,omitempty"`
 	BudgetRateDecreaseThresholdPerMillion *int                    `json:"budget_rate_decrease_threshold_per_million,omitempty"`
+	Description                           string                  `json:"description,omitempty"`
 	SLO                                   SLORef                  `json:"slo"`
 	CreatedAt                             time.Time               `json:"created_at,omitempty"`
 	UpdatedAt                             time.Time               `json:"updated_at,omitempty"`
diff --git a/docs/resources/burn_alert.md b/docs/resources/burn_alert.md
index 8006f85..0321338 100644
--- a/docs/resources/burn_alert.md
+++ b/docs/resources/burn_alert.md
@@ -20,6 +20,7 @@ variable "slo_id" {
 resource "honeycombio_burn_alert" "example_alert" {
   alert_type         = "exhaustion_time"
   exhaustion_minutes = 480
+  description        = "Exhaustion burn alert description"
 
   dataset = var.dataset
   slo_id  = var.slo_id
@@ -51,6 +52,7 @@ resource "honeycombio_burn_alert" "example_alert" {
   alert_type                   = "budget_rate"
   budget_rate_window_minutes   = 480
   budget_rate_decrease_percent = 1
+  description                  =  "my example description"
 
   dataset = var.dataset
   slo_id  = var.slo_id
@@ -84,6 +86,7 @@ data "honeycombio_recipient" "pd_prod" {
 
 resource "honeycombio_burn_alert" "example_alert" {
   exhaustion_minutes = 60
+  description        = "Burn alert description"
   dataset            = var.dataset
   slo_id             = var.slo_id
 
@@ -103,6 +106,7 @@ resource "honeycombio_burn_alert" "example_alert" {
 The following arguments are supported:
 * `slo_id` - (Required) ID of the SLO this burn alert is associated with.
 * `dataset` - (Required) The dataset this burn alert is associated with.
+* `description` - (Optional) A description for this Burn Alert.
 * `alert_type` - (Optional) Type of the burn alert. Valid values are `exhaustion_time` and `budget_rate`. 
    Defaults to `exhaustion_time`.
 * `budget_rate_window_minutes` - (Optional) The time period, in minutes, over which a budget rate will be calculated. 
diff --git a/internal/models/burn_alerts.go b/internal/models/burn_alerts.go
index d208bff..d296d7d 100644
--- a/internal/models/burn_alerts.go
+++ b/internal/models/burn_alerts.go
@@ -7,6 +7,7 @@ type BurnAlertResourceModel struct {
 	AlertType                 types.String  `tfsdk:"alert_type"`
 	BudgetRateWindowMinutes   types.Int64   `tfsdk:"budget_rate_window_minutes"`
 	BudgetRateDecreasePercent types.Float64 `tfsdk:"budget_rate_decrease_percent"`
+	Description               types.String  `tfsdk:"description"`
 	Dataset                   types.String  `tfsdk:"dataset"`
 	SLOID                     types.String  `tfsdk:"slo_id"`
 	ExhaustionMinutes         types.Int64   `tfsdk:"exhaustion_minutes"`
diff --git a/internal/provider/burn_alert_resource.go b/internal/provider/burn_alert_resource.go
index 661d218..a4e0fcf 100644
--- a/internal/provider/burn_alert_resource.go
+++ b/internal/provider/burn_alert_resource.go
@@ -103,6 +103,15 @@ func (*burnAlertResource) Schema(_ context.Context, _ resource.SchemaRequest, re
 					stringplanmodifier.RequiresReplace(),
 				},
 			},
+			"description": schema.StringAttribute{
+				Description: "A description for this Burn Alert.",
+				Computed:    true,
+				Optional:    true,
+				Default:     stringdefault.StaticString(""),
+				Validators: []validator.String{
+					stringvalidator.LengthAtMost(1023),
+				},
+			},
 			"exhaustion_minutes": schema.Int64Attribute{
 				Optional:    true,
 				Description: "The amount of time, in minutes, remaining before the SLO's error budget will be exhausted and the alert will fire.",
@@ -235,9 +244,10 @@ func (r *burnAlertResource) Create(ctx context.Context, req resource.CreateReque
 
 	// Get attributes from config and construct the create request
 	createRequest := &client.BurnAlert{
-		AlertType:  client.BurnAlertAlertType(plan.AlertType.ValueString()),
-		Recipients: expandNotificationRecipients(ctx, plan.Recipients, &resp.Diagnostics),
-		SLO:        client.SLORef{ID: plan.SLOID.ValueString()},
+		AlertType:   client.BurnAlertAlertType(plan.AlertType.ValueString()),
+		Recipients:  expandNotificationRecipients(ctx, plan.Recipients, &resp.Diagnostics),
+		SLO:         client.SLORef{ID: plan.SLOID.ValueString()},
+		Description: plan.Description.ValueString(),
 	}
 
 	// Process any attributes that could be nil and add them to the create request
@@ -264,6 +274,7 @@ func (r *burnAlertResource) Create(ctx context.Context, req resource.CreateReque
 	state.ID = types.StringValue(burnAlert.ID)
 	state.AlertType = types.StringValue(string(burnAlert.AlertType))
 	state.Dataset = plan.Dataset
+	state.Description = types.StringValue(burnAlert.Description)
 	// we created them as authored so to avoid matching type-target or ID we can just use the same value
 	state.Recipients = config.Recipients
 	state.SLOID = types.StringValue(burnAlert.SLO.ID)
@@ -322,6 +333,7 @@ func (r *burnAlertResource) Read(ctx context.Context, req resource.ReadRequest,
 	state.AlertType = types.StringValue(string(burnAlert.AlertType))
 	state.SLOID = types.StringValue(burnAlert.SLO.ID)
 	state.Recipients = reconcileReadNotificationRecipientState(ctx, burnAlert.Recipients, state.Recipients, &resp.Diagnostics)
+	state.Description = types.StringValue(burnAlert.Description)
 
 	// Process any attributes that could be nil and add them to the state values
 	if burnAlert.ExhaustionMinutes != nil {
@@ -351,10 +363,11 @@ func (r *burnAlertResource) Update(ctx context.Context, req resource.UpdateReque
 
 	// Get attributes from config and construct the update request
 	updateRequest := &client.BurnAlert{
-		ID:         plan.ID.ValueString(),
-		AlertType:  client.BurnAlertAlertType(plan.AlertType.ValueString()),
-		Recipients: expandNotificationRecipients(ctx, plan.Recipients, &resp.Diagnostics),
-		SLO:        client.SLORef{ID: plan.SLOID.ValueString()},
+		ID:          plan.ID.ValueString(),
+		AlertType:   client.BurnAlertAlertType(plan.AlertType.ValueString()),
+		Recipients:  expandNotificationRecipients(ctx, plan.Recipients, &resp.Diagnostics),
+		SLO:         client.SLORef{ID: plan.SLOID.ValueString()},
+		Description: plan.Description.ValueString(),
 	}
 
 	// Process any attributes that could be nil and add them to the update request
@@ -390,6 +403,7 @@ func (r *burnAlertResource) Update(ctx context.Context, req resource.UpdateReque
 	// we created them as authored so to avoid matching type-target or ID we can just use the same value
 	state.Recipients = config.Recipients
 	state.SLOID = types.StringValue(burnAlert.SLO.ID)
+	state.Description = types.StringValue(burnAlert.Description)
 
 	// Process any attributes that could be nil and add them to the state values
 	if burnAlert.ExhaustionMinutes != nil {


Test patch:
diff --git a/client/burn_alert_test.go b/client/burn_alert_test.go
index fdc318c..a27f3e8 100644
--- a/client/burn_alert_test.go
+++ b/client/burn_alert_test.go
@@ -55,6 +55,7 @@ func TestBurnAlerts(t *testing.T) {
 	var defaultBurnAlert *client.BurnAlert
 	exhaustionMinutes24Hours := 24 * 60
 	defaultBurnAlertCreateRequest := client.BurnAlert{
+		Description:       "default burn alert",
 		ExhaustionMinutes: &exhaustionMinutes24Hours,
 		SLO:               client.SLORef{ID: slo.ID},
 		Recipients: []client.NotificationRecipient{
@@ -67,6 +68,7 @@ func TestBurnAlerts(t *testing.T) {
 	exhaustionMinutes1Hour := 60
 	defaultBurnAlertUpdateRequest := client.BurnAlert{
 		ExhaustionMinutes: &exhaustionMinutes1Hour,
+		Description:       "updated default burn alert",
 		SLO:               client.SLORef{ID: slo.ID},
 		Recipients: []client.NotificationRecipient{
 			{
@@ -80,6 +82,7 @@ func TestBurnAlerts(t *testing.T) {
 	exhaustionMinutes0Minutes := 0
 	exhaustionTimeBurnAlertCreateRequest := client.BurnAlert{
 		AlertType:         client.BurnAlertAlertTypeExhaustionTime,
+		Description:       "exhaustion time burn alert",
 		ExhaustionMinutes: &exhaustionMinutes0Minutes,
 		SLO:               client.SLORef{ID: slo.ID},
 		Recipients: []client.NotificationRecipient{
@@ -92,6 +95,7 @@ func TestBurnAlerts(t *testing.T) {
 	exhaustionMinutes4Hours := 4 * 60
 	exhaustionTimeBurnAlertUpdateRequest := client.BurnAlert{
 		AlertType:         client.BurnAlertAlertTypeExhaustionTime,
+		Description:       "updated exhaustion time burn alert",
 		ExhaustionMinutes: &exhaustionMinutes4Hours,
 		SLO:               client.SLORef{ID: slo.ID},
 		Recipients: []client.NotificationRecipient{
@@ -107,6 +111,7 @@ func TestBurnAlerts(t *testing.T) {
 	budgetRateDecreaseThresholdPerMillion1Percent := 10000
 	budgetRateBurnAlertCreateRequest := client.BurnAlert{
 		AlertType:                             client.BurnAlertAlertTypeBudgetRate,
+		Description:                           "budget rate burn alert",
 		BudgetRateWindowMinutes:               &budgetRateWindowMinutes1Hour,
 		BudgetRateDecreaseThresholdPerMillion: &budgetRateDecreaseThresholdPerMillion1Percent,
 		SLO:                                   client.SLORef{ID: slo.ID},
@@ -121,6 +126,7 @@ func TestBurnAlerts(t *testing.T) {
 	budgetRateDecreaseThresholdPerMillion5Percent := 10000
 	budgetRateBurnAlertUpdateRequest := client.BurnAlert{
 		AlertType:                             client.BurnAlertAlertTypeBudgetRate,
+		Description:                           "updated budget rate burn alert",
 		BudgetRateWindowMinutes:               &budgetRateWindowMinutes2Hours,
 		BudgetRateDecreaseThresholdPerMillion: &budgetRateDecreaseThresholdPerMillion5Percent,
 		SLO:                                   client.SLORef{ID: slo.ID},
@@ -134,6 +140,7 @@ func TestBurnAlerts(t *testing.T) {
 
 	testCases := map[string]struct {
 		alertType     client.BurnAlertAlertType
+		Description   string
 		createRequest client.BurnAlert
 		updateRequest client.BurnAlert
 		burnAlert     *client.BurnAlert
@@ -170,6 +177,7 @@ func TestBurnAlerts(t *testing.T) {
 			assert.NotNil(t, burnAlert.CreatedAt, "created at is empty")
 			assert.NotNil(t, burnAlert.UpdatedAt, "updated at is empty")
 			assert.Equal(t, testCase.alertType, burnAlert.AlertType)
+			assert.Equal(t, testCase.createRequest.Description, burnAlert.Description)
 
 			// copy dynamic fields before asserting equality
 			data.AlertType = burnAlert.AlertType
diff --git a/internal/provider/burn_alert_resource_test.go b/internal/provider/burn_alert_resource_test.go
index e0326e6..3a6db48 100644
--- a/internal/provider/burn_alert_resource_test.go
+++ b/internal/provider/burn_alert_resource_test.go
@@ -19,6 +19,8 @@ import (
 	"github.com/honeycombio/terraform-provider-honeycombio/client"
 )
 
+const testBADescription = "burn alert description"
+
 func TestAcc_BurnAlertResource_defaultBasic(t *testing.T) {
 	dataset, sloID := burnAlertAccTestSetup(t)
 	burnAlert := &client.BurnAlert{}
@@ -213,7 +215,7 @@ func TestAcc_BurnAlertResourceUpgradeFromVersion015(t *testing.T) {
 	dataset, sloID := burnAlertAccTestSetup(t)
 	burnAlert := &client.BurnAlert{}
 
-	config := testAccConfigBurnAlertDefault_basic(60, dataset, sloID, "info")
+	config := testAccConfigBurnAlert_withoutDescription(60, dataset, sloID, "info")
 
 	resource.Test(t, resource.TestCase{
 		Steps: []resource.TestStep{
@@ -491,11 +493,13 @@ func testAccEnsureSuccessExhaustionTimeAlert(t *testing.T, burnAlert *client.Bur
 
 		// Check that the burn alert has the correct values in state
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "slo_id", sloID),
+		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "description", testBADescription),
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "alert_type", "exhaustion_time"),
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "exhaustion_minutes", fmt.Sprintf("%d", exhaustionMinutes)),
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "recipient.#", "1"),
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "recipient.0.notification_details.#", "1"),
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "recipient.0.notification_details.0.pagerduty_severity", pagerdutySeverity),
+
 		// Budget rate attributes should not be set
 		resource.TestCheckNoResourceAttr("honeycombio_burn_alert.test", "budget_rate_window_minutes"),
 		resource.TestCheckNoResourceAttr("honeycombio_burn_alert.test", "budget_rate_decrease_percent"),
@@ -513,6 +517,7 @@ func testAccEnsureSuccessBudgetRateAlert(t *testing.T, burnAlert *client.BurnAle
 
 		// Check that the burn alert has the correct values in state
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "slo_id", sloID),
+		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "description", testBADescription),
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "alert_type", "budget_rate"),
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "budget_rate_window_minutes", fmt.Sprintf("%d", budgetRateWindowMinutes)),
 		resource.TestCheckResourceAttr("honeycombio_burn_alert.test", "budget_rate_decrease_percent", helper.FloatToPercentString(budgetRateDecreasePercent)),
@@ -650,7 +655,7 @@ func burnAlertAccTestSetup(t *testing.T) (string, string) {
 	return dataset, slo.ID
 }
 
-func testAccConfigBurnAlertDefault_basic(exhaustionMinutes int, dataset, sloID, pdseverity string) string {
+func testAccConfigBurnAlert_withoutDescription(exhaustionMinutes int, dataset, sloID, pdseverity string) string {
 	return fmt.Sprintf(`
 resource "honeycombio_pagerduty_recipient" "test" {
   integration_key  = "08b9d4cacd68933151a1ef1028b67da2"
@@ -662,7 +667,6 @@ resource "honeycombio_burn_alert" "test" {
 
   dataset            = "%[2]s"
   slo_id             = "%[3]s"
-
   recipient {
     id = honeycombio_pagerduty_recipient.test.id
 
@@ -673,6 +677,30 @@ resource "honeycombio_burn_alert" "test" {
 }`, exhaustionMinutes, dataset, sloID, pdseverity)
 }
 
+func testAccConfigBurnAlertDefault_basic(exhaustionMinutes int, dataset, sloID, pdseverity string) string {
+	return fmt.Sprintf(`
+resource "honeycombio_pagerduty_recipient" "test" {
+  integration_key  = "08b9d4cacd68933151a1ef1028b67da2"
+  integration_name = "test.pd-basic"
+}
+
+resource "honeycombio_burn_alert" "test" {
+  exhaustion_minutes = %[1]d
+
+  dataset            = "%[2]s"
+  slo_id             = "%[3]s"
+  description        = "%[5]s"
+  
+  recipient {
+    id = honeycombio_pagerduty_recipient.test.id
+
+    notification_details {
+      pagerduty_severity = "%[4]s"
+    }
+  }
+}`, exhaustionMinutes, dataset, sloID, pdseverity, testBADescription)
+}
+
 func testAccConfigBurnAlertDefault_validateAttributesWhenAlertTypeIsExhaustionTime(dataset, sloID string) string {
 	return fmt.Sprintf(`
 resource "honeycombio_burn_alert" "test" {
@@ -698,6 +726,7 @@ resource "honeycombio_pagerduty_recipient" "test" {
 
 resource "honeycombio_burn_alert" "test" {
   alert_type         = "exhaustion_time"
+  description        = "%[5]s"
   exhaustion_minutes = %[1]d
 
   dataset = "%[2]s"
@@ -710,7 +739,7 @@ resource "honeycombio_burn_alert" "test" {
       pagerduty_severity = "%[4]s"
     }
   }
-}`, exhaustionMinutes, dataset, sloID, pdseverity)
+}`, exhaustionMinutes, dataset, sloID, pdseverity, testBADescription)
 }
 
 func testAccConfigBurnAlertExhaustionTime_validateAttributesWhenAlertTypeIsExhaustionTime(dataset, sloID string) string {
@@ -739,6 +768,7 @@ resource "honeycombio_pagerduty_recipient" "test" {
 
 resource "honeycombio_burn_alert" "test" {
   alert_type                   = "budget_rate"
+  description                  = "%[6]s"
   budget_rate_window_minutes   = %[1]d
   budget_rate_decrease_percent = %[2]s
 
@@ -752,7 +782,7 @@ resource "honeycombio_burn_alert" "test" {
       pagerduty_severity = "%[5]s"
     }
   }
-}`, budgetRateWindowMinutes, helper.FloatToPercentString(budgetRateDecreasePercent), dataset, sloID, pdseverity)
+}`, budgetRateWindowMinutes, helper.FloatToPercentString(budgetRateDecreasePercent), dataset, sloID, pdseverity, testBADescription)
 }
 
 func testAccConfigBurnAlertBudgetRate_trailingZeros(dataset, sloID string) string {
@@ -764,6 +794,7 @@ resource "honeycombio_pagerduty_recipient" "test" {
 
 resource "honeycombio_burn_alert" "test" {
   alert_type                   = "budget_rate"
+  description				   = "%[3]s"
   budget_rate_window_minutes   = 60
   budget_rate_decrease_percent = 5.00000
 
@@ -777,7 +808,7 @@ resource "honeycombio_burn_alert" "test" {
       pagerduty_severity = "info"
     }
   }
-}`, dataset, sloID)
+}`, dataset, sloID, testBADescription)
 }
 
 func testAccConfigBurnAlertBudgetRate_validateAttributesWhenAlertTypeIsBudgetRate(dataset, sloID string) string {
@@ -813,6 +844,7 @@ resource "honeycombio_burn_alert" "test" {
 
   dataset = "%[1]s"
   slo_id  = "%[2]s"
+  description = "%[3]s"
 
   recipient {
     id = honeycombio_pagerduty_recipient.test.id
@@ -821,7 +853,7 @@ resource "honeycombio_burn_alert" "test" {
       pagerduty_severity = "info"
     }
   }
-}`, dataset, sloID)
+}`, dataset, sloID, testBADescription)
 }
 
 func testAccConfigBurnAlertWithSlackRecipient(dataset, sloID, channel string) string {
@@ -831,12 +863,13 @@ resource "honeycombio_burn_alert" "test" {
 
   dataset = "%[1]s"
   slo_id  = "%[2]s"
+  description = "%[4]s"
 
   recipient {
     type   = "slack"
     target = "%[3]s"
   }
-}`, dataset, sloID, channel)
+}`, dataset, sloID, channel, testBADescription)
 }
 
 func testAccConfigBurnAlertWithDynamicRecipient(dataset, sloID string) string {