Skip to content

Commit

Permalink
Add support for 'msteams' recipients (#386)
Browse files Browse the repository at this point in the history
Adds supports for `msteams` recipients.

Also fixes a "sneaky bug" where a previous refactor would allow `marker`
type recipients on Burn Alerts during the validation stage (the API
still would reject them).
  • Loading branch information
jharley authored Nov 7, 2023
1 parent bd9eef5 commit 04ffa24
Show file tree
Hide file tree
Showing 17 changed files with 198 additions and 45 deletions.
25 changes: 12 additions & 13 deletions client/recipient.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ type RecipientDetails struct {
PDIntegrationName string `json:"pagerduty_integration_name,omitempty"`
// slack
SlackChannel string `json:"slack_channel,omitempty"`
// webhook
WebhookName string `json:"webhook_name,omitempty"`
WebhookURL string `json:"webhook_url,omitempty"`
// webhook or msteams
WebhookName string `json:"webhook_name,omitempty"`
WebhookURL string `json:"webhook_url,omitempty"`
// webhook only
WebhookSecret string `json:"webhook_secret,omitempty"`
}

Expand All @@ -81,6 +82,7 @@ const (
RecipientTypeSlack RecipientType = "slack"
RecipientTypeWebhook RecipientType = "webhook"
RecipientTypeMarker RecipientType = "marker"
RecipientTypeMSTeams RecipientType = "msteams"
)

// PagerDutySeverity holds all the possible PD Severity types
Expand All @@ -94,24 +96,21 @@ const (
PDDefaultSeverity = PDSeverityCRITICAL
)

// TriggerRecipientTypes returns a list of recipient types compatible with Triggers
// TriggerRecipientTypes returns a list of recipient types compatible with Triggers.
// Triggers are a special case as 'Marker' recipients are supported in addition to
// usual types.
func TriggerRecipientTypes() []RecipientType {
return []RecipientType{
RecipientTypeEmail,
RecipientTypePagerDuty,
RecipientTypeSlack,
RecipientTypeWebhook,
RecipientTypeMarker,
}
return append(RecipientTypes(), RecipientTypeMarker)
}

// BurnAlertRecipientTypes returns a list of recipient types compatible with Burn Alerts
func BurnAlertRecipientTypes() []RecipientType {
// RecipientTypes returns all supported Recipient types
func RecipientTypes() []RecipientType {
return []RecipientType{
RecipientTypeEmail,
RecipientTypePagerDuty,
RecipientTypeSlack,
RecipientTypeWebhook,
RecipientTypeMSTeams,
}
}

Expand Down
39 changes: 39 additions & 0 deletions client/recipient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,42 @@ func TestRecipientsEmail(t *testing.T) {
assert.True(t, de.IsNotFound())
})
}

