Skip to content

Commit e24c780

Browse files
dgomez04alexott
andauthored
[Feature] Add data source databricks_notification_destinations (#4087)
## Changes <!-- Summary of your changes that are easy to understand --> Added `databricks_notification_destinations` data source as requested in #3950 to retrieve notification destinations that are created out-of-band or in other terraform templates. ## Tests <!-- How is this tested? Please see the checklist below and also describe any other relevant tests --> - [x] `make test` run locally - [x] relevant change in `docs/` folder - [x] covered with integration tests in `internal/acceptance` - [x] relevant acceptance tests are passing - [x] using Go SDK --------- Co-authored-by: Alex Ott <[email protected]>
1 parent c3ae6f3 commit e24c780

File tree

5 files changed

+258
-0
lines changed

5 files changed

+258
-0
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
subcategory: "Workspace"
3+
---
4+
# databricks_notification_destinations Data Source
5+
6+
This data source allows you to retrieve information about [Notification Destinations](https://docs.databricks.com/api/workspace/notificationdestinations). Notification Destinations are used to send notifications for query alerts and jobs to external systems such as email, Slack, Microsoft Teams, PagerDuty, or generic webhooks.
7+
8+
## Example Usage
9+
10+
11+
```hcl
12+
resource "databricks_notification_destination" "email" {
13+
display_name = "Email Destination"
14+
config {
15+
email {
16+
addresses = ["[email protected]"]
17+
}
18+
}
19+
}
20+
21+
resource "databricks_notification_destination" "slack" {
22+
display_name = "Slack Destination"
23+
config {
24+
slack {
25+
url = "https://hooks.slack.com/services/..."
26+
}
27+
}
28+
}
29+
30+
# Lists all notification desitnations
31+
data "databricks_notification_destinations" "this" {}
32+
33+
# List destinations of specific type and name
34+
data "databricks_notification_destinations" "filtered_notification" {
35+
display_name_contains = "Destination"
36+
type = "EMAIL"
37+
}
38+
```
39+
40+
41+
## Argument Reference
42+
43+
The following arguments are supported:
44+
45+
* `display_name_contains` - (Optional) A **case-insensitive** substring to filter Notification Destinations by their display name.
46+
* `type` - (Optional) The type of the Notification Destination to filter by. Valid values are:
47+
* `EMAIL` - Filters Notification Destinations of type Email.
48+
* `MICROSOFT_TEAMS` - Filters Notification Destinations of type Microsoft Teams.
49+
* `PAGERDUTY` - Filters Notification Destinations of type PagerDuty.
50+
* `SLACK` - Filters Notification Destinations of type Slack.
51+
* `WEBHOOK` - Filters Notification Destinations of type Webhook.
52+
53+
## Attribute Reference
54+
55+
In addition to all arguments above, the following attributes are exported:
56+
57+
* `notification_destinations` - A list of Notification Destinations matching the specified criteria. Each element contains the following attributes:
58+
* `id` - The unique ID of the Notification Destination.
59+
* `display_name` - The display name of the Notification Destination.
60+
* `destination_type` - The type of the notification destination. Possible values are `EMAIL`, `MICROSOFT_TEAMS`, `PAGERDUTY`, `SLACK`, or `WEBHOOK`.
61+
62+
If no matches are found, an empty list will be returned.

internal/providers/pluginfw/pluginfw.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
providercommon "github.com/databricks/terraform-provider-databricks/internal/providers/common"
1919
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/resources/cluster"
2020
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/resources/library"
21+
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/resources/notificationdestinations"
2122
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/resources/qualitymonitor"
2223
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/resources/registered_model"
2324
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/resources/volume"
@@ -54,6 +55,7 @@ func (p *DatabricksProviderPluginFramework) DataSources(ctx context.Context) []f
5455
cluster.DataSourceCluster,
5556
volume.DataSourceVolumes,
5657
registered_model.DataSourceRegisteredModel,
58+
notificationdestinations.DataSourceNotificationDestinations,
5759
}
5860
}
5961

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package notificationdestinations
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"slices"
7+
"strings"
8+
9+
"github.com/databricks/databricks-sdk-go/service/settings"
10+
"github.com/databricks/terraform-provider-databricks/common"
11+
pluginfwcommon "github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/common"
12+
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/converters"
13+
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/tfschema"
14+
"github.com/databricks/terraform-provider-databricks/internal/service/settings_tf"
15+
"github.com/hashicorp/terraform-plugin-framework/datasource"
16+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
17+
"github.com/hashicorp/terraform-plugin-framework/diag"
18+
"github.com/hashicorp/terraform-plugin-framework/types"
19+
)
20+
21+
func DataSourceNotificationDestinations() datasource.DataSource {
22+
return &NotificationDestinationsDataSource{}
23+
}
24+
25+
var _ datasource.DataSourceWithConfigure = &NotificationDestinationsDataSource{}
26+
27+
type NotificationDestinationsDataSource struct {
28+
Client *common.DatabricksClient
29+
}
30+
31+
type NotificationDestinationsInfo struct {
32+
DisplayNameContains types.String `tfsdk:"display_name_contains" tf:"optional"`
33+
Type types.String `tfsdk:"type" tf:"optional"`
34+
NotificationDestinations []settings_tf.ListNotificationDestinationsResult `tfsdk:"notification_destinations" tf:"computed"`
35+
}
36+
37+
func (d *NotificationDestinationsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
38+
resp.TypeName = "databricks_notification_destinations"
39+
}
40+
41+
func (d *NotificationDestinationsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
42+
attrs, blocks := tfschema.DataSourceStructToSchemaMap(NotificationDestinationsInfo{}, nil)
43+
resp.Schema = schema.Schema{
44+
Attributes: attrs,
45+
Blocks: blocks,
46+
}
47+
}
48+
49+
func (d *NotificationDestinationsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
50+
if d.Client == nil {
51+
d.Client = pluginfwcommon.ConfigureDataSource(req, resp)
52+
}
53+
}
54+
55+
func validateType(notificationType string) diag.Diagnostics {
56+
validTypes := []string{
57+
string(settings.DestinationTypeEmail),
58+
string(settings.DestinationTypeMicrosoftTeams),
59+
string(settings.DestinationTypePagerduty),
60+
string(settings.DestinationTypeSlack),
61+
string(settings.DestinationTypeWebhook),
62+
}
63+
64+
if !slices.Contains(validTypes, notificationType) {
65+
return diag.Diagnostics{diag.NewErrorDiagnostic(fmt.Sprintf("Invalid type '%s'; valid types are %s.", notificationType, strings.Join(validTypes, ", ")), "")}
66+
}
67+
return nil
68+
}
69+
70+
func AppendDiagAndCheckErrors(resp *datasource.ReadResponse, diags diag.Diagnostics) bool {
71+
resp.Diagnostics.Append(diags...)
72+
return resp.Diagnostics.HasError()
73+
}
74+
75+
func (d *NotificationDestinationsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
76+
w, diags := d.Client.GetWorkspaceClient()
77+
if AppendDiagAndCheckErrors(resp, diags) {
78+
return
79+
}
80+
81+
var notificationInfo NotificationDestinationsInfo
82+
if AppendDiagAndCheckErrors(resp, req.Config.Get(ctx, &notificationInfo)) {
83+
return
84+
}
85+
86+
notificationType := notificationInfo.Type.ValueString()
87+
notificationDisplayName := strings.ToLower(notificationInfo.DisplayNameContains.ValueString())
88+
89+
if notificationType != "" && AppendDiagAndCheckErrors(resp, validateType(notificationType)) {
90+
return
91+
}
92+
93+
notificationsGoSdk, err := w.NotificationDestinations.ListAll(ctx, settings.ListNotificationDestinationsRequest{})
94+
if err != nil {
95+
resp.Diagnostics.AddError("Failed to fetch Notification Destinations", err.Error())
96+
return
97+
}
98+
99+
var notificationsTfSdk []settings_tf.ListNotificationDestinationsResult
100+
for _, notification := range notificationsGoSdk {
101+
if (notificationType != "" && notification.DestinationType.String() != notificationType) ||
102+
(notificationDisplayName != "" && !strings.Contains(strings.ToLower(notification.DisplayName), notificationDisplayName)) {
103+
continue
104+
}
105+
106+
var notificationDestination settings_tf.ListNotificationDestinationsResult
107+
if AppendDiagAndCheckErrors(resp, converters.GoSdkToTfSdkStruct(ctx, notification, &notificationDestination)) {
108+
return
109+
}
110+
notificationsTfSdk = append(notificationsTfSdk, notificationDestination)
111+
}
112+
113+
notificationInfo.NotificationDestinations = notificationsTfSdk
114+
resp.Diagnostics.Append(resp.State.Set(ctx, notificationInfo)...)
115+
116+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package notificationdestinations_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/databricks/terraform-provider-databricks/internal/acceptance"
7+
"github.com/hashicorp/terraform-plugin-testing/terraform"
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func CheckDataSourceNotificationsPopulated(t *testing.T) func(s *terraform.State) error {
13+
return func(s *terraform.State) error {
14+
ds, ok := s.Modules[0].Resources["data.databricks_notification_destinations.this"]
15+
require.True(t, ok, "data.databricks_notification_destinations.this has to be there")
16+
17+
notificationCount := ds.Primary.Attributes["notification_destinations.#"]
18+
require.Equal(t, "2", notificationCount, "expected two notifications")
19+
20+
notificationIds := []string{
21+
ds.Primary.Attributes["notification_destinations.0.id"],
22+
ds.Primary.Attributes["notification_destinations.1.id"],
23+
}
24+
25+
expectedNotificationIds := []string{
26+
s.Modules[0].Resources["databricks_notification_destination.email_notification"].Primary.ID,
27+
s.Modules[0].Resources["databricks_notification_destination.slack_notification"].Primary.ID,
28+
}
29+
30+
assert.ElementsMatch(t, expectedNotificationIds, notificationIds, "expected notification_destination ids to match")
31+
32+
return nil
33+
}
34+
}
35+
36+
func TestAccNotificationsCreation(t *testing.T) {
37+
acceptance.WorkspaceLevel(t, acceptance.Step{
38+
Template: `
39+
resource "databricks_notification_destination" "email_notification" {
40+
display_name = "email notification destination"
41+
config {
42+
email {
43+
addresses = ["[email protected]"]
44+
}
45+
}
46+
}
47+
48+
resource "databricks_notification_destination" "slack_notification" {
49+
display_name = "slack notification destination"
50+
config {
51+
slack {
52+
url = "https://hooks.slack.com/services/..."
53+
}
54+
}
55+
}
56+
57+
data "databricks_notification_destinations" "this" {
58+
depends_on = [databricks_notification_destination.email_notification, databricks_notification_destination.slack_notification]
59+
}
60+
`,
61+
Check: CheckDataSourceNotificationsPopulated(t),
62+
})
63+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package notificationdestinations
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform-plugin-framework/diag"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestValidateType_InvalidType(t *testing.T) {
11+
actualDiagnostics := validateType("INVALID")
12+
expectedDiagnostics := diag.Diagnostics{diag.NewErrorDiagnostic("Invalid type 'INVALID'; valid types are EMAIL, MICROSOFT_TEAMS, PAGERDUTY, SLACK, WEBHOOK.", "")}
13+
assert.True(t, actualDiagnostics.HasError())
14+
assert.Equal(t, expectedDiagnostics, actualDiagnostics)
15+
}

0 commit comments

Comments
 (0)