Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for 'msteams' recipients #386

Merged
merged 2 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a fine tradeoff to not have to introduce more complex logic for webhooks and teams being more or less equivalent. We don't fail as fast, but 🤷🏻

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