func TestRecipientsWebhooksandMSTeams(t *testing.T) {
ctx := context.Background()
c := newTestClient(t)

testRcpts := []Recipient{
{
Type: RecipientTypeWebhook,
Details: RecipientDetails{
WebhookName: "test webhook",
WebhookURL: "https://example.com",
WebhookSecret: "secret",
},
},
{
Type: RecipientTypeMSTeams,
Details: RecipientDetails{
WebhookName: "test channel",
WebhookURL: "https://corp.office.com/webhook",
},
},
}

for _, tr := range testRcpts {
r, err := c.Recipients.Create(ctx, &tr)
require.NoError(t, err)
t.Cleanup(func() {
_ = c.Recipients.Delete(ctx, r.ID)
})

r, err = c.Recipients.Get(ctx, r.ID)
require.NoError(t, err)

assert.Equal(t, tr.Type, r.Type)
assert.Equal(t, tr.Details.WebhookName, r.Details.WebhookName)
assert.Equal(t, tr.Details.WebhookURL, r.Details.WebhookURL)
assert.Equal(t, tr.Details.WebhookSecret, r.Details.WebhookSecret)
}
}
7 changes: 4 additions & 3 deletions docs/data-sources/recipient.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ resource "honeycombio_trigger" "example" {

The following arguments are supported:

* `type` - (Required) The type of recipient, allowed types are `email`, `pagerduty`, `slack` and `webhook`.
* `type` - (Required) The type of recipient, allowed types are `email`, `pagerduty`, `msteams`, `slack` and `webhook`.
* `dataset` - (Optional) Deprecated: recipients are now a Team-level construct. Any provided value will be ignored.
* `detail_filter` - (Optional) a block to further filter recipients as described below.
* `target` - (Optional) Deprecated: use `detail_filter` instead. The target of the recipient, this has another meaning depending on the type of recipient (see the table below).
Expand All @@ -63,6 +63,7 @@ Type | Target
----------|-------------------------
email | an email address
marker | name of the marker
msteams | name of the integration
pagerduty | _N/A_
slack | name of the channel
webhook | name of the webhook
Expand All @@ -82,8 +83,8 @@ In addition to all arguments above, the following attributes are exported:
* `id` - ID of the recipient.
* `address` - The email recipient's address -- if of type `email`.
* `channel` - The Slack recipient's channel -- if of type `slack`.
* `name` - The webhook recipient's name -- if of type `webhook`.
* `name` - The webhook recipient's name -- if of type `webhook` or `msteams`.
* `secret` - (Sensitive) The webhook recipient's secret -- if of type `webhook`.
* `url` - The webhook recipient's URL - if of type `webhook`.
* `url` - The webhook recipient's URL - if of type `webhook` or `msteams`.
* `integration_key` - (Sensitive) The PagerDuty recipient's integration key -- if of type `pagerduty`.
* `integration_name` - The PagerDuty recipient's inregration name -- if of type `pagerduty`.
2 changes: 1 addition & 1 deletion docs/data-sources/recipients.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ data "honeycombio_recipients" "example-dot-com" {

The following arguments are supported:

* `type` - (Optional) The type of recipient, allowed types are `email`, `pagerduty`, `slack` and `webhook`.
* `type` - (Optional) The type of recipient, allowed types are `email`, `pagerduty`, `msteams`, `slack` and `webhook`.
* `detail_filter` - (Optional) a block to further filter recipients as described below. `name` must be set when providing a filter.

To further filter the recipient results, a `detail_filter` block can be provided which accepts the following arguments:
Expand Down
2 changes: 1 addition & 1 deletion docs/resources/burn_alert.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ The following arguments are supported:

Each burn alert configuration may have one or more `recipient` blocks, which each accept the following arguments. A recipient block can either refer to an existing recipient (a recipient that is already present in another burn alert or trigger) or a new recipient. When specifying an existing recipient, only `id` may be set. If you pass in a recipient without its ID and only include the type and target, Honeycomb will make a best effort to match to an existing recipient. To retrieve the ID of an existing recipient, refer to the [`honeycombio_recipient`](../data-sources/recipient.md) data source.

* `type` - (Optional) The type of the recipient, allowed types are `email`, `pagerduty`, `slack` and `webhook`. Should not be used in combination with `id`.
* `type` - (Optional) The type of the recipient, allowed types are `email`, `pagerduty`, `msteams`, `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 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.
Expand Down
33 changes: 33 additions & 0 deletions docs/resources/msteams_recipient.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Resource: honeycombio_msteams_recipient

`honeycombio_msteams_recipient` allows you to define and manage an MSTeams recipient that can be used by Triggers or BurnAlerts notifications.

## Example Usage

```hcl
resource "honeycombio_msteams_recipient" "prod" {
name = "Production Alerts"
url = "https://mycorp.webhook.office.com/webhookb2/abcd12345"
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) The name of the MS Teams Integration to create.
* `url` - (Required) The Incoming Webhook URL to send the notification to.

## Attribute Reference

In addition to all arguments above, the following attributes are exported:

* `id` - The ID of the recipient.

## Import

MSTeams Recipients can be imported by their ID, e.g.

```
$ terraform import honeycombio_msteams_recipient.my_recipient nx2zsefB1cX
```
2 changes: 1 addition & 1 deletion docs/resources/trigger.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Each trigger configuration may provide an `evaluation_schedule` block, which acc

Each trigger configuration may have zero or more `recipient` blocks, which each accept the following arguments. A trigger recipient block can either refer to an existing recipient (a recipient that is already present in another trigger) or a new recipient. When specifying an existing recipient, only `id` may be set. If you pass in a recipient without its ID and only include the type and target, Honeycomb will make a best effort to match to an existing recipient. To retrieve the ID of an existing recipient, refer to the [`honeycombio_recipient`](../data-sources/recipient.md) data source.

* `type` - (Optional) The type of the trigger recipient, allowed types are `email`, `marker`, `pagerduty`, `slack` and `webhook`.
* `type` - (Optional) The type of the trigger recipient, allowed types are `email`, `marker`, `msteams`, `pagerduty`, `slack` and `webhook`.
Cannot 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).
Cannot not be used in combination with `id`.
Expand Down
18 changes: 9 additions & 9 deletions honeycombio/data_source_recipient.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
honeycombio "github.com/honeycombio/terraform-provider-honeycombio/client"
"github.com/honeycombio/terraform-provider-honeycombio/internal/helper"
)

