Repository: honeycombio/terraform-provider-honeycombio (language: python)

Issue:
Terraform is unable to apply trigger with the change in recipients with different types
**Versions**
0.8.0

**Steps to reproduce**

1. Start with
```hcl
data "honeycombio_query_specification" "example" {
  calculation {
    op = "COUNT"
  }

  filter {
    column = "trace.parent_id"
    op     = "does-not-exist"
  }
}

resource "honeycombio_query" "example" {
  dataset    = local.dataset
  query_json = data.honeycombio_query_specification.example.json
}

data "honeycombio_recipient" "example" {
  type    = "slack"

  detail_filter {
    name  = "channel"
    value = "#alex-test"
  }
}

data "honeycombio_recipient" "example_slack" {
  type    = "slack"

  detail_filter {
    name  = "channel"
    value = "#test_channel"
  }
}

data "honeycombio_recipient" "example_pd" {
  type    = "pagerduty"

  detail_filter {
    name  = "integration_name"
    value = "Alex Test1"
  }
}

resource "honeycombio_trigger" "example" {
  name        = "Alex test"
  description = "Alex test"

  query_id = honeycombio_query.example.id
  dataset  = local.dataset

  frequency = 1800

  threshold {
    op    = ">"
    value = 1000000000
  }

  recipient {
    id = data.honeycombio_recipient.example.id
  }

  recipient {
    id = data.honeycombio_recipient.example_slack.id
  }

  recipient {
    id = data.honeycombio_recipient.example_pd.id

    notification_details {
      pagerduty_severity = "critical"
    }
  }
}
```

```
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
```

2. Comment out second recipient and apply:

```hcl
  # recipient {
  #   id = data.honeycombio_recipient.example_slack.id
  # }
```

```
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
```

3. Run apply again:

We would expect to have 0 changes but... 🐛 

```
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
```

4. Uncomment the previously commented block and run apply again 💣 

```hcl
honeycombio_trigger.example: Modifying... [id=pVVZZxandMW]
╷
│ Error: 400 Bad Request: PagerDuty target not found
│ 
│   with honeycombio_trigger.example,
│   on test.tf line 139, in resource "honeycombio_trigger" "example":
│  139: resource "honeycombio_trigger" "example" {
│ 
```

**Additional context**



Discussion / hints:
0.7.0 is also broken actually but in a slightly different way. Please let me know if I need to raise a separate issue for this.

1. Let's start with this:

```hcl
data "honeycombio_query_specification" "example" {
  calculation {
    op = "COUNT"
  }

  filter {
    column = "trace.parent_id"
    op     = "does-not-exist"
  }
}

resource "honeycombio_query" "example" {
  dataset    = local.dataset
  query_json = data.honeycombio_query_specification.example.json
}

resource "honeycombio_trigger" "example" {
  name        = "Alex test"
  description = "Alex test"

  query_id = honeycombio_query.example.id
  dataset  = local.dataset

  frequency = 1800

  threshold {
    op    = ">"
    value = 1000000000
  }

  recipient {
    type   = "slack"
    target = "#alex-test"
  }

  recipient {
    type   = "slack"
    target = "#test_channel"
  }

  recipient {
    id = "hgvpnCY1vwY"
  }
}
```

```
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
```

2. Comment second recipient and run apply

```hcl
  # recipient {
  #   type   = "slack"
  #   target = "#test_channel"
  # }
```

```
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
```

3. Apply again

We would expect to have 0 changes but... 🐛

```
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
```

4. Uncomment and apply

```hcl
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
```

And you can do this forever you will never get 0 changes 🤷 

Fix patch:
diff --git a/docs/resources/burn_alert.md b/docs/resources/burn_alert.md
index 194de8a8..ca787d0b 100644
--- a/docs/resources/burn_alert.md
+++ b/docs/resources/burn_alert.md
@@ -82,7 +82,7 @@ Each burn alert configuration may have one or more `recipient` blocks, which eac
 * `type` - (Optional) The type of the recipient, allowed types are `email`, `pagerduty`, `slack` and `webhook`. Should not be used in combination with `id`.
 * `target` - (Optional) Target of the recipient, this has another meaning depending on the type of recipient (see the table below). Should not be used in combination with `id`.
 * `id` - (Optional) The ID of an already existing recipient. Should not be used in combination with `type` and `target`.
-* `notification_details` - (Optional) a block of additional details to send along with the notification. The only supported option currently is `pagerduty_severity` which can be set to one of `info`, `warning`, `error`, or `critical` and must be used in combination with a PagerDuty recipient.
+* `notification_details` - (Optional) a block of additional details to send along with the notification. The only supported option currently is `pagerduty_severity` which has a default value of `critical` but can be set to one of `info`, `warning`, `error`, or `critical` and must be used in combination with a PagerDuty recipient.
 
 Type      | Target
 ----------|-------------------------
