-
Notifications
You must be signed in to change notification settings - Fork 391
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 datasource databricks_users
#4028
base: main
Are you sure you want to change the base?
Changes from all commits
05f70c1
f2dd1c2
2d594a9
0d6f280
b6380f8
1c703b4
dbd79d8
4ed08d4
072123a
bffcf54
7fa5823
1c58eaa
c2d70b9
4ab1e27
8db0188
2e46921
ed587ee
6e4b8ed
5604c68
f285db5
a628819
d5ac8b4
32e79f6
6f6d19e
88608c1
26c69fb
9e54137
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
--- | ||
subcategory: "Security" | ||
--- | ||
|
||
# databricks_users Data Source | ||
|
||
-> If you have a fully automated setup with workspaces created by [databricks_mws_workspaces](../resources/mws_workspaces.md) or [azurerm_databricks_workspace](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/databricks_workspace), please make sure to add [depends_on attribute](../guides/troubleshooting.md#data-resources-and-authentication-is-not-configured-errors) in order to prevent _default auth: cannot configure default credentials_ errors. | ||
|
||
Retrieves information about multiple [databricks_user](../resources/user.md) resources. | ||
|
||
## Example Usage | ||
|
||
Adding a subset of users to a group | ||
|
||
```hcl | ||
data "databricks_users" "company_users" { | ||
filter = "userName co \"@domain.org\"" | ||
} | ||
resource "databricks_group" "data_users_group" { | ||
display_name = "Data Users" | ||
} | ||
resource "databricks_group_member" "add_users_to_group" { | ||
for_each = { for user in data.databricks_users.company_users.users : user.id => user } | ||
group_id = databricks_group.data_users_group.id | ||
member_id = each.value.id | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
This data source allows you to filter the list of users using the following optional arguments: | ||
|
||
- `filter` - (Optional) Query by which the results have to be filtered. If not specified, all users will be returned. Supported operators are equals (`eq`), contains (`co`), starts with (`sw`), and not equals (`ne`). Additionally, simple expressions can be formed using logical operators `and` and `or`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should add a note (or pointer to the doc) that will clarify if the search is case-sensitive or not? |
||
|
||
**Examples:** | ||
- User whose `displayName` equals "john": | ||
```hcl | ||
filter = "displayName eq \"john\"" | ||
``` | ||
- User whose `displayName` contains "john" or `userName` contains "@domain.org": | ||
```hcl | ||
filter = "displayName co \"john\" or userName co \"@domain.org\"" | ||
``` | ||
|
||
## Attribute Reference | ||
|
||
This data source exposes the following attributes: | ||
|
||
- `users` - A list of users matching the specified criteria. Each user has the following attributes: | ||
- `id` - The ID of the user. | ||
- `userName` - The username of the user. | ||
- `emails` - All the emails associated with the Databricks user. | ||
- `name` | ||
- `givenName` - Given name of the Databricks user. | ||
- `familyName` - Family name of the Databricks user. | ||
- `displayName` - The display name of the user. | ||
- `roles` - Indicates if the user has the admin role. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's not only for admin roles |
||
- `$ref` | ||
- `value` | ||
- `display` | ||
- `primary` | ||
- `type` | ||
- `externalId` - reserved for future use. | ||
- `active` - Boolean that represents if this user is active. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have more information in the |
||
|
||
## Related Resources | ||
|
||
The following resources are used in the same context: | ||
|
||
- [**databricks_user**](../resources/user.md): Resource to manage individual users in Databricks. | ||
|
||
- [**databricks_group**](../resources/group.md): Resource to manage groups in Databricks. | ||
|
||
- [**databricks_group_member**](../resources/group_member.md): Resource to manage group memberships by adding users to groups. | ||
|
||
- [**databricks_permissions**](../resources/permissions.md): Resource to manage access control in the Databricks workspace. | ||
|
||
- [**databricks_current_user**](current_user.md): Data source to retrieve information about the user or service principal that is calling the Databricks REST API. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package user | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/databricks/databricks-sdk-go/service/iam" | ||
"github.com/databricks/terraform-provider-databricks/common" | ||
pluginfwcommon "github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/common" | ||
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/converters" | ||
"github.com/databricks/terraform-provider-databricks/internal/providers/pluginfw/tfschema" | ||
"github.com/databricks/terraform-provider-databricks/internal/service/iam_tf" | ||
"github.com/hashicorp/terraform-plugin-framework/datasource" | ||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
) | ||
|
||
const dataSourceName = "users" | ||
|
||
func DataSourceUsers() datasource.DataSource { | ||
return &UsersDataSource{} | ||
} | ||
|
||
var _ datasource.DataSourceWithConfigure = &UsersDataSource{} | ||
|
||
type UsersDataSource struct { | ||
Client *common.DatabricksClient | ||
} | ||
|
||
type UsersInfo struct { | ||
Filter types.String `json:"filter,omitempty"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I would recommend as well - by default fetch only limited number of attributes, i.e., don't include We can add an additional parameter, like, |
||
Users []iam_tf.User `json:"users,omitempty" tf:"computed"` | ||
} | ||
|
||
func (d *UsersDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { | ||
resp.TypeName = pluginfwcommon.GetDatabricksProductionName(dataSourceName) | ||
} | ||
|
||
func (d *UsersDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { | ||
attrs, blocks := tfschema.DataSourceStructToSchemaMap(UsersInfo{}, nil) | ||
resp.Schema = schema.Schema{ | ||
Attributes: attrs, | ||
Blocks: blocks, | ||
} | ||
} | ||
|
||
func (d *UsersDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { | ||
if d.Client == nil { | ||
d.Client = pluginfwcommon.ConfigureDataSource(req, resp) | ||
} | ||
} | ||
|
||
func (d *UsersDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { | ||
var usersInfo UsersInfo | ||
|
||
resp.Diagnostics.Append(req.Config.Get(ctx, &usersInfo)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
var users []iam.User | ||
var err error | ||
|
||
if d.Client.Config.IsAccountClient() { | ||
a, diags := d.Client.GetAccountClient() | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
users, err = a.Users.ListAll(ctx, iam.ListAccountUsersRequest{Filter: usersInfo.Filter.ValueString()}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. explicitly configure attributes, like this: https://github.com/databricks/terraform-provider-databricks/blob/main/exporter/util_scim.go#L289, but without |
||
if err != nil { | ||
resp.Diagnostics.AddError("Error listing account users", err.Error()) | ||
} | ||
} else { | ||
w, diags := d.Client.GetWorkspaceClient() | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
users, err = w.Users.ListAll(ctx, iam.ListUsersRequest{Filter: usersInfo.Filter.ValueString()}) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error listing workspace users", err.Error()) | ||
} | ||
} | ||
|
||
for _, user := range users { | ||
var tfUser iam_tf.User | ||
resp.Diagnostics.Append(converters.GoSdkToTfSdkStruct(ctx, user, &tfUser)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
usersInfo.Users = append(usersInfo.Users, tfUser) | ||
} | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, usersInfo)...) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package user_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/databricks/terraform-provider-databricks/internal/acceptance" | ||
"github.com/hashicorp/terraform-plugin-testing/terraform" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
const dataSourceTemplate = ` | ||
resource "databricks_user" "user1" { | ||
user_name = "tf-{var.STICKY_RANDOM}[email protected]" | ||
} | ||
|
||
resource "databricks_user" "user2" { | ||
user_name = "tf-{var.STICKY_RANDOM}[email protected]" | ||
} | ||
|
||
data "databricks_users" "this" { | ||
dgomez04 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
filter = "userName co \"testuser\"" | ||
depends_on = [databricks_user.user1, databricks_user.user2] | ||
} | ||
` | ||
|
||
func checkUsersDataSourcePopulated(t *testing.T) func(s *terraform.State) error { | ||
return func(s *terraform.State) error { | ||
ds, ok := s.Modules[0].Resources["data.databricks_users.this"] | ||
require.True(t, ok, "data.databricks_users.this has to be there") | ||
|
||
usersCount := ds.Primary.Attributes["users.#"] | ||
require.Equal(t, "2", usersCount, "expected two users") | ||
|
||
userIds := []string{ | ||
ds.Primary.Attributes["users.0.id"], | ||
ds.Primary.Attributes["users.1.id"], | ||
} | ||
|
||
expectedUserIDs := []string{ | ||
s.Modules[0].Resources["databricks_user.user1"].Primary.ID, | ||
s.Modules[0].Resources["databricks_user.user2"].Primary.ID, | ||
} | ||
|
||
assert.ElementsMatch(t, expectedUserIDs, userIds, "expected user ids to match") | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func TestAccDataSourceDataUsers(t *testing.T) { | ||
acceptance.AccountLevel(t, acceptance.Step{ | ||
Template: dataSourceTemplate, | ||
Check: checkUsersDataSourcePopulated(t), | ||
}) | ||
} | ||
|
||
func TestWorkspaceDataSourceDataUsers(t *testing.T) { | ||
acceptance.WorkspaceLevel(t, acceptance.Step{ | ||
Template: dataSourceTemplate, | ||
Check: checkUsersDataSourcePopulated(t), | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a note that it works with both workspace & account-level providers?