func dataSourceHoneycombioRecipient() *schema.Resource {
Expand All @@ -33,8 +34,8 @@ If you want to match multiple recipients, use the 'honeycombio_recipients' data
"type": {
Type: schema.TypeString,
Required: true,
Description: "The type of recipient, allowed types are `email`, `pagerduty`, `slack` and `webhook`.",
ValidateFunc: validation.StringInSlice([]string{"email", "pagerduty", "slack", "webhook"}, false),
Description: "The type of recipient.",
ValidateFunc: validation.StringInSlice(helper.AsStringSlice(honeycombio.RecipientTypes()), false),
},
"target": {
Type: schema.TypeString,
Expand Down Expand Up @@ -95,7 +96,7 @@ If you want to match multiple recipients, use the 'honeycombio_recipients' data
Computed: true,
Required: false,
Optional: false,
Description: "The webhook recipient's name -- if of type `webhook`",
Description: "The webhook recipient's name -- if of type `webhook` or `msteams`",
},
"secret": {
Type: schema.TypeString,
Expand All @@ -110,7 +111,7 @@ If you want to match multiple recipients, use the 'honeycombio_recipients' data
Computed: true,
Required: false,
Optional: false,
Description: "The webhook recipient's URL -- if of type `webhook`",
Description: "The webhook recipient's URL -- if of type `webhook` or `msteams`",
},
"integration_key": {
Type: schema.TypeString,
Expand Down Expand Up @@ -143,14 +144,10 @@ func dataSourceHoneycombioRecipientRead(ctx context.Context, d *schema.ResourceD
rcptFilter := &recipientFilter{Type: matchType}
if v, ok := d.GetOk("target"); ok {
// deprecated argument to be removed in future
target := v.(string)
rcptFilter.Value = &target
rcptFilter = &recipientFilter{Value: honeycombio.ToPtr(v.(string))}
}
if v, ok := d.GetOk("detail_filter"); ok {
rcptFilter = expandRecipientFilter(v.([]interface{}))
if rcptFilter.Type != matchType {
return diag.Errorf("provided type doesn't match filter type")
}
}

var filteredRcpts []honeycombio.Recipient
Expand All @@ -174,6 +171,9 @@ func dataSourceHoneycombioRecipientRead(ctx context.Context, d *schema.ResourceD
d.Set("address", rcpt.Details.EmailAddress)
case honeycombio.RecipientTypeSlack:
d.Set("channel", rcpt.Details.SlackChannel)
case honeycombio.RecipientTypeMSTeams:
d.Set("name", rcpt.Details.WebhookName)
d.Set("url", rcpt.Details.WebhookURL)
case honeycombio.RecipientTypeWebhook:
d.Set("name", rcpt.Details.WebhookName)
d.Set("secret", rcpt.Details.WebhookSecret)
Expand Down
14 changes: 14 additions & 0 deletions honeycombio/data_source_recipient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ func TestAccDataSourceHoneycombioRecipient_basic(t *testing.T) {
WebhookURL: "https://my.webhook.dev.corp.io",
},
},
{
Type: honeycombio.RecipientTypeMSTeams,
Details: honeycombio.RecipientDetails{
WebhookName: "My Teams Channel",
WebhookURL: "https://outlook.office.com/webhook/12345",
},
},
}

for i, r := range testRecipients {
Expand Down Expand Up @@ -117,6 +124,13 @@ func TestAccDataSourceHoneycombioRecipient_basic(t *testing.T) {
resource.TestCheckResourceAttr("data.honeycombio_recipient.test", "url", "https://my.webhook.dev.corp.io"),
),
},
{
Config: testAccRecipientWithFilterValue("msteams", "name", "My Teams Channel"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.honeycombio_recipient.test", "name", "My Teams Channel"),
resource.TestCheckResourceAttr("data.honeycombio_recipient.test", "url", "https://outlook.office.com/webhook/12345"),
),
},
{
Config: testAccRecipientWithFilterValue("slack", "channel", "#tmp-acctest"),
Check: resource.TestCheckResourceAttr("data.honeycombio_recipient.test", "channel", "#tmp-acctest"),
Expand Down
6 changes: 2 additions & 4 deletions honeycombio/data_source_recipients.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
honeycombio "github.com/honeycombio/terraform-provider-honeycombio/client"
"github.com/honeycombio/terraform-provider-honeycombio/internal/helper"
"github.com/honeycombio/terraform-provider-honeycombio/internal/helper/hashcode"
)

Expand All @@ -25,7 +26,7 @@ func dataSourceHoneycombioRecipients() *schema.Resource {
Type: schema.TypeString,
Optional: true,
Description: "The type of recipients.",
ValidateFunc: validation.StringInSlice([]string{"email", "pagerduty", "slack", "webhook"}, false),
ValidateFunc: validation.StringInSlice(helper.AsStringSlice(honeycombio.RecipientTypes()), false),
},
"detail_filter": {
Type: schema.TypeList,
Expand Down Expand Up @@ -90,9 +91,6 @@ func dataSourceHoneycombioRecipientsRead(ctx context.Context, d *schema.Resource
}
if v, ok := d.GetOk("detail_filter"); ok {
rcptFilter = expandRecipientFilter(v.([]interface{}))
if rcptFilter.Type != matchType {
return diag.Errorf("provided type doesn't match filter type")
}
}

var rcptIDs []string
Expand Down
1 change: 1 addition & 0 deletions honeycombio/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func Provider(version string) *schema.Provider {
"honeycombio_query_annotation": newQueryAnnotation(),
"honeycombio_email_recipient": newEmailRecipient(),
"honeycombio_pagerduty_recipient": newPDRecipient(),
"honeycombio_msteams_recipient": newMSTeamsRecipient(),
"honeycombio_slack_recipient": newSlackRecipient(),
"honeycombio_webhook_recipient": newWebhookRecipient(),
"honeycombio_slo": newSLO(),
Expand Down
53 changes: 53 additions & 0 deletions honeycombio/resource_msteams_recipient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package honeycombio

import (
"context"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
honeycombio "github.com/honeycombio/terraform-provider-honeycombio/client"
)

func newMSTeamsRecipient() *schema.Resource {
return &schema.Resource{
CreateContext: resourceMSTeamsRecipientCreate,
ReadContext: resourceMSTeamsRecipientRead,
UpdateContext: resourceMSTeamsRecipientUpdate,
DeleteContext: resourceMSTeamsRecipientDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Description: "Honeycomb MSTeams Recipient allows you to define and manage an MSTeams recipient that can be used by Triggers or BurnAlerts notifications.",

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the MSTeams Integration to create",
},
"url": {
Type: schema.TypeString,
Required: true,
Description: "The Incoming Webhook URL to send the notification to",
ValidateFunc: validation.IsURLWithHTTPorHTTPS,
},
},
}
}

func resourceMSTeamsRecipientCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
return createRecipient(ctx, d, meta, honeycombio.RecipientTypeMSTeams)
}

func resourceMSTeamsRecipientRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
return readRecipient(ctx, d, meta, honeycombio.RecipientTypeMSTeams)
}

func resourceMSTeamsRecipientUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
return updateRecipient(ctx, d, meta, honeycombio.RecipientTypeMSTeams)
}

func resourceMSTeamsRecipientDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
return deleteRecipient(ctx, d, meta)
}
13 changes: 13 additions & 0 deletions honeycombio/resource_recipients_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ resource "honeycombio_webhook_recipient" "test" {
resource.TestCheckResourceAttr("honeycombio_webhook_recipient.test", "url", "https://my.url.corp.net"),
),
},
{
Config: `
resource "honeycombio_msteams_recipient" "test" {
name = "my teams channel"
url = "https://my.url.office.com/webhooks/incoming/123456789/abcdefg"
}
`,
Check: resource.ComposeTestCheckFunc(
testAccCheckRecipientExists(t, "honeycombio_msteams_recipient.test"),
resource.TestCheckResourceAttr("honeycombio_msteams_recipient.test", "name", "my teams channel"),
resource.TestCheckResourceAttr("honeycombio_msteams_recipient.test", "url", "https://my.url.office.com/webhooks/incoming/123456789/abcdefg"),
),
},
},
})
}
Loading

0 comments on commit 04ffa24

Please sign in to comment.