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] Added "databricks_groups" data resource to list all the groups in the databricks account. #3992

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
1 change: 1 addition & 0 deletions docs/data-sources/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Data source exposes the following attributes:
The following resources are used in the same context:

* [End to end workspace management](../guides/workspace-management.md) guide
* [databricks_groups](../data-sources/groups.md) to retrive [Groups](https://docs.databricks.com/en/admin/users-groups/groups.html) information.
* [databricks_cluster](../resources/cluster.md) to create [Databricks Clusters](https://docs.databricks.com/clusters/index.html).
* [databricks_directory](../resources/directory.md) to manage directories in [Databricks Workpace](https://docs.databricks.com/workspace/workspace-objects.html).
* [databricks_group_member](../resources/group_member.md) to attach [users](../resources/user.md) and [groups](../resources/group.md) as group members.
Expand Down
58 changes: 58 additions & 0 deletions docs/data-sources/groups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
subcategory: "Security"
---
# databricks_groups Data Source

Retrieves a list of all [databricks_group](../resources/group.md) display names associated with the workspace, or those matching the provided filter. Maximum 100 results.


## Example Usage

Get all groups:

```hcl
data "databricks_groups" "all" {}

output "all_groups" {
value = data.databricksdatabricks_groups.all.display_names
}
```

Get groups whose displayName contains `foo` or displayName contains `bar`.:

```hcl
data "databricks_groups" "this" {
filter = "displayName co "foo" or displayName co "bar""
sergiumpopa marked this conversation as resolved.
Show resolved Hide resolved
}

output "foobar_groups" {
value = data.databricks_pipelines.this.display_names
}
```


## Argument Reference

The following arguments are supported:

* `filter` - (Optional) Query by which the results have to be filtered. Supported operators are equals(`eq`), contains(`co`), starts with(`sw`) and not equals(`ne`).
sergiumpopa marked this conversation as resolved.
Show resolved Hide resolved


## Attribute Reference

Data source exposes the following attributes:

* `display_names` - List of display names for [Groups](https://docs.databricks.com/data-engineering/delta-live-tables/index.html) matching the provided search criteria.


## Related Resources

The following resources are used in the same context:

* [End to end workspace management](../guides/workspace-management.md) guide
* [databricks_group](../data-sources/group.md) to retrive specific [Group](https://docs.databricks.com/en/admin/users-groups/groups.html) information.
* [databricks_cluster](../resources/cluster.md) to create [Databricks Clusters](https://docs.databricks.com/clusters/index.html).
* [databricks_directory](../resources/directory.md) to manage directories in [Databricks Workpace](https://docs.databricks.com/workspace/workspace-objects.html).
* [databricks_group_member](../resources/group_member.md) to attach [users](../resources/user.md) and [groups](../resources/group.md) as group members.
* [databricks_permissions](../resources/permissions.md) to manage [access control](https://docs.databricks.com/security/access-control/index.html) in Databricks workspace.
* [databricks_user](../resources/user.md) to [manage users](https://docs.databricks.com/administration-guide/users-groups/users.html), that could be added to [databricks_group](../resources/group.md) within the workspace.
56 changes: 56 additions & 0 deletions internal/acceptance/data_groups_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package acceptance

import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

const groupsDataSourceTemplate = `
resource "databricks_group" "group1" {
display_name = "tf-group-{var.RANDOM}"
}
resource "databricks_group" "group2" {
display_name = "tf-groupfoo-{var.RANDOM}"
}
resource "databricks_group" "group3" {
display_name = "tf-groupbar-{var.RANDOM}"
}

#data "databricks_groups" "all" {}

data "databricks_groups" "this" {
sergiumpopa marked this conversation as resolved.
Show resolved Hide resolved
filter = "displayName co \"foo\" or displayName co \"bar\""
}
`

func checkGroupsDataSourcePopulated(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
r_all, ok := s.Modules[0].Resources["data.databricks_groups.all"]
require.True(t, ok, "data.databricks_group.all has to be there")
attr := r_all.Primary.Attributes
assert.Equal(t, attr["display_names.#"], "3")

r_filtered, ok := s.Modules[0].Resources["data.databricks_groups.this"]
require.True(t, ok, "data.databricks_group.this has to be there")
attr_filtered := r_filtered.Primary.Attributes
assert.Equal(t, attr_filtered["display_names.#"], "2")

return nil
}
}

func TestAccDataSourceGroups(t *testing.T) {
accountLevel(t, step{
Template: groupsDataSourceTemplate,
Check: checkGroupsDataSourcePopulated(t),
})
}
func TestMwsAccDataSourceGroups(t *testing.T) {
workspaceLevel(t, step{
Template: groupsDataSourceTemplate,
Check: checkGroupsDataSourcePopulated(t),
})
}
1 change: 1 addition & 0 deletions internal/providers/sdkv2/sdkv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func DatabricksProvider() *schema.Provider {
"databricks_external_location": catalog.DataSourceExternalLocation().ToResource(),
"databricks_external_locations": catalog.DataSourceExternalLocations().ToResource(),
"databricks_group": scim.DataSourceGroup().ToResource(),
"databricks_groups": scim.DataSourceGroups().ToResource(),
"databricks_instance_pool": pools.DataSourceInstancePool().ToResource(),
"databricks_instance_profiles": aws.DataSourceInstanceProfiles().ToResource(),
"databricks_jobs": jobs.DataSourceJobs().ToResource(),
Expand Down
6 changes: 3 additions & 3 deletions scim/data_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

// DataSourceGroup returns information about group specified by display name
func DataSourceGroup() common.Resource {
type entity struct {
type groupData struct {
DisplayName string `json:"display_name"`
Recursive bool `json:"recursive,omitempty"`
Members []string `json:"members,omitempty" tf:"slice_set,computed"`
Expand All @@ -26,7 +26,7 @@ func DataSourceGroup() common.Resource {
AclPrincipalID string `json:"acl_principal_id,omitempty" tf:"computed"`
}

s := common.StructToSchema(entity{}, func(
s := common.StructToSchema(groupData{}, func(
s map[string]*schema.Schema) map[string]*schema.Schema {
// nolint once SDKv2 has Diagnostics-returning validators, change
s["display_name"].ValidateFunc = validation.StringIsNotEmpty
Expand All @@ -39,7 +39,7 @@ func DataSourceGroup() common.Resource {
return common.Resource{
Schema: s,
Read: func(ctx context.Context, d *schema.ResourceData, m *common.DatabricksClient) error {
var this entity
var this groupData
common.DataToStructPointer(d, s, &this)
groupsAPI := NewGroupsAPI(ctx, m)
groupAttributes := "members,roles,entitlements,externalId"
Expand Down
34 changes: 34 additions & 0 deletions scim/data_groups.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package scim

import (
"context"

"github.com/databricks/databricks-sdk-go"
"github.com/databricks/databricks-sdk-go/service/iam"
"github.com/databricks/terraform-provider-databricks/common"
)

// DataSourceGroups searches from groups based on filter
func DataSourceGroups() common.Resource {
type groupData struct {
DisplayNameFilter string `json:"filter,omitempty"`
DisplayNames []string `json:"display_names,omitempty" tf:"computed,slice_set"`
}

return common.WorkspaceData(func(ctx context.Context, data *groupData, w *databricks.WorkspaceClient) error {
groupSearch := iam.ListGroupsRequest{}
sergiumpopa marked this conversation as resolved.
Show resolved Hide resolved
if data.DisplayNameFilter != "" {
groupSearch = iam.ListGroupsRequest{Filter: data.DisplayNameFilter, Count: 100}
alexott marked this conversation as resolved.
Show resolved Hide resolved
}

groups, err := w.Groups.ListAll(ctx, groupSearch)
if err != nil {
return err
}
data.DisplayNames = make([]string, 0, len(groups))
for _, v := range groups {
data.DisplayNames = append(data.DisplayNames, v.DisplayName)
}
return nil
})
}
97 changes: 97 additions & 0 deletions scim/data_groups_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package scim

import (
"testing"

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

func TestDataSourceGroups_Error(t *testing.T) {
qa.ResourceFixture{
Fixtures: qa.HTTPFailures,
Resource: DataSourceGroups(),
Read: true,
NonWritable: true,
ID: "_",
}.ExpectError(t, "i'm a teapot")
}

func TestDataSourceGroups(t *testing.T) {
qa.ResourceFixture{
Fixtures: []qa.HTTPFixture{
sergiumpopa marked this conversation as resolved.
Show resolved Hide resolved
{
Method: "GET",
Resource: `/api/2.0/preview/scim/v2/Groups?count=100&startIndex=1`,
Response: GroupList{
TotalResults: 0,
ItemsPerPage: 0,
StartIndex: 1,
Resources: []Group{
{
DisplayName: "ds",
ID: "eerste",
},
{
DisplayName: "product",
ID: "abc",
},
},
},
},
{
Method: "GET",
Resource: `/api/2.0/preview/scim/v2/Groups?count=100&startIndex=3`,
Response: GroupList{
Resources: []Group{},
},
},
},
Read: true,
NonWritable: true,
Resource: DataSourceGroups(),
ID: "_",
}.ApplyAndExpectData(t, map[string]any{
"display_names": []string{
"ds",
"product",
},
})
}

func TestDataSourceGroups_Filter(t *testing.T) {
qa.ResourceFixture{
Fixtures: []qa.HTTPFixture{
{
Method: "GET",
Resource: `/api/2.0/preview/scim/v2/Groups?count=100&filter=display_name+sw+%22prod%22&startIndex=1`,
Response: GroupList{
TotalResults: 0,
ItemsPerPage: 0,
StartIndex: 1,
Resources: []Group{
{
DisplayName: "product",
ID: "abc",
},
},
},
},
{
Method: "GET",
Resource: `/api/2.0/preview/scim/v2/Groups?count=100&filter=display_name+sw+%22prod%22&startIndex=2`,
Response: GroupList{
Resources: []Group{},
},
},
},
Read: true,
NonWritable: true,
Resource: DataSourceGroups(),
HCL: `filter="display_name sw \"prod\""`,
ID: "_",
}.ApplyAndExpectData(t, map[string]any{
"display_names": []string{
"product",
},
})
}
2 changes: 1 addition & 1 deletion scim/scim.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ type GroupList struct {
StartIndex int32 `json:"startIndex,omitempty"`
ItemsPerPage int32 `json:"itemsPerPage,omitempty"`
Schemas []URN `json:"schemas,omitempty"`
Resources []Group `json:"resources,omitempty"`
Resources []Group `json:"Resources,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, we need to understand when this has changed...

}

type email struct {
Expand Down
Loading