Skip to content

Commit cf8cc0f

Browse files
Added databricks_sql_alert resource (#2047)
1 parent a0921ab commit cf8cc0f

File tree

4 files changed

+250
-0
lines changed

4 files changed

+250
-0
lines changed

docs/resources/sql_alert.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
subcategory: "Databricks SQL"
3+
---
4+
# databricks_sql_alert Resource
5+
6+
This resource allows you to manage [Databricks SQL Alerts](https://docs.databricks.com/sql/user/queries/index.html).
7+
8+
**Note:** To manage [SQLA resources](https://docs.databricks.com/sql/get-started/concepts.html) you must have `databricks_sql_access` on your [databricks_group](group.md#databricks_sql_access) or [databricks_user](user.md#databricks_sql_access).
9+
10+
## Example Usage
11+
12+
```hcl
13+
resource "databricks_directory" "shared_dir" {
14+
path = "/Shared/Queries"
15+
}
16+
17+
resource "databricks_sql_query" "this" {
18+
data_source_id = databricks_sql_endpoint.example.data_source_id
19+
name = "My Query Name"
20+
query = "SELECT 1 AS p1, 2 as p2"
21+
parent = "folders/${databricks_directory.shared_dir.object_id}"
22+
}
23+
24+
resource "databricks_sql_alert" "alert" {
25+
query_id = databricks_sql_query.this.id
26+
name = "My Alert"
27+
parent = "folders/${databricks_directory.shared_dir.object_id}"
28+
rearm = 1
29+
options {
30+
column = "p1"
31+
op = "=="
32+
value = "2"
33+
muted = false
34+
}
35+
}
36+
```
37+
38+
## Argument Reference
39+
40+
The following arguments are available:
41+
42+
* `query_id` - (Required, String) ID of the query evaluated by the alert.
43+
* `name` - (Required, String) Name of the alert.
44+
* `options` - (Required) Alert configuration options.
45+
* `column` - (Required, String) Name of column in the query result to compare in alert evaluation.
46+
* `op` - (Required, String Enum) Operator used to compare in alert evaluation. (Enum: `>`, `>=`, `<`, `<=`, `==`, `!=`)
47+
* `value` - (Required, String) Value used to compare in alert evaluation.
48+
* `muted` - (Optional, bool) Whether or not the alert is muted. If an alert is muted, it will not notify users and alert destinations when triggered.
49+
* `custom_subject` - (Optional, String) Custom subject of alert notification, if it exists. This includes email subject, Slack notification header, etc. See [Alerts API reference](https://docs.databricks.com/sql/user/alerts/index.html) for custom templating instructions.
50+
* `custom_body` - (Optional, String) Custom body of alert notification, if it exists. See [Alerts API reference](https://docs.databricks.com/sql/user/alerts/index.html) for custom templating instructions.
51+
* `parent` - (Optional, String) The identifier of the workspace folder containing the alert. The default is ther user's home folder. The folder identifier is formatted as `folder/<folder_id>`.
52+
* `rearm` - (Optional, Integer) Number of seconds after being triggered before the alert rearms itself and can be triggered again. If not defined, alert will never be triggered again.
53+
54+
## Related Resources
55+
56+
The following resources are often used in the same context:
57+
58+
* [End to end workspace management](../guides/workspace-management.md) guide.
59+
* [databricks_sql_query](sql_query.md) to manage Databricks SQL [Queries](https://docs.databricks.com/sql/user/queries/index.html).
60+
* [databricks_sql_endpoint](sql_endpoint.md) to manage Databricks SQL [Endpoints](https://docs.databricks.com/sql/admin/sql-endpoints.html).
61+
* [databricks_directory](directory.md) to manage directories in [Databricks Workpace](https://docs.databricks.com/workspace/workspace-objects.html).
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package acceptance
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestAccAlert(t *testing.T) {
8+
workspaceLevel(t, step{
9+
Template: `
10+
resource "databricks_sql_query" "this" {
11+
data_source_id = "{env.TEST_DEFAULT_WAREHOUSE_DATASOURCE_ID}"
12+
name = "tf-{var.RANDOM}"
13+
query = "SELECT 1 AS p1, 2 as p2"
14+
}
15+
16+
resource "databricks_sql_alert" "alert" {
17+
query_id = databricks_sql_query.this.id
18+
name = "tf-alert-{var.RANDOM}"
19+
options {
20+
column = "p1"
21+
op = "=="
22+
value = "2"
23+
muted = false
24+
}
25+
}`,
26+
}, step{
27+
Template: `
28+
resource "databricks_sql_query" "this" {
29+
data_source_id = "{env.TEST_DEFAULT_WAREHOUSE_DATASOURCE_ID}"
30+
name = "tf-{var.RANDOM}"
31+
query = "SELECT 1 AS p1, 2 as p2"
32+
}
33+
34+
resource "databricks_sql_alert" "alert" {
35+
query_id = databricks_sql_query.this.id
36+
name = "tf-alert-{var.RANDOM}"
37+
options {
38+
column = "p1"
39+
op = ">="
40+
value = "2"
41+
muted = false
42+
}
43+
}`,
44+
})
45+
}

provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ func DatabricksProvider() *schema.Provider {
142142
"databricks_sql_global_config": sql.ResourceSqlGlobalConfig(),
143143
"databricks_sql_permissions": access.ResourceSqlPermissions(),
144144
"databricks_sql_query": sql.ResourceSqlQuery(),
145+
"databricks_sql_alert": sql.ResourceSqlAlert(),
145146
"databricks_sql_visualization": sql.ResourceSqlVisualization(),
146147
"databricks_sql_widget": sql.ResourceSqlWidget(),
147148
"databricks_storage_credential": catalog.ResourceStorageCredential(),

sql/resource_sql_alerts.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package sql
2+
3+
import (
4+
"context"
5+
6+
"github.com/databricks/databricks-sdk-go/service/sql"
7+
"github.com/databricks/terraform-provider-databricks/common"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
10+
)
11+
12+
type AlertOptions struct {
13+
Column string `json:"column"`
14+
Op string `json:"op"`
15+
Value string `json:"value"`
16+
Muted bool `json:"muted,omitempty"`
17+
CustomBody string `json:"custom_body,omitempty"`
18+
CustomSubject string `json:"custom_subject,omitempty"`
19+
}
20+
21+
type AlertEntity struct {
22+
Name string `json:"name"`
23+
QueryId string `json:"query_id"`
24+
Rearm int `json:"rearm,omitempty"`
25+
Options *AlertOptions `json:"options"`
26+
Parent string `json:"parent,omitempty" tf:"suppress_diff,force_new"`
27+
}
28+
29+
func (a *AlertEntity) toCreateAlertApiObject(s map[string]*schema.Schema, data *schema.ResourceData) (sql.CreateAlert, error) {
30+
common.DataToStructPointer(data, s, a)
31+
32+
var ca sql.CreateAlert
33+
ca.Name = a.Name
34+
ca.Parent = a.Parent
35+
ca.QueryId = a.QueryId
36+
ca.Rearm = a.Rearm
37+
ca.Options = sql.AlertOptions{
38+
Column: a.Options.Column,
39+
CustomBody: a.Options.CustomBody,
40+
CustomSubject: a.Options.CustomSubject,
41+
Muted: a.Options.Muted,
42+
Op: a.Options.Op,
43+
Value: a.Options.Value,
44+
}
45+
46+
return ca, nil
47+
}
48+
49+
func (a *AlertEntity) toEditAlertApiObject(s map[string]*schema.Schema, data *schema.ResourceData) (sql.EditAlert, error) {
50+
common.DataToStructPointer(data, s, a)
51+
52+
return sql.EditAlert{
53+
AlertId: data.Id(),
54+
Name: a.Name,
55+
Options: sql.AlertOptions{
56+
Column: a.Options.Column,
57+
CustomBody: a.Options.CustomBody,
58+
CustomSubject: a.Options.CustomSubject,
59+
Muted: a.Options.Muted,
60+
Op: a.Options.Op,
61+
Value: a.Options.Value,
62+
},
63+
QueryId: a.QueryId,
64+
Rearm: a.Rearm,
65+
}, nil
66+
}
67+
68+
func (a *AlertEntity) fromAPIObject(apiAlert *sql.Alert, s map[string]*schema.Schema, data *schema.ResourceData) error {
69+
a.Name = apiAlert.Name
70+
a.Parent = apiAlert.Parent
71+
a.QueryId = apiAlert.Query.Id
72+
a.Rearm = apiAlert.Rearm
73+
a.Options = &AlertOptions{
74+
Column: apiAlert.Options.Column,
75+
Op: apiAlert.Options.Op,
76+
Value: apiAlert.Options.Value,
77+
Muted: apiAlert.Options.Muted,
78+
CustomBody: apiAlert.Options.CustomBody,
79+
CustomSubject: apiAlert.Options.CustomSubject,
80+
}
81+
82+
return common.StructToData(a, s, data)
83+
}
84+
85+
func ResourceSqlAlert() *schema.Resource {
86+
s := common.StructToSchema(AlertEntity{}, func(m map[string]*schema.Schema) map[string]*schema.Schema {
87+
options := m["options"].Elem.(*schema.Resource)
88+
options.Schema["op"].ValidateFunc = validation.StringInSlice([]string{">", ">=", "<", "<=", "==", "!="}, true)
89+
return m
90+
})
91+
92+
return common.Resource{
93+
Create: func(ctx context.Context, data *schema.ResourceData, c *common.DatabricksClient) error {
94+
w, err := c.WorkspaceClient()
95+
if err != nil {
96+
return err
97+
}
98+
var a AlertEntity
99+
ca, err := a.toCreateAlertApiObject(s, data)
100+
if err != nil {
101+
return err
102+
}
103+
apiAlert, err := w.Alerts.Create(ctx, ca)
104+
if err != nil {
105+
return err
106+
}
107+
data.SetId(apiAlert.Id)
108+
return nil
109+
},
110+
Read: func(ctx context.Context, data *schema.ResourceData, c *common.DatabricksClient) error {
111+
w, err := c.WorkspaceClient()
112+
if err != nil {
113+
return err
114+
}
115+
apiAlert, err := w.Alerts.GetByAlertId(ctx, data.Id())
116+
if err != nil {
117+
return err
118+
}
119+
var a AlertEntity
120+
return a.fromAPIObject(apiAlert, s, data)
121+
},
122+
Update: func(ctx context.Context, data *schema.ResourceData, c *common.DatabricksClient) error {
123+
w, err := c.WorkspaceClient()
124+
if err != nil {
125+
return err
126+
}
127+
var a AlertEntity
128+
ca, err := a.toEditAlertApiObject(s, data)
129+
if err != nil {
130+
return err
131+
}
132+
return w.Alerts.Update(ctx, ca)
133+
},
134+
Delete: func(ctx context.Context, data *schema.ResourceData, c *common.DatabricksClient) error {
135+
w, err := c.WorkspaceClient()
136+
if err != nil {
137+
return err
138+
}
139+
return w.Alerts.DeleteByAlertId(ctx, data.Id())
140+
},
141+
Schema: s,
142+
}.ToResource()
143+
}

0 commit comments

Comments
 (0)