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

[Feature] Add databricks_budget resource #3955

Merged
merged 32 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3ab39fb
WIP
840 Aug 27, 2024
170109c
WIP
840 Aug 27, 2024
4c31ac8
WIP
840 Aug 27, 2024
8567d6b
WIP
840 Aug 28, 2024
e70e844
WIP on tests
840 Sep 2, 2024
1c2c946
Use SDK struct
840 Sep 2, 2024
b998c4b
WIP
840 Sep 2, 2024
1a2f6e5
Improve Budget resource
840 Sep 3, 2024
fe44b95
Rename files to singular, add acceptance test
840 Sep 3, 2024
0ba9802
Support `Update` to prevent force replacement, add documentation
840 Sep 3, 2024
3789a33
Add unit tests
840 Sep 4, 2024
f67c84c
Merge remote-tracking branch 'origin/master' into issue-3887
840 Sep 4, 2024
8dd32ff
Add error checks
840 Sep 4, 2024
95b6625
Test clean up
840 Sep 4, 2024
9337daa
Merge branch 'main' into issue-3887
840 Sep 4, 2024
05b981a
Support BigDecimal conversion and resolve drift issues
840 Sep 4, 2024
f33d739
Merge branch 'main' into issue-3887
840 Sep 5, 2024
21e08e8
Refactor BigDecimal conversion, add unit tests, fix acceptance tests
840 Sep 5, 2024
c0cfee7
Add empty check
840 Sep 5, 2024
f8fe342
Fix test
840 Sep 5, 2024
c7f32db
Use `SetCustomSuppressDiff` to detect drift for `quantity_threshold` …
840 Sep 6, 2024
25e4ed7
Fix test
840 Sep 6, 2024
1ae1cdc
Fix update test
840 Sep 6, 2024
2dfeb23
Merge branch 'main' into issue-3887
840 Sep 6, 2024
5e92bc6
Improve doc, fix acceptance test
840 Sep 6, 2024
3e2f234
Change host example to AWS account console
840 Sep 6, 2024
20bfded
Merge branch 'main' into issue-3887
alexott Sep 10, 2024
2be6ea5
Rename from `databricks_mws_budget` to `databricks_budget`
alexott Sep 10, 2024
9206b5d
Correct doc a bit as this feature is available in all clouds
alexott Sep 11, 2024
8ea27de
Update docs
alexott Oct 1, 2024
98bd847
Address the rest of PR comments
alexott Oct 2, 2024
27284f8
Add negative test case for read
alexott Oct 2, 2024
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
103 changes: 103 additions & 0 deletions docs/resources/budget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
subcategory: "FinOps"
---
# databricks_budget Resource

-> **Note** Initialize provider with `alias = "account"`, and `host` pointing to the account URL, like, `host = "https://accounts.cloud.databricks.com"`. Use `provider = databricks.account` for all account-level resources.

