From 4709988cb863b7c6cd607a380c9b5b5cd1d8405a Mon Sep 17 00:00:00 2001 From: Serge Smertin <259697+nfx@users.noreply.github.com> Date: Thu, 6 Apr 2023 18:25:20 +0200 Subject: [PATCH] Explicitly include SCIM attributes for `databricks_group`, `databricks_user`, `databricks_user_role`, `databricks_group_role`, `databricks_group_member`, `databricks_group_instance_profile`, `databricks_user` data, `databricks_group` data, and `databricks_entitlement` resources (#2200) Reduce the possibility of platform errors --- aws/resource_group_instance_profile.go | 2 +- aws/resource_group_instance_profile_test.go | 10 +++--- aws/resource_user_instance_profile.go | 2 +- aws/resource_user_instance_profile_test.go | 10 +++--- aws/resource_user_role.go | 2 +- aws/resource_user_role_test.go | 2 +- exporter/exporter_test.go | 24 +++++++++---- internal/acceptance/data_user_test.go | 40 +++++++++++++++++++++ internal/acceptance/group_member_test.go | 4 +-- internal/acceptance/group_role_test.go | 18 ++++++++++ internal/acceptance/group_test.go | 4 +-- internal/acceptance/user_role_test.go | 18 ++++++++++ scim/data_group.go | 5 +-- scim/data_group_test.go | 4 +-- scim/data_user.go | 2 +- scim/data_user_test.go | 2 +- scim/groups.go | 11 +++--- scim/resource_entitlement.go | 4 +-- scim/resource_entitlement_test.go | 30 ++++++++-------- scim/resource_group.go | 4 +-- scim/resource_group_member.go | 2 +- scim/resource_group_member_test.go | 10 +++--- scim/resource_group_role.go | 2 +- scim/resource_group_role_test.go | 10 +++--- scim/resource_group_test.go | 20 +++++------ scim/resource_user.go | 6 ++-- scim/resource_user_test.go | 22 ++++++------ scim/users.go | 8 ++--- 28 files changed, 184 insertions(+), 94 deletions(-) create mode 100644 internal/acceptance/data_user_test.go create mode 100644 internal/acceptance/group_role_test.go create mode 100644 internal/acceptance/user_role_test.go diff --git a/aws/resource_group_instance_profile.go b/aws/resource_group_instance_profile.go index 08338c37c6..9e06a36e0e 100644 --- a/aws/resource_group_instance_profile.go +++ b/aws/resource_group_instance_profile.go @@ -19,7 +19,7 @@ func ResourceGroupInstanceProfile() *schema.Resource { return m }).BindResource(common.BindResource{ ReadContext: func(ctx context.Context, groupID, roleARN string, c *common.DatabricksClient) error { - group, err := scim.NewGroupsAPI(ctx, c).Read(groupID) + group, err := scim.NewGroupsAPI(ctx, c).Read(groupID, "roles") hasRole := scim.ComplexValues(group.Roles).HasValue(roleARN) if err == nil && !hasRole { return apierr.NotFound("Group has no instance profile") diff --git a/aws/resource_group_instance_profile_test.go b/aws/resource_group_instance_profile_test.go index 83cd4ee5b8..c0f699701d 100644 --- a/aws/resource_group_instance_profile_test.go +++ b/aws/resource_group_instance_profile_test.go @@ -26,7 +26,7 @@ func TestResourceGroupInstanceProfileCreate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: scim.Group{ Schemas: []scim.URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -125,7 +125,7 @@ func TestResourceGroupInstanceProfileRead(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: scim.Group{ Schemas: []scim.URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -151,7 +151,7 @@ func TestResourceGroupInstanceProfileRead_NotFound(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: apierr.APIErrorBody{ ErrorCode: "NOT_FOUND", Message: "Item not found", @@ -171,7 +171,7 @@ func TestResourceGroupInstanceProfileRead_NotFound_Role(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: scim.Group{ Schemas: []scim.URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -191,7 +191,7 @@ func TestResourceGroupInstanceProfileRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: apierr.APIErrorBody{ ErrorCode: "INVALID_REQUEST", Message: "Internal error happened", diff --git a/aws/resource_user_instance_profile.go b/aws/resource_user_instance_profile.go index 2bff25281f..b316dfd02c 100644 --- a/aws/resource_user_instance_profile.go +++ b/aws/resource_user_instance_profile.go @@ -22,7 +22,7 @@ func ResourceUserInstanceProfile() *schema.Resource { return scim.NewUsersAPI(ctx, c).Patch(userID, scim.PatchRequest("add", "roles", roleARN)) }, ReadContext: func(ctx context.Context, userID, roleARN string, c *common.DatabricksClient) error { - user, err := scim.NewUsersAPI(ctx, c).Read(userID) + user, err := scim.NewUsersAPI(ctx, c).Read(userID, "roles") hasRole := scim.ComplexValues(user.Roles).HasValue(roleARN) if err == nil && !hasRole { return apierr.NotFound("User has no role") diff --git a/aws/resource_user_instance_profile_test.go b/aws/resource_user_instance_profile_test.go index 7eee930907..50a661e65b 100644 --- a/aws/resource_user_instance_profile_test.go +++ b/aws/resource_user_instance_profile_test.go @@ -26,7 +26,7 @@ func TestResourceUserInstanceProfileCreate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=roles", Response: scim.User{ Schemas: []scim.URN{"urn:ietf:params:scim:schemas:core:2.0:User"}, DisplayName: "Data Scientists", @@ -91,7 +91,7 @@ func TestResourceUserInstanceProfileRead(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=roles", Response: scim.User{ Schemas: []scim.URN{"urn:ietf:params:scim:schemas:core:2.0:User"}, DisplayName: "Data Scientists", @@ -117,7 +117,7 @@ func TestResourceUserInstanceProfileRead_NoRole(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=roles", Response: scim.User{ Schemas: []scim.URN{"urn:ietf:params:scim:schemas:core:2.0:User"}, DisplayName: "Data Scientists", @@ -137,7 +137,7 @@ func TestResourceUserInstanceProfileRead_NotFound(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=roles", Response: apierr.APIErrorBody{ ErrorCode: "NOT_FOUND", Message: "Item not found", @@ -157,7 +157,7 @@ func TestResourceUserInstanceProfileRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=roles", Response: apierr.APIErrorBody{ ErrorCode: "INVALID_REQUEST", Message: "Internal error happened", diff --git a/aws/resource_user_role.go b/aws/resource_user_role.go index 1b67f62f0f..ef65f0612e 100644 --- a/aws/resource_user_role.go +++ b/aws/resource_user_role.go @@ -16,7 +16,7 @@ func ResourceUserRole() *schema.Resource { return scim.NewUsersAPI(ctx, c).Patch(userID, scim.PatchRequest("add", "roles", role)) }, ReadContext: func(ctx context.Context, userID, roleARN string, c *common.DatabricksClient) error { - user, err := scim.NewUsersAPI(ctx, c).Read(userID) + user, err := scim.NewUsersAPI(ctx, c).Read(userID, "roles") hasRole := scim.ComplexValues(user.Roles).HasValue(roleARN) if err == nil && !hasRole { return apierr.NotFound("User has no role") diff --git a/aws/resource_user_role_test.go b/aws/resource_user_role_test.go index 7e919a64ff..19bb31fa55 100644 --- a/aws/resource_user_role_test.go +++ b/aws/resource_user_role_test.go @@ -23,7 +23,7 @@ func TestUserRoleCreate_AndGetResourceDrift(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/a", + Resource: "/api/2.0/preview/scim/v2/Users/a?attributes=roles", Response: scim.User{}, }, }, diff --git a/exporter/exporter_test.go b/exporter/exporter_test.go index 7b235d7b93..516e107669 100644 --- a/exporter/exporter_test.go +++ b/exporter/exporter_test.go @@ -357,7 +357,7 @@ func TestImportingUsersGroupsSecretScopes(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/a", + Resource: "/api/2.0/preview/scim/v2/Groups/a?attributes=members", Response: scim.Group{ID: "a", DisplayName: "admins", Members: []scim.ComplexValue{ {Display: "test@test.com", Value: "123", Ref: "Users/123"}, @@ -369,12 +369,24 @@ func TestImportingUsersGroupsSecretScopes(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/b", + Resource: "/api/2.0/preview/scim/v2/Groups/a?attributes=displayName,externalId,entitlements", + Response: scim.Group{ID: "a", DisplayName: "admins", + Members: []scim.ComplexValue{ + {Display: "test@test.com", Value: "123", Ref: "Users/123"}, + {Display: "Test group", Value: "f", Ref: "Groups/f"}, + {Display: "spn", Value: "spn", Ref: "ServicePrincipals/spn"}, + }, + }, + ReuseRequest: true, + }, + { + Method: "GET", + Resource: "/api/2.0/preview/scim/v2/Groups/b?attributes=displayName,externalId,entitlements", Response: scim.Group{ID: "b", DisplayName: "users"}, }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/c", + Resource: "/api/2.0/preview/scim/v2/Groups/c?attributes=displayName,externalId,entitlements", Response: scim.Group{ID: "c", DisplayName: "test", Groups: []scim.ComplexValue{ {Display: "admins", Value: "a", Ref: "Groups/a", Type: "direct"}, @@ -383,13 +395,13 @@ func TestImportingUsersGroupsSecretScopes(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/f", + Resource: "/api/2.0/preview/scim/v2/Groups/f?attributes=displayName,externalId,entitlements", Response: scim.Group{ID: "f", DisplayName: "nested"}, }, // TODO: add groups to the output { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/123", + Resource: "/api/2.0/preview/scim/v2/Users/123?attributes=userName,displayName,active,externalID,entitlements", Response: scim.User{ID: "123", DisplayName: "test@test.com", UserName: "test@test.com"}, }, { @@ -1614,7 +1626,7 @@ func TestImportingDLTPipelines(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/123", + Resource: "/api/2.0/preview/scim/v2/Users/123?attributes=userName,displayName,active,externalID,entitlements", Response: scim.User{ID: "123", DisplayName: "user@domain.com", UserName: "user@domain.com"}, }, { diff --git a/internal/acceptance/data_user_test.go b/internal/acceptance/data_user_test.go new file mode 100644 index 0000000000..66a3deab2e --- /dev/null +++ b/internal/acceptance/data_user_test.go @@ -0,0 +1,40 @@ +package acceptance + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const userDataSourceTemplate = ` +resource "databricks_user" "this" { + user_name = "tf-{var.RANDOM}@example.com" +} +data "databricks_user" "this" { + user_name = databricks_user.this.user_name +}` + +func checkUserDataSourcePopulated(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + r, ok := s.Modules[0].Resources["data.databricks_user.this"] + require.True(t, ok, "data.databricks_user.this has to be there") + assert.Equal(t, s.Modules[0].Resources["databricks_user.this"].Primary.ID, r.Primary.ID) + return nil + } +} + +func TestMwsAccUserData(t *testing.T) { + accountLevel(t, step{ + Template: userDataSourceTemplate, + Check: checkUserDataSourcePopulated(t), + }) +} + +func TestAccUserData(t *testing.T) { + workspaceLevel(t, step{ + Template: userDataSourceTemplate, + Check: checkUserDataSourcePopulated(t), + }) +} diff --git a/internal/acceptance/group_member_test.go b/internal/acceptance/group_member_test.go index 3a7f8ffaa6..b261fd132b 100644 --- a/internal/acceptance/group_member_test.go +++ b/internal/acceptance/group_member_test.go @@ -32,7 +32,7 @@ func TestMwsAccGroupMemberResource(t *testing.T) { accountLevel(t, step{ Template: groupMemberTest, Callback: func(ctx context.Context, client *common.DatabricksClient, id string) error { - g, err := scim.NewGroupsAPI(ctx, client).Read(id) + g, err := scim.NewGroupsAPI(ctx, client).Read(id, "members") if err != nil { return err } @@ -46,7 +46,7 @@ func TestAccGroupMemberResource(t *testing.T) { workspaceLevel(t, step{ Template: groupMemberTest, Callback: func(ctx context.Context, client *common.DatabricksClient, id string) error { - g, err := scim.NewGroupsAPI(ctx, client).Read(id) + g, err := scim.NewGroupsAPI(ctx, client).Read(id, "members") if err != nil { return err } diff --git a/internal/acceptance/group_role_test.go b/internal/acceptance/group_role_test.go new file mode 100644 index 0000000000..7ba0c167df --- /dev/null +++ b/internal/acceptance/group_role_test.go @@ -0,0 +1,18 @@ +package acceptance + +import ( + "testing" +) + +func TestAccGroupRole(t *testing.T) { + workspaceLevel(t, step{ + Template: ` + resource "databricks_group" "this" { + display_name = "tf-{var.RANDOM}" + } + resource "databricks_group_role" "this" { + group_id = databricks_group.this.id + role = "arn:aws:iam::999999999999:role/foo" + }`, + }) +} diff --git a/internal/acceptance/group_test.go b/internal/acceptance/group_test.go index aa1a1500a9..32663c5518 100644 --- a/internal/acceptance/group_test.go +++ b/internal/acceptance/group_test.go @@ -23,7 +23,7 @@ func TestMwsAccGroupsExternalIdAndScimProvisioning(t *testing.T) { // duplicate code between workspace level and account level, because clients // might get different groupsAPI := scim.NewGroupsAPI(ctx, client) - group, err := groupsAPI.Read(id) + group, err := groupsAPI.Read(id, "displayName,entitlements") if err != nil { return err } @@ -52,7 +52,7 @@ func TestAccGroupsExternalIdAndScimProvisioning(t *testing.T) { resourceCheck("databricks_group.this", func(ctx context.Context, client *common.DatabricksClient, id string) error { groupsAPI := scim.NewGroupsAPI(ctx, client) - group, err := groupsAPI.Read(id) + group, err := groupsAPI.Read(id, "displayName,entitlements") if err != nil { return err } diff --git a/internal/acceptance/user_role_test.go b/internal/acceptance/user_role_test.go new file mode 100644 index 0000000000..9828b1c050 --- /dev/null +++ b/internal/acceptance/user_role_test.go @@ -0,0 +1,18 @@ +package acceptance + +import ( + "testing" +) + +func TestAccUserRole(t *testing.T) { + workspaceLevel(t, step{ + Template: ` + resource "databricks_user" "this" { + user_name = "{var.RANDOM}@example.com" + } + resource "databricks_user_role" "this" { + user_id = databricks_user.this.id + role = "arn:aws:iam::999999999999:role/foo" + }`, + }) +} diff --git a/scim/data_group.go b/scim/data_group.go index 0bec38d060..400035c9b8 100644 --- a/scim/data_group.go +++ b/scim/data_group.go @@ -41,7 +41,8 @@ func DataSourceGroup() *schema.Resource { var this entity common.DataToStructPointer(d, s, &this) groupsAPI := NewGroupsAPI(ctx, m) - group, err := groupsAPI.ReadByDisplayName(this.DisplayName) + groupAttributes := "members,roles,entitlements,externalId" + group, err := groupsAPI.ReadByDisplayName(this.DisplayName, groupAttributes) if err != nil { return diag.FromErr(err) } @@ -69,7 +70,7 @@ func DataSourceGroup() *schema.Resource { for _, x := range current.Groups { this.Groups = append(this.Groups, x.Value) if this.Recursive { - childGroup, err := groupsAPI.Read(x.Value) + childGroup, err := groupsAPI.Read(x.Value, groupAttributes) if err != nil { return diag.FromErr(err) } diff --git a/scim/data_group_test.go b/scim/data_group_test.go index 3bcf59bee9..5ecb416244 100644 --- a/scim/data_group_test.go +++ b/scim/data_group_test.go @@ -54,7 +54,7 @@ func TestDataSourceGroup(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/eerste", + Resource: "/api/2.0/preview/scim/v2/Groups/eerste?attributes=members,roles,entitlements,externalId", Response: Group{ DisplayName: "ds", ID: "eerste", @@ -91,7 +91,7 @@ func TestDataSourceGroup(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=members,roles,entitlements,externalId", Response: Group{ DisplayName: "product", ID: "abc", diff --git a/scim/data_user.go b/scim/data_user.go index 2d627a019f..9646e0ca98 100644 --- a/scim/data_user.go +++ b/scim/data_user.go @@ -11,7 +11,7 @@ import ( func getUser(usersAPI UsersAPI, id, name string) (user User, err error) { if id != "" { - return usersAPI.Read(id) + return usersAPI.Read(id, "userName,displayName,externalId,applicationId") } userList, err := usersAPI.Filter(fmt.Sprintf("userName eq '%s'", name)) if err != nil { diff --git a/scim/data_user_test.go b/scim/data_user_test.go index b79567b18b..5954c532cc 100644 --- a/scim/data_user_test.go +++ b/scim/data_user_test.go @@ -46,7 +46,7 @@ func TestDataSourceUserGerUser(t *testing.T) { qa.HTTPFixturesApply(t, []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/a", + Resource: "/api/2.0/preview/scim/v2/Users/a?attributes=userName,displayName,externalId,applicationId", Response: User{ ID: "a", }, diff --git a/scim/groups.go b/scim/groups.go index cec9d082fc..be31c40c36 100644 --- a/scim/groups.go +++ b/scim/groups.go @@ -30,8 +30,9 @@ func (a GroupsAPI) Create(scimGroupRequest Group) (group Group, err error) { } // Read reads and returns a Group object via SCIM api -func (a GroupsAPI) Read(groupID string) (group Group, err error) { - err = a.client.Scim(a.context, http.MethodGet, fmt.Sprintf("/preview/scim/v2/Groups/%v", groupID), nil, &group) +func (a GroupsAPI) Read(groupID, attributes string) (group Group, err error) { + err = a.client.Scim(a.context, http.MethodGet, fmt.Sprintf( + "/preview/scim/v2/Groups/%v?attributes=%s", groupID, attributes), nil, &group) if err != nil { return } @@ -53,7 +54,7 @@ func (a GroupsAPI) Filter(filter string, includeRoles bool) (GroupList, error) { return groups, err } -func (a GroupsAPI) ReadByDisplayName(displayName string) (group Group, err error) { +func (a GroupsAPI) ReadByDisplayName(displayName, attributes string) (group Group, err error) { groupList, err := a.Filter(fmt.Sprintf("displayName eq '%s'", displayName), false) if err != nil { return @@ -64,7 +65,7 @@ func (a GroupsAPI) ReadByDisplayName(displayName string) (group Group, err error } // We GET the group again to fetch any fields that were excluded the first // time around - return a.Read(groupList.Resources[0].ID) + return a.Read(groupList.Resources[0].ID, attributes) } func (a GroupsAPI) Patch(groupID string, r patchRequest) error { @@ -72,7 +73,7 @@ func (a GroupsAPI) Patch(groupID string, r patchRequest) error { } func (a GroupsAPI) UpdateNameAndEntitlements(groupID string, name string, externalID string, e entitlements) error { - g, err := a.Read(groupID) + g, err := a.Read(groupID, "displayName,entitlements,groups,members,externalId") if err != nil { return err } diff --git a/scim/resource_entitlement.go b/scim/resource_entitlement.go index 7844758d39..6c96a6beb8 100644 --- a/scim/resource_entitlement.go +++ b/scim/resource_entitlement.go @@ -37,13 +37,13 @@ func ResourceEntitlements() *schema.Resource { } switch strings.ToLower(split[0]) { case "group": - group, err := NewGroupsAPI(ctx, c).Read(split[1]) + group, err := NewGroupsAPI(ctx, c).Read(split[1], "entitlements") if err != nil { return err } return group.Entitlements.readIntoData(d) case "user": - user, err := NewUsersAPI(ctx, c).Read(split[1]) + user, err := NewUsersAPI(ctx, c).Read(split[1], "entitlements") if err != nil { return err } diff --git a/scim/resource_entitlement_test.go b/scim/resource_entitlement_test.go index b7725ab429..a492fd1f80 100644 --- a/scim/resource_entitlement_test.go +++ b/scim/resource_entitlement_test.go @@ -96,7 +96,7 @@ func TestResourceEntitlementsGroupCreate(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=entitlements", Response: oldGroup, }, { @@ -109,7 +109,7 @@ func TestResourceEntitlementsGroupCreate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=entitlements", Response: newGroup, }, }, @@ -134,7 +134,7 @@ func TestResourceEntitlementsGroupRead(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=entitlements", Response: oldGroup, }, }, @@ -154,7 +154,7 @@ func TestResourceEntitlementsGroupRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=entitlements", Status: 400, Response: apierr.APIErrorBody{ ScimDetail: "Something", @@ -175,7 +175,7 @@ func TestResourceEntitlementsGroupUpdate(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=entitlements", Response: oldGroup, }, { @@ -188,7 +188,7 @@ func TestResourceEntitlementsGroupUpdate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=entitlements", Response: newGroup, }, }, @@ -218,7 +218,7 @@ func TestResourceEntitlementsGroupDelete(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=entitlements", Response: oldGroup, }, { @@ -315,7 +315,7 @@ func TestResourceEntitlementsUserCreate(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=entitlements", Response: oldUser, }, { @@ -328,7 +328,7 @@ func TestResourceEntitlementsUserCreate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=entitlements", Response: newUser, }, }, @@ -353,7 +353,7 @@ func TestResourceEntitlementsUserRead(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=entitlements", Response: oldUser, }, }, @@ -373,7 +373,7 @@ func TestResourceEntitlementsUserRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=entitlements", Status: 400, Response: apierr.APIErrorBody{ ScimDetail: "Something", @@ -394,7 +394,7 @@ func TestResourceEntitlementsUserUpdate_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=entitlements", Status: 400, Response: apierr.APIErrorBody{ ScimDetail: "Something", @@ -433,7 +433,7 @@ func TestResourceEntitlementsUserUpdate(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=entitlements", Response: oldUser, }, { @@ -446,7 +446,7 @@ func TestResourceEntitlementsUserUpdate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=entitlements", Response: newUser, }, }, @@ -476,7 +476,7 @@ func TestResourceEntitlementsUserDelete(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=entitlements", Response: oldUser, }, { diff --git a/scim/resource_group.go b/scim/resource_group.go index fa49a4c344..faa1606d84 100644 --- a/scim/resource_group.go +++ b/scim/resource_group.go @@ -46,7 +46,7 @@ func ResourceGroup() *schema.Resource { return nil }, Read: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error { - group, err := NewGroupsAPI(ctx, c).Read(d.Id()) + group, err := NewGroupsAPI(ctx, c).Read(d.Id(), "displayName,externalId,entitlements") if err != nil { return err } @@ -78,7 +78,7 @@ func createForceOverridesManuallyAddedGroup(err error, d *schema.ResourceData, g if err.Error() != force { return err } - group, err := groupsAPI.ReadByDisplayName(groupName) + group, err := groupsAPI.ReadByDisplayName(groupName, "") if err != nil { return err } diff --git a/scim/resource_group_member.go b/scim/resource_group_member.go index 55e3c45584..f707b4e519 100644 --- a/scim/resource_group_member.go +++ b/scim/resource_group_member.go @@ -17,7 +17,7 @@ func ResourceGroupMember() *schema.Resource { return NewGroupsAPI(ctx, c).Patch(groupID, PatchRequest("add", "members", memberID)) }, ReadContext: func(ctx context.Context, groupID, memberID string, c *common.DatabricksClient) error { - group, err := NewGroupsAPI(ctx, c).Read(groupID) + group, err := NewGroupsAPI(ctx, c).Read(groupID, "members") hasMember := ComplexValues(group.Members).HasValue(memberID) if err == nil && !hasMember { return apierr.NotFound("Group has no member") diff --git a/scim/resource_group_member_test.go b/scim/resource_group_member_test.go index 3e4e2ff699..a99c4096c1 100644 --- a/scim/resource_group_member_test.go +++ b/scim/resource_group_member_test.go @@ -21,7 +21,7 @@ func TestResourceGroupMemberCreate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=members", Response: Group{ Schemas: []URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -74,7 +74,7 @@ func TestResourceGroupMemberRead(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=members", Response: Group{ Schemas: []URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -100,7 +100,7 @@ func TestResourceGroupMemberRead_NoMember(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=members", Response: Group{ Schemas: []URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -120,7 +120,7 @@ func TestResourceGroupMemberRead_NotFound(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=members", Response: apierr.APIErrorBody{ ErrorCode: "NOT_FOUND", Message: "Item not found", @@ -140,7 +140,7 @@ func TestResourceGroupMemberRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=members", Response: apierr.APIErrorBody{ ErrorCode: "INVALID_REQUEST", Message: "Internal error happened", diff --git a/scim/resource_group_role.go b/scim/resource_group_role.go index 46f215833b..bbebb0e2bb 100644 --- a/scim/resource_group_role.go +++ b/scim/resource_group_role.go @@ -16,7 +16,7 @@ func ResourceGroupRole() *schema.Resource { return NewGroupsAPI(ctx, c).Patch(groupID, PatchRequest("add", "roles", role)) }, ReadContext: func(ctx context.Context, groupID, role string, c *common.DatabricksClient) error { - group, err := NewGroupsAPI(ctx, c).Read(groupID) + group, err := NewGroupsAPI(ctx, c).Read(groupID, "roles") hasRole := ComplexValues(group.Roles).HasValue(role) if err == nil && !hasRole { return apierr.NotFound("Group has no role") diff --git a/scim/resource_group_role_test.go b/scim/resource_group_role_test.go index d8f65ab278..75c12179da 100644 --- a/scim/resource_group_role_test.go +++ b/scim/resource_group_role_test.go @@ -20,7 +20,7 @@ func TestResourceGroupRoleCreate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: Group{ Schemas: []URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -69,7 +69,7 @@ func TestResourceGroupRoleRead(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: Group{ Schemas: []URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -93,7 +93,7 @@ func TestResourceGroupRoleRead_NoRole(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: Group{ Schemas: []URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -113,7 +113,7 @@ func TestResourceGroupRoleRead_NotFound(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: apierr.APIErrorBody{ ErrorCode: "NOT_FOUND", Message: "Item not found", @@ -133,7 +133,7 @@ func TestResourceGroupRoleRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=roles", Response: apierr.APIErrorBody{ ErrorCode: "INVALID_REQUEST", Message: "Internal error happened", diff --git a/scim/resource_group_test.go b/scim/resource_group_test.go index c23e7c8ca9..f07bb42716 100644 --- a/scim/resource_group_test.go +++ b/scim/resource_group_test.go @@ -39,7 +39,7 @@ func TestResourceGroupCreate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=displayName,externalId,entitlements", Response: Group{ Schemas: []URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -101,7 +101,7 @@ func TestResourceGroupRead(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=displayName,externalId,entitlements", Response: Group{ Schemas: []URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -137,7 +137,7 @@ func TestResourceGroupRead_NoEntitlements(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=displayName,externalId,entitlements", Response: Group{ Schemas: []URN{"urn:ietf:params:scim:schemas:core:2.0:Group"}, DisplayName: "Data Scientists", @@ -162,7 +162,7 @@ func TestResourceGroupRead_NotFound(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=displayName,externalId,entitlements", Response: apierr.APIErrorBody{ ErrorCode: "NOT_FOUND", Message: "Item not found", @@ -182,7 +182,7 @@ func TestResourceGroupRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=displayName,externalId,entitlements", Response: apierr.APIErrorBody{ ErrorCode: "INVALID_REQUEST", Message: "Internal error happened", @@ -201,7 +201,7 @@ func TestResourceGroupUpdate(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=displayName,entitlements,groups,members,externalId", Response: Group{ Members: []ComplexValue{ { @@ -256,7 +256,7 @@ func TestResourceGroupUpdate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=displayName,externalId,entitlements", Response: Group{ DisplayName: "Data Ninjas", Entitlements: entitlements{ @@ -298,7 +298,7 @@ func TestResourceGroupUpdate_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/abc", + Resource: "/api/2.0/preview/scim/v2/Groups/abc?attributes=displayName,entitlements,groups,members,externalId", Response: apierr.APIErrorBody{ ErrorCode: "INVALID_REQUEST", Message: "Internal error happened", @@ -387,14 +387,14 @@ func TestCreateForceOverwriteFindsAndSetsGroupID(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/123", + Resource: "/api/2.0/preview/scim/v2/Groups/123?attributes=displayName,entitlements,groups,members,externalId", Response: Group{ ID: "123", }, }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Groups/123", + Resource: "/api/2.0/preview/scim/v2/Groups/123?attributes=", Response: Group{ ID: "123", }, diff --git a/scim/resource_user.go b/scim/resource_user.go index c3f8591121..042fe18550 100644 --- a/scim/resource_user.go +++ b/scim/resource_user.go @@ -81,7 +81,7 @@ func ResourceUser() *schema.Resource { return nil }, Read: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error { - user, err := NewUsersAPI(ctx, c).Read(d.Id()) + user, err := NewUsersAPI(ctx, c).Read(d.Id(), "userName,displayName,active,externalID,entitlements") if err != nil { return err } @@ -98,7 +98,7 @@ func ResourceUser() *schema.Resource { if err != nil { return err } - return NewUsersAPI(ctx, c).Update(d.Id(), u) + return NewUsersAPI(ctx, c).Update(d.Id(), "userName,displayName,active,externalID,entitlements", u) }, Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error { user := NewUsersAPI(ctx, c) @@ -146,5 +146,5 @@ func createForceOverridesManuallyAddedUser(err error, d *schema.ResourceData, us } user := userList[0] d.SetId(user.ID) - return usersAPI.Update(d.Id(), u) + return usersAPI.Update(d.Id(), "userName,displayName,active,externalID,entitlements", u) } diff --git a/scim/resource_user_test.go b/scim/resource_user_test.go index f94320ed55..1424e9c7e2 100644 --- a/scim/resource_user_test.go +++ b/scim/resource_user_test.go @@ -19,7 +19,7 @@ func TestResourceUserRead(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Response: User{ ID: "abc", DisplayName: "Example user", @@ -56,7 +56,7 @@ func TestResourceUserRead_NotFound(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Status: 404, }, }, @@ -73,7 +73,7 @@ func TestResourceUserRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Status: 400, Response: apierr.APIErrorBody{ ScimDetail: "Something", @@ -113,7 +113,7 @@ func TestResourceUserCreate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Response: User{ DisplayName: "Example user", Active: true, @@ -177,7 +177,7 @@ func TestResourceUserCreateInactive(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Response: User{ DisplayName: "Example user", Active: false, @@ -271,7 +271,7 @@ func TestResourceUserUpdate(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Response: User{ DisplayName: "Example user", Active: true, @@ -309,7 +309,7 @@ func TestResourceUserUpdate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Response: newUser, }, }, @@ -340,7 +340,7 @@ func TestResourceUserUpdate_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Status: 400, }, }, @@ -362,7 +362,7 @@ func TestResourceUserUpdate_ErrorPut(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Response: User{ DisplayName: "Example user", Active: true, @@ -658,7 +658,7 @@ func TestCreateForceOverwriteFindsAndSetsID(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Response: User{ ID: "abc", }, @@ -700,7 +700,7 @@ func TestCreateForceOverwriteFindsAndSetsAccID(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/preview/scim/v2/Users/abc", + Resource: "/api/2.0/preview/scim/v2/Users/abc?attributes=userName,displayName,active,externalID,entitlements", Response: User{ ID: "abc", }, diff --git a/scim/users.go b/scim/users.go index 78a0f636e1..7e3c09f9f8 100644 --- a/scim/users.go +++ b/scim/users.go @@ -48,8 +48,8 @@ func (a UsersAPI) Filter(filter string) (u []User, err error) { return } -func (a UsersAPI) Read(userID string) (User, error) { - userPath := fmt.Sprintf("/preview/scim/v2/Users/%v", userID) +func (a UsersAPI) Read(userID, attributes string) (User, error) { + userPath := fmt.Sprintf("/preview/scim/v2/Users/%v?attributes=%s", userID, attributes) return a.readByPath(userPath) } @@ -64,8 +64,8 @@ func (a UsersAPI) readByPath(userPath string) (user User, err error) { } // Update replaces user information for given ID -func (a UsersAPI) Update(userID string, updateRequest User) error { - user, err := a.Read(userID) +func (a UsersAPI) Update(userID, attributes string, updateRequest User) error { + user, err := a.Read(userID, attributes) if err != nil { return err }