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 7 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
61 changes: 61 additions & 0 deletions mws/resource_mws_budgets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package mws

import (
"context"
"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 ResourceMwsBudget() 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()
}
return m
})
p := common.NewPairSeparatedID("account_id", "budget_configuration_id", "/")
840 marked this conversation as resolved.
Show resolved Hide resolved
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.AccountClientWithAccountIdFromConfig(d)
840 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
budget, err := acc.Budgets.Create(ctx, billing.CreateBudgetConfigurationRequest{Budget: create})
if err != nil {
return err
}
d.SetId(budget.Budget.BudgetConfigurationId)
840 marked this conversation as resolved.
Show resolved Hide resolved
d.Set("budget_configuration_id", budget.Budget.BudgetConfigurationId)
d.Set("account_id", c.Config.AccountID)
common.StructToData(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)
acc, err := c.AccountClient()
if err != nil {
return err
}
res, err := acc.Budgets.GetByBudgetId(ctx, id)
if err != nil {
return err
}
return common.StructToData(res.Budget, s, d)
},
Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
_, id, err := p.Unpack(d)
acc, err := c.AccountClient()
if err != nil {
return err
}
return acc.Budgets.DeleteByBudgetId(ctx, id)
},
Schema: s,
}
}
143 changes: 143 additions & 0 deletions mws/resource_mws_budgets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package mws

import (
"github.com/databricks/databricks-sdk-go/experimental/mocks"
"github.com/databricks/databricks-sdk-go/service/billing"
"github.com/stretchr/testify/mock"
"testing"

"github.com/databricks/terraform-provider-databricks/qa"
)

func getTestBudget() *billing.BudgetConfiguration {
return &billing.BudgetConfiguration{
AccountId: "account_id",
AlertConfigurations: []billing.AlertConfiguration{
{
ActionConfigurations: []billing.ActionConfiguration{
{
ActionType: billing.ActionConfigurationTypeEmailNotification,
Target: "me@databricks.com",
},
},
AlertConfigurationId: "alert_configuration_id",
QuantityThreshold: "840",
QuantityType: billing.AlertConfigurationQuantityTypeListPriceDollarsUsd,
TimePeriod: billing.AlertConfigurationTimePeriodMonth,
TriggerType: billing.AlertConfigurationTriggerTypeCumulativeSpendingExceeded,
},
},
Filter: &billing.BudgetConfigurationFilter{
Tags: []billing.BudgetConfigurationFilterTagClause{
{
Key: "Environment",
Value: &billing.BudgetConfigurationFilterClause{
Operator: billing.BudgetConfigurationFilterOperatorIn,
Values: []string{"Testing"},
},
},
},
WorkspaceId: &billing.BudgetConfigurationFilterWorkspaceIdClause{
Operator: billing.BudgetConfigurationFilterOperatorIn,
Values: []int64{
1234567890098765,
},
},
},
BudgetConfigurationId: "budget_configuration_id",
DisplayName: "budget_name",
}
}

func TestResourceBudgetCreate(t *testing.T) {
qa.ResourceFixture{
MockAccountClientFunc: func(a *mocks.MockAccountClient) {
api := a.GetMockbudgetsAPI().EXPECT()
api.Create(mock.Anything, billing.CreateBudgetConfigurationRequest{
Budget: billing.CreateBudgetConfigurationBudget{
AlertConfigurations: []billing.CreateBudgetConfigurationBudgetAlertConfigurations{
{
ActionConfigurations: []billing.CreateBudgetConfigurationBudgetActionConfigurations{
{
ActionType: billing.ActionConfigurationTypeEmailNotification,
Target: "me@databricks.com",
},
},
QuantityThreshold: "840",
QuantityType: billing.AlertConfigurationQuantityTypeListPriceDollarsUsd,
TimePeriod: billing.AlertConfigurationTimePeriodMonth,
TriggerType: billing.AlertConfigurationTriggerTypeCumulativeSpendingExceeded,
},
},
DisplayName: getTestBudget().DisplayName,
Filter: getTestBudget().Filter,
},
}).Return(&billing.CreateBudgetConfigurationResponse{Budget: getTestBudget()}, nil)
api.GetByBudgetId(mock.Anything, "budget_configuration_id").Return(
&billing.GetBudgetConfigurationResponse{Budget: getTestBudget()}, nil,
)
},
Create: true,
AccountID: "account_id",
HCL: `
display_name = "budget_name"

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 = "me@databricks.com"
}
}

filter {
tags {
key = "Environment"
value {
operator = "IN"
values = ["Testing"]
}
}

workspace_id {
operator = "IN"
values = [
1234567890098765
]
}
}
`,
Resource: ResourceMwsBudget(),
}.ApplyAndExpectData(t, nil) // ???
}

func TestResourceMwsBudgetRead(t *testing.T) {
qa.ResourceFixture{
MockAccountClientFunc: func(a *mocks.MockAccountClient) {
a.GetMockbudgetsAPI().EXPECT().
GetByBudgetId(mock.Anything, "budget_configuration_id").
Return(&billing.GetBudgetConfigurationResponse{Budget: getTestBudget()}, nil)
},
Resource: ResourceMwsBudget(),
Read: true,
New: true,
AccountID: "account_id",
ID: "account_id/budget_configuration_id",
}.ApplyAndExpectData(t, nil) // ???
}

func TestResourceMwsBudgetDelete(t *testing.T) {
qa.ResourceFixture{
MockAccountClientFunc: func(a *mocks.MockAccountClient) {
a.GetMockbudgetsAPI().EXPECT().DeleteByBudgetId(mock.Anything, "budget_configuration_id").Return(nil)
},
Resource: ResourceMwsBudget(),
AccountID: "account_id",
Delete: true,
ID: "account_id/budget_configuration_id",
}.ApplyAndExpectData(t, nil)
}
1 change: 1 addition & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ func DatabricksProvider() *schema.Provider {
"databricks_mlflow_webhook": mlflow.ResourceMlflowWebhook().ToResource(),
"databricks_model_serving": serving.ResourceModelServing().ToResource(),
"databricks_mount": storage.ResourceMount().ToResource(),
"databricks_mws_budget": mws.ResourceMwsBudget().ToResource(),
"databricks_mws_customer_managed_keys": mws.ResourceMwsCustomerManagedKeys().ToResource(),
"databricks_mws_credentials": mws.ResourceMwsCredentials().ToResource(),
"databricks_mws_log_delivery": mws.ResourceMwsLogDelivery().ToResource(),
Expand Down