-> **Public Preview** This feature is in [Public Preview](https://docs.databricks.com/release-notes/release-types.html).

This resource allows you to manage [Databricks Budgets](https://docs.databricks.com/en/admin/account-settings/budgets.html).

## Example Usage

```hcl
resource "databricks_budget" "this" {
display_name = "databricks-workspace-budget"

alert_configurations {
time_period = "MONTH"
trigger_type = "CUMULATIVE_SPENDING_EXCEEDED"
quantity_type = "LIST_PRICE_DOLLARS_USD"
quantity_threshold = "840"

action_configurations {
action_type = "EMAIL_NOTIFICATION"
target = "abc@gmail.com"
}
}

filter {
workspace_id {
operator = "IN"
values = [
1234567890098765
]
}

tags {
key = "Team"
value {
operator = "IN"
values = ["Data Science"]
}
}

tags {
key = "Environment"
value {
operator = "IN"
values = ["Development"]
}
}
}
}
```

## Argument Reference

The following arguments are available:

* `display_name` - (Required) Name of the budget in Databricks Account.

### alert_configurations Configuration Block (Required)
alexott marked this conversation as resolved.
Show resolved Hide resolved

* `time_period` - (Required, String Enum) The time window of usage data for the budget. (Enum: `MONTH`)
* `trigger_type` - (Required, String Enum) The evaluation method to determine when this budget alert is in a triggered state. (Enum: `CUMULATIVE_SPENDING_EXCEEDED`)
* `quantity_type` - (Required, String Enum) The way to calculate cost for this budget alert. This is what quantity_threshold is measured in. (Enum: `LIST_PRICE_DOLLARS_USD`)
* `quantity_threshold` - (Required, String) The threshold for the budget alert to determine if it is in a triggered state. The number is evaluated based on `quantity_type`.
* `action_configurations` - (Required) List of action configurations to take when the budget alert is triggered. Consists of the following fields:
* `action_type` - (Required, String Enum) The type of action to take when the budget alert is triggered. (Enum: `EMAIL_NOTIFICATION`)
* `target` - (Required, String) The target of the action. For `EMAIL_NOTIFICATION`, this is the email address to send the notification to.

### filter Configuration Block (Optional)

* `workspace_id` - (Optional) Filter by workspace ID (if empty, include usage all usage for this account). Consists of the following fields:
* `operator` - (Required, String Enum) The operator to use for the filter. (Enum: `IN`)
* `values` - (Required, List of numbers) The values to filter by.
* `tags` - (Optional) List of tags to filter by. Consists of the following fields:
* `key` - (Required, String) The key of the tag.
* `value` - (Required) Consists of the following fields:
* `operator` - (Required, String Enum) The operator to use for the filter. (Enum: `IN`)
* `values` - (Required, List of strings) The values to filter by.

## Attribute Reference

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

* `budget_configuration_id` - The ID of the budget configuration.
* `account_id` - The ID of the Databricks Account.

## Import

This resource can be imported by Databricks account ID and Budget.

```sh
terraform import databricks_budget.this '<account_id>|<budget_configuration_id>'
```

## Related Resources

The following resources are used in the context:

* [databricks_mws_workspaces](mws_workspaces.md) to set up Databricks workspaces.
102 changes: 102 additions & 0 deletions finops/resource_budget.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package finops

import (
"context"
"strings"

"github.com/databricks/databricks-sdk-go/service/billing"
"github.com/databricks/terraform-provider-databricks/common"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func ResourceBudget() common.Resource {
s := common.StructToSchema(billing.BudgetConfiguration{}, func(m map[string]*schema.Schema) map[string]*schema.Schema {
common.CustomizeSchemaPath(m, "display_name").SetValidateFunc(validation.StringLenBetween(1, 128))
for _, p := range []string{"account_id", "budget_configuration_id", "create_time", "update_time"} {
common.CustomizeSchemaPath(m, p).SetComputed()
}
common.CustomizeSchemaPath(m, "alert_configurations", "alert_configuration_id").SetComputed()
common.CustomizeSchemaPath(m, "alert_configurations", "action_configurations", "action_configuration_id").SetComputed()
// We need SuppressDiff because API returns a string representation of BigDecimal with a lot
// of trailing 0s, etc.
common.CustomizeSchemaPath(m, "alert_configurations", "quantity_threshold").SetCustomSuppressDiff(func(k, old, new string, d *schema.ResourceData) bool {
alexott marked this conversation as resolved.
Show resolved Hide resolved
normalize := func(v string) string {
if strings.Contains(v, ".") {
v = strings.TrimRight(v, "0")
v = strings.TrimSuffix(v, ".")
}
return v
}
return normalize(old) == normalize(new)
})
return m
})
p := common.NewPairID("account_id", "budget_configuration_id")
return common.Resource{
Create: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
var create billing.CreateBudgetConfigurationBudget
common.DataToStructPointer(d, s, &create)
acc, err := c.AccountClient()
if err != nil {
return err
}
budget, err := acc.Budgets.Create(ctx, billing.CreateBudgetConfigurationRequest{Budget: create})
if err != nil {
return err
}
d.Set("budget_configuration_id", budget.Budget.BudgetConfigurationId)
d.Set("account_id", c.Config.AccountID)
common.StructToData(budget.Budget, s, d)
p.Pack(d)
return nil
},
Read: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
_, id, err := p.Unpack(d)
if err != nil {
return err
}
acc, err := c.AccountClient()
if err != nil {
return err
}
budget, err := acc.Budgets.GetByBudgetId(ctx, id)
if err != nil {
return err
}
return common.StructToData(budget.Budget, s, d)
},
Update: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
var update billing.UpdateBudgetConfigurationBudget
_, id, err := p.Unpack(d)
if err != nil {
return err
}
common.DataToStructPointer(d, s, &update)
acc, err := c.AccountClient()
if err != nil {
return err
}
budget, err := acc.Budgets.Update(ctx, billing.UpdateBudgetConfigurationRequest{
Budget: update,
BudgetId: id,
})
if err != nil {
return err
}
return common.StructToData(budget.Budget, s, d)
},
Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
_, id, err := p.Unpack(d)
if err != nil {
return err
}
acc, err := c.AccountClient()
if err != nil {
return err
}
return acc.Budgets.DeleteByBudgetId(ctx, id)
},
Schema: s,
}
}
Loading
Loading