Skip to content

Commit 696061f

Browse files
authored
Added force_delete_home_dir and force_delete_repos attributes to databricks_user and databricks_service_principal resources (#2032)
1 parent 2a2fff8 commit 696061f

File tree

8 files changed

+519
-14
lines changed

8 files changed

+519
-14
lines changed

docs/resources/service_principal.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ The following arguments are available:
9696
* `workspace_access` - (Optional) This is a field to allow the group to have access to Databricks Workspace.
9797
* `active` - (Optional) Either service principal is active or not. True by default, but can be set to false in case of service principal deactivation with preserving service principal assets.
9898
* `force` - (Optional) Ignore `cannot create service principal: Service principal with application ID X already exists` errors and implicitly import the specified service principal into Terraform state, enforcing entitlements defined in the instance of resource. _This functionality is experimental_ and is designed to simplify corner cases, like Azure Active Directory synchronisation.
99+
* `force_delete_repos` - (Optional) This flag determines whether the service principal's repo directory is deleted when the user is deleted. It will have no impact when in the accounts SCIM API. False by default.
100+
* `force_delete_home_dir` - (Optional) This flag determines whether the service principal's home directory is deleted when the user is deleted. It will have no impact when in the accounts SCIM API. False by default.
99101

100102
## Attribute Reference
101103

docs/resources/user.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ The following arguments are available:
9393
* `databricks_sql_access` - (Optional) This is a field to allow the group to have access to [Databricks SQL](https://databricks.com/product/databricks-sql) feature in User Interface and through [databricks_sql_endpoint](sql_endpoint.md).
9494
* `active` - (Optional) Either user is active or not. True by default, but can be set to false in case of user deactivation with preserving user assets.
9595
* `force` - (Optional) Ignore `cannot create user: User with username X already exists` errors and implicitly import the specific user into Terraform state, enforcing entitlements defined in the instance of resource. _This functionality is experimental_ and is designed to simplify corner cases, like Azure Active Directory synchronisation.
96+
* `force_delete_repos` - (Optional) This flag determines whether the user's repo directory is deleted when the user is deleted. It will have no impact when in the accounts SCIM API. False by default.
97+
* `force_delete_home_dir` - (Optional) This flag determines whether the user's home directory is deleted when the user is deleted. It will have not impact when in the accounts SCIM API. False by default.
9698

9799
## Attribute Reference
98100

internal/acceptance/service_principal_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package acceptance
22

33
import (
4+
"context"
5+
"fmt"
6+
"os"
47
"testing"
8+
9+
"github.com/databricks/databricks-sdk-go"
10+
"github.com/databricks/databricks-sdk-go/apierr"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
512
)
613

714
const azureSpn = `resource "databricks_service_principal" "this" {
@@ -14,6 +21,77 @@ const awsSpn = `resource "databricks_service_principal" "this" {
1421
display_name = "SPN {var.RANDOM}"
1522
}`
1623

24+
func TestAccServicePrincipalHomeDeleteSuccess(t *testing.T) {
25+
GetEnvOrSkipTest(t, "ARM_CLIENT_ID")
26+
workspaceLevel(t, step{
27+
Template: `
28+
resource "databricks_service_principal" "a" {
29+
application_id = "{var.RANDOM_UUID}"
30+
force_delete_home_dir = true
31+
}`,
32+
Check: func(s *terraform.State) error {
33+
appId := s.RootModule().Resources["databricks_service_principal.a"].Primary.Attributes["application_id"]
34+
os.Setenv("application_id_a", appId)
35+
return nil
36+
},
37+
}, step{
38+
Template: `
39+
resource "databricks_service_principal" "b" {
40+
application_id = "{var.RANDOM_UUID}"
41+
}
42+
`,
43+
Check: func(s *terraform.State) error {
44+
w, err := databricks.NewWorkspaceClient()
45+
if err != nil {
46+
return err
47+
}
48+
ctx := context.Background()
49+
_, err = w.Workspace.GetStatusByPath(ctx, fmt.Sprintf("/Users/%v", os.Getenv("application_id_a")))
50+
os.Remove("application_id_a")
51+
if err != nil {
52+
if apierr.IsMissing(err) {
53+
return nil
54+
}
55+
return err
56+
}
57+
return nil
58+
},
59+
})
60+
}
61+
62+
func TestAccServicePrinicpalHomeDeleteNotDeleted(t *testing.T) {
63+
GetEnvOrSkipTest(t, "ARM_CLIENT_ID")
64+
workspaceLevel(t, step{
65+
Template: `
66+
resource "databricks_service_principal" "a" {
67+
application_id = "{var.RANDOM_UUID}"
68+
force_delete_home_dir = false
69+
}`,
70+
Check: func(s *terraform.State) error {
71+
appId := s.RootModule().Resources["databricks_service_principal.a"].Primary.Attributes["application_id"]
72+
os.Setenv("application_id_a", appId)
73+
return nil
74+
},
75+
}, step{
76+
Template: `
77+
resource "databricks_service_principal" "b" {
78+
application_id = "{var.RANDOM_UUID}"
79+
}
80+
`,
81+
Check: func(s *terraform.State) error {
82+
w, err := databricks.NewWorkspaceClient()
83+
if err != nil {
84+
return err
85+
}
86+
ctx := context.Background()
87+
appId := os.Getenv("application_id_a")
88+
_, err = w.Workspace.GetStatusByPath(ctx, fmt.Sprintf("/Users/%v", appId))
89+
os.Remove("application_id_a")
90+
return err
91+
},
92+
})
93+
}
94+
1795
func TestMwsAccServicePrincipalResourceOnAzure(t *testing.T) {
1896
GetEnvOrSkipTest(t, "ARM_CLIENT_ID")
1997
accountLevel(t, step{

internal/acceptance/user_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package acceptance
22

33
import (
44
"context"
5+
"fmt"
6+
"strings"
57
"testing"
68

79
"github.com/databricks/databricks-sdk-go"
@@ -44,6 +46,66 @@ func TestAccForceUserImport(t *testing.T) {
4446
})
4547
}
4648

49+
func TestAccUserHomeDelete(t *testing.T) {
50+
username := qa.RandomEmail()
51+
workspaceLevel(t, step{
52+
Template: `
53+
resource "databricks_user" "first" {
54+
user_name = "` + username + `"
55+
force_delete_home_dir = true
56+
}`,
57+
Check: func(s *terraform.State) error {
58+
return nil
59+
},
60+
}, step{
61+
Template: `
62+
resource "databricks_user" "second" {
63+
user_name = "{var.RANDOM}@example.com"
64+
}`,
65+
Check: func(s *terraform.State) error {
66+
w, err := databricks.NewWorkspaceClient()
67+
if err != nil {
68+
return err
69+
}
70+
ctx := context.Background()
71+
_, err = w.Workspace.GetStatusByPath(ctx, fmt.Sprintf("/Users/%v", username))
72+
if err != nil {
73+
targetErr := fmt.Sprintf("Path (/Users/%v) doesn't exist", username)
74+
if strings.Contains(err.Error(), targetErr) {
75+
return nil
76+
}
77+
return err
78+
}
79+
return nil
80+
},
81+
})
82+
}
83+
func TestAccUserHomeDeleteNotDeleted(t *testing.T) {
84+
username := qa.RandomEmail()
85+
workspaceLevel(t, step{
86+
Template: `
87+
resource "databricks_user" "a" {
88+
user_name = "` + username + `"
89+
}`,
90+
Check: func(s *terraform.State) error {
91+
return nil
92+
},
93+
}, step{
94+
Template: `
95+
resource "databricks_user" "b" {
96+
user_name = "{var.RANDOM}@example.com"
97+
}`,
98+
Check: func(s *terraform.State) error {
99+
w, err := databricks.NewWorkspaceClient()
100+
if err != nil {
101+
return err
102+
}
103+
ctx := context.Background()
104+
_, err = w.Workspace.GetStatusByPath(ctx, fmt.Sprintf("/Users/%v", username))
105+
return err
106+
},
107+
})
108+
}
47109
func TestAccUserResource(t *testing.T) {
48110
differentUsers := `
49111
resource "databricks_user" "first" {

scim/resource_service_principal.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/databricks/terraform-provider-databricks/common"
1010
"golang.org/x/exp/slices"
1111

12+
"github.com/databricks/terraform-provider-databricks/workspace"
1213
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1314
)
1415

@@ -109,6 +110,14 @@ func ResourceServicePrincipal() *schema.Resource {
109110
Optional: true,
110111
Computed: true,
111112
}
113+
m["force_delete_repos"] = &schema.Schema{
114+
Type: schema.TypeBool,
115+
Optional: true,
116+
}
117+
m["force_delete_home_dir"] = &schema.Schema{
118+
Type: schema.TypeBool,
119+
Optional: true,
120+
}
112121
return m
113122
})
114123
spFromData := func(d *schema.ResourceData) User {
@@ -161,7 +170,28 @@ func ResourceServicePrincipal() *schema.Resource {
161170
})
162171
},
163172
Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
164-
return NewServicePrincipalsAPI(ctx, c).Delete(d.Id())
173+
spAPI := NewServicePrincipalsAPI(ctx, c)
174+
appId := d.Get("application_id").(string)
175+
err := spAPI.Delete(d.Id())
176+
if err != nil {
177+
return err
178+
}
179+
if c.Config.IsAccountClient() && c.Config.AccountID != "" {
180+
return nil
181+
}
182+
if d.Get("force_delete_repos").(bool) {
183+
err = workspace.NewNotebooksAPI(ctx, c).Delete(fmt.Sprintf("/Repos/%v", appId), true)
184+
if err != nil {
185+
return fmt.Errorf("force_delete_repos: %w", err)
186+
}
187+
}
188+
if d.Get("force_delete_home_dir").(bool) {
189+
err = workspace.NewNotebooksAPI(ctx, c).Delete(fmt.Sprintf("/Users/%v", appId), true)
190+
if err != nil {
191+
return fmt.Errorf("force_delete_home_dir: %w", err)
192+
}
193+
}
194+
return nil
165195
},
166196
}.ToResource()
167197
}

0 commit comments

Comments
 (0)