diff --git a/docs/resources/trigger.md b/docs/resources/trigger.md
index d6b5ae78..9970a381 100644
--- a/docs/resources/trigger.md
+++ b/docs/resources/trigger.md
@@ -139,7 +139,7 @@ Each trigger configuration may have zero or more `recipient` blocks, which each
 * `type` - (Optional) The type of the trigger recipient, allowed types are `email`, `marker`, `pagerduty`, `slack` and `webhook`. Should not be used in combination with `id`.
 * `target` - (Optional) Target of the trigger recipient, this has another meaning depending on the type of recipient (see the table below). Should not be used in combination with `id`.
 * `id` - (Optional) The ID of an already existing recipient. Should not be used in combination with `type` and `target`.
-* `notification_details` - (Optional) a block of additional details to send along with the notification. The only supported option currently is `pagerduty_severity` which can be set to one of `info`, `warning`, `error`, or `critical` and must be used in combination with a PagerDuty recipient.
+* `notification_details` - (Optional) a block of additional details to send along with the notification. The only supported option currently is `pagerduty_severity` which has a default value of `critical` but can be set to one of `info`, `warning`, `error`, or `critical` and must be used in combination with a PagerDuty recipient.
 
 Type      | Target
 ----------|-------------------------
diff --git a/honeycombio/resource_burn_alert.go b/honeycombio/resource_burn_alert.go
index 9e434275..02876954 100644
--- a/honeycombio/resource_burn_alert.go
+++ b/honeycombio/resource_burn_alert.go
@@ -72,6 +72,9 @@ func newBurnAlert() *schema.Resource {
 							Optional: true,
 							MinItems: 1,
 							MaxItems: 1,
+							// value may be set to defaults for a given type
+							//  e.g. PagerDuty type recipients have a `pagerduty_severity` of `critical`
+							Computed: true,
 							Elem: &schema.Resource{
 								Schema: map[string]*schema.Schema{
 									"pagerduty_severity": {
diff --git a/honeycombio/resource_trigger.go b/honeycombio/resource_trigger.go
index 1c9877af..38268394 100644
--- a/honeycombio/resource_trigger.go
+++ b/honeycombio/resource_trigger.go
@@ -104,6 +104,9 @@ func newTrigger() *schema.Resource {
 						"notification_details": {
 							Type:     schema.TypeList,
 							Optional: true,
+							// value may be set to defaults for a given type
+							//  e.g. PagerDuty type recipients have a `pagerduty_severity` of `critical`
+							Computed: true,
 							MinItems: 1,
 							MaxItems: 1,
 							Elem: &schema.Resource{
diff --git a/honeycombio/type_helpers.go b/honeycombio/type_helpers.go
index 22885b0c..f318cf88 100644
--- a/honeycombio/type_helpers.go
+++ b/honeycombio/type_helpers.go
@@ -159,7 +159,7 @@ func flattenNotificationRecipients(rs []honeycombio.NotificationRecipient) []map
 	result := make([]map[string]interface{}, len(rs))
 
 	for i, r := range rs {
-		result[i] = map[string]interface{}{
+		rcpt := map[string]interface{}{
 			"id":     r.ID,
 			"type":   string(r.Type),
 			"target": r.Target,
@@ -171,8 +171,9 @@ func flattenNotificationRecipients(rs []honeycombio.NotificationRecipient) []map
 			if r.Details.PDSeverity != "" {
 				details[0]["pagerduty_severity"] = string(r.Details.PDSeverity)
 			}
-			result[i]["notification_details"] = details
+			rcpt["notification_details"] = details
 		}
+		result[i] = rcpt
 	}
 
 	return result
@@ -184,7 +185,7 @@ func expandNotificationRecipients(s []interface{}) []honeycombio.NotificationRec
 	for i, r := range s {
 		rMap := r.(map[string]interface{})
 
-		recipients[i] = honeycombio.NotificationRecipient{
+		rcpt := honeycombio.NotificationRecipient{
 			ID:     rMap["id"].(string),
 			Type:   honeycombio.RecipientType(rMap["type"].(string)),
 			Target: rMap["target"].(string),
@@ -193,11 +194,12 @@ func expandNotificationRecipients(s []interface{}) []honeycombio.NotificationRec
 			// notification details have been provided
 			details := v[0].(map[string]interface{})
 			if s, ok := details["pagerduty_severity"]; ok {
-				recipients[i].Details = &honeycombio.NotificationRecipientDetails{
+				rcpt.Details = &honeycombio.NotificationRecipientDetails{
 					PDSeverity: honeycombio.PagerDutySeverity(s.(string)),
 				}
 			}
 		}
+		recipients[i] = rcpt
 	}
 
 	return recipients
@@ -209,7 +211,7 @@ func expandNotificationRecipients(s []interface{}) []honeycombio.NotificationRec
 // This cannot currently be handled efficiently by a DiffSuppressFunc.
 // See: https://github.com/hashicorp/terraform-plugin-sdk/issues/477
 func matchNotificationRecipientsWithSchema(readRecipients []honeycombio.NotificationRecipient, declaredRecipients []interface{}) []honeycombio.NotificationRecipient {
-	result := make([]honeycombio.NotificationRecipient, len(declaredRecipients))
+	result := make([]honeycombio.NotificationRecipient, 0)
 
 	rMap := make(map[string]honeycombio.NotificationRecipient, len(readRecipients))
 	for _, recipient := range readRecipients {
@@ -224,20 +226,20 @@ func matchNotificationRecipientsWithSchema(readRecipients []honeycombio.Notifica
 	// put it in it's place. Otherwise, try to match it to a readRecipient with
 	// the same type and target. If we can't find it at all, it must be new, so
 	// put it at the end.
-	for i, declaredRcpt := range declaredRecipients {
+	for _, declaredRcpt := range declaredRecipients {
 		declaredRcpt := declaredRcpt.(map[string]interface{})
 
 		if declaredRcpt["id"] != "" {
 			if v, ok := rMap[declaredRcpt["id"].(string)]; ok {
 				// matched recipient declared by ID
-				result[i] = v
+				result = append(result, v)
 				delete(rMap, v.ID)
 			}
 		} else {
 			// group result recipients by type
 			for key, rcpt := range rMap {
 				if string(rcpt.Type) == declaredRcpt["type"] && rcpt.Target == declaredRcpt["target"] {
-					result[i] = rcpt
+					result = append(result, rcpt)
 					delete(rMap, key)
 					break
 				}


Test patch:
diff --git a/honeycombio/resource_burn_alert_test.go b/honeycombio/resource_burn_alert_test.go
index 50c94c52..0372826c 100644
--- a/honeycombio/resource_burn_alert_test.go
+++ b/honeycombio/resource_burn_alert_test.go
@@ -135,10 +135,7 @@ resource "honeycombio_burn_alert" "test" {
 
   recipient {
     id = honeycombio_pagerduty_recipient.test.id
-
-    notification_details {
-      pagerduty_severity = "critical"
-    }
+    // default severity is critical
   }
 }`, dataset, slo.ID),
 				Check: resource.ComposeTestCheckFunc(
diff --git a/honeycombio/resource_trigger_test.go b/honeycombio/resource_trigger_test.go
index 4bafd0c0..69816053 100644
--- a/honeycombio/resource_trigger_test.go
+++ b/honeycombio/resource_trigger_test.go
@@ -111,6 +111,56 @@ func TestAccHoneycombioTrigger_triggerRecipientById(t *testing.T) {
 	})
 
 	// test PD Recipient with Severity
+	resource.Test(t, resource.TestCase{
+		PreCheck:          testAccPreCheck(t),
+		ProviderFactories: testAccProviderFactories,
+		Steps: []resource.TestStep{
+			{
+				Config: fmt.Sprintf(`
+		data "honeycombio_query_specification" "test" {
+		  calculation {
+		    op     = "AVG"
+		    column = "duration_ms"
+		  }
+		  time_range = 1800
+		}
+
+		resource "honeycombio_query" "test" {
+		  dataset    = "%s"
+		    query_json = data.honeycombio_query_specification.test.json
+		  }
+
+		resource "honeycombio_pagerduty_recipient" "test" {
+		  integration_key  = "09c9d4cacd68933151a1ef1048b67dd5"
+		  integration_name = "acctest"
+		}
+
+		resource "honeycombio_trigger" "test" {
+		  name    = "Test trigger with PD Severity Recipient"
+		  dataset = "%s"
+
+		  query_id = honeycombio_query.test.id
+
+		  alert_type = "on_change"
+
+		  threshold {
+		    op    = ">"
+		    value = 100
+		  }
+
+		  recipient {
+		    id = honeycombio_pagerduty_recipient.test.id
+
+		    notification_details {
+		      pagerduty_severity = "info"
+		    }
+		  }
+		}`, dataset, dataset),
+			},
+		},
+	})
+
+	// test PD Recipient with no specified severity
 	resource.Test(t, resource.TestCase{
 		PreCheck:          testAccPreCheck(t),
 		ProviderFactories: testAccProviderFactories,
@@ -136,13 +186,11 @@ resource "honeycombio_pagerduty_recipient" "test" {
 }
 
 resource "honeycombio_trigger" "test" {
-  name    = "Test trigger with PD Severity Recipient"
+  name    = "Test trigger with PD default Severity"
   dataset = "%s"
 
   query_id = honeycombio_query.test.id
 
-  alert_type = "on_change"
-
   threshold {
     op    = ">"
     value = 100
@@ -150,10 +198,7 @@ resource "honeycombio_trigger" "test" {
 
   recipient {
     id = honeycombio_pagerduty_recipient.test.id
-
-    notification_details {
-      pagerduty_severity = "info"
-    }
+    // default severity is critical
   }
 }`, dataset, dataset),
 			},