Skip to content

Commit da259d7

Browse files
authored
Implicitly force import manually added user (#1048)
1 parent 9bd9112 commit da259d7

File tree

4 files changed

+115
-2
lines changed

4 files changed

+115
-2
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Version changelog
22

3+
## 0.4.6
4+
5+
* Added optional `force` argument to `databricks_user` resource to 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.
6+
7+
Updated dependency versions:
8+
9+
* Bump github.com/Azure/go-autorest/autorest/azure/auth from 0.5.10 to 0.5.11
10+
* Bump github.com/Azure/go-autorest/autorest/azure/cli from 0.4.3 to 0.4.5
11+
* Bump github.com/Azure/go-autorest/autorest from 0.11.23 to 0.11.24
12+
313
## 0.4.5
414

515
* Cross-linked resource documentation ([#1027](https://github.com/databrickslabs/terraform-provider-databricks/pull/1027)).

docs/resources/user.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ The following arguments are available:
5353
* `allow_instance_pool_create` - (Optional) Allow the user to have [instance pool](instance_pool.md) create privileges. Defaults to false. More fine grained permissions could be assigned with [databricks_permissions](permissions.md#Instance-Pool-usage) and [instance_pool_id](permissions.md#instance_pool_id) argument.
5454
* `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).
5555
* `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.
56+
* `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.
5657

5758
## Attribute Reference
5859

scim/resource_user.go

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

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

68
"github.com/databrickslabs/terraform-provider-databricks/common"
79

@@ -20,6 +22,10 @@ func ResourceUser() *schema.Resource {
2022
func(m map[string]*schema.Schema) map[string]*schema.Schema {
2123
addEntitlementsToSchema(&m)
2224
m["active"].Default = true
25+
m["force"] = &schema.Schema{
26+
Type: schema.TypeBool,
27+
Optional: true,
28+
}
2329
return m
2430
})
2531
scimUserFromData := func(d *schema.ResourceData) (user User, err error) {
@@ -40,9 +46,10 @@ func ResourceUser() *schema.Resource {
4046
if err != nil {
4147
return err
4248
}
43-
user, err := NewUsersAPI(ctx, c).Create(u)
49+
usersAPI := NewUsersAPI(ctx, c)
50+
user, err := usersAPI.Create(u)
4451
if err != nil {
45-
return err
52+
return createForceOverridesManuallyAddedUser(err, d, usersAPI, u)
4653
}
4754
d.SetId(user.ID)
4855
return nil
@@ -70,3 +77,23 @@ func ResourceUser() *schema.Resource {
7077
},
7178
}.ToResource()
7279
}
80+
81+
func createForceOverridesManuallyAddedUser(err error, d *schema.ResourceData, usersAPI UsersAPI, u User) error {
82+
forceCreate := d.Get("force").(bool)
83+
if !forceCreate {
84+
return err
85+
}
86+
// corner-case for overriding manually provisioned users
87+
userName := strings.ReplaceAll(u.UserName, "'", "")
88+
force := fmt.Sprintf("User with username %s already exists.", userName)
89+
if err.Error() != force {
90+
return err
91+
}
92+
userList, err := usersAPI.Filter(fmt.Sprintf("userName eq '%s'", userName))
93+
if err != nil {
94+
return err
95+
}
96+
user := userList[0]
97+
d.SetId(user.ID)
98+
return usersAPI.Update(d.Id(), u)
99+
}

scim/resource_user_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package scim
22

33
import (
4+
"context"
5+
"fmt"
46
"testing"
57

68
"github.com/databrickslabs/terraform-provider-databricks/common"
@@ -370,3 +372,76 @@ func TestResourceUserDelete_Error(t *testing.T) {
370372
}.Apply(t)
371373
require.Error(t, err, err)
372374
}
375+
376+
func TestCreateForceOverridesManuallyAddedUserErrorNotMatched(t *testing.T) {
377+
d := ResourceUser().TestResourceData()
378+
d.Set("force", true)
379+
rerr := createForceOverridesManuallyAddedUser(
380+
fmt.Errorf("nonsense"), d,
381+
NewUsersAPI(context.Background(), &common.DatabricksClient{}), User{})
382+
assert.EqualError(t, rerr, "nonsense")
383+
}
384+
385+
func TestCreateForceOverwriteCannotListUsers(t *testing.T) {
386+
qa.HTTPFixturesApply(t, []qa.HTTPFixture{
387+
{
388+
Method: "GET",
389+
Resource: "/api/2.0/preview/scim/v2/Users?filter=userName%20eq%20%27me%40example.com%27",
390+
Status: 417,
391+
Response: common.APIError{
392+
Message: "cannot find user",
393+
},
394+
},
395+
}, func(ctx context.Context, client *common.DatabricksClient) {
396+
d := ResourceUser().TestResourceData()
397+
d.Set("force", true)
398+
err := createForceOverridesManuallyAddedUser(
399+
fmt.Errorf("User with username [email protected] already exists."),
400+
d, NewUsersAPI(ctx, client), User{
401+
UserName: "[email protected]",
402+
})
403+
assert.EqualError(t, err, "cannot find user")
404+
})
405+
}
406+
407+
func TestCreateForceOverwriteFindsAndSetsID(t *testing.T) {
408+
qa.HTTPFixturesApply(t, []qa.HTTPFixture{
409+
{
410+
Method: "GET",
411+
Resource: "/api/2.0/preview/scim/v2/Users?filter=userName%20eq%20%27me%40example.com%27",
412+
Response: UserList{
413+
Resources: []User{
414+
{
415+
ID: "abc",
416+
},
417+
},
418+
},
419+
},
420+
{
421+
Method: "GET",
422+
Resource: "/api/2.0/preview/scim/v2/Users/abc",
423+
Response: User{
424+
ID: "abc",
425+
},
426+
},
427+
{
428+
Method: "PUT",
429+
Resource: "/api/2.0/preview/scim/v2/Users/abc",
430+
ExpectedRequest: User{
431+
Schemas: []URN{UserSchema},
432+
UserName: "[email protected]",
433+
},
434+
},
435+
}, func(ctx context.Context, client *common.DatabricksClient) {
436+
d := ResourceUser().TestResourceData()
437+
d.Set("force", true)
438+
d.Set("user_name", "[email protected]")
439+
err := createForceOverridesManuallyAddedUser(
440+
fmt.Errorf("User with username [email protected] already exists."),
441+
d, NewUsersAPI(ctx, client), User{
442+
UserName: "[email protected]",
443+
})
444+
assert.NoError(t, err)
445+
assert.Equal(t, "abc", d.Id())
446+
})
447+
}

0 commit comments

Comments
 (0)