diff --git a/.golangci.yml b/.golangci.yml index 4ab47e29..61afa947 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -50,9 +50,6 @@ linters-settings: tenv: all: true - varcheck: - exported-fields: false # this appears to improperly detect exported variables as unused when they are used from a package with the same name - linters: disable-all: true diff --git a/pkg/connector/account.go b/pkg/connector/account.go index f840ae85..651494cb 100644 --- a/pkg/connector/account.go +++ b/pkg/connector/account.go @@ -35,9 +35,8 @@ const ( ) type accountBuilder struct { - client *databricks.Client - resourceType *v2.ResourceType - resourceCache *ResourceCache + client *databricks.Client + resourceType *v2.ResourceType } func (a *accountBuilder) ResourceType(ctx context.Context) *v2.ResourceType { @@ -133,12 +132,12 @@ func (a *accountBuilder) Grants(ctx context.Context, resource *v2.Resource, pTok var annotations []protoreflect.ProtoMessage if resourceId.ResourceType == groupResourceType.Id { - memberResource, annotation, err := a.resourceCache.ExpandGrantForGroup(ctx, "", resourceId.Resource) + rid, expandAnnotation, err := groupGrantExpansion(ctx, resourceId.Resource, resource.ParentResourceId) if err != nil { - return nil, "", nil, fmt.Errorf("databricks-connector: failed to expand grant for group %s: %w", resourceId.Resource, err) + return rv, "", nil, err } - annotations = append(annotations, annotation) - resourceId = memberResource.Id + resourceId = rid + annotations = append(annotations, expandAnnotation) } rv = append(rv, grant.NewGrant(resource, MarketplaceAdminRole, resourceId, grant.WithAnnotation(annotations...))) @@ -282,10 +281,9 @@ func (a *accountBuilder) Revoke(ctx context.Context, grant *v2.Grant) (annotatio return nil, nil } -func newAccountBuilder(client *databricks.Client, resourceCache *ResourceCache) *accountBuilder { +func newAccountBuilder(client *databricks.Client) *accountBuilder { return &accountBuilder{ - client: client, - resourceType: accountResourceType, - resourceCache: resourceCache, + client: client, + resourceType: accountResourceType, } } diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 1f1a7507..cefe4d85 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -12,20 +12,19 @@ import ( ) type Databricks struct { - client *databricks.Client - workspaces []string - resourceCache *ResourceCache + client *databricks.Client + workspaces []string } // ResourceSyncers returns a ResourceSyncer for each resource type that should be synced from the upstream service. func (d *Databricks) ResourceSyncers(ctx context.Context) []connectorbuilder.ResourceSyncer { return []connectorbuilder.ResourceSyncer{ - newAccountBuilder(d.client, d.resourceCache), - newGroupBuilder(d.client, d.resourceCache), - newServicePrincipalBuilder(d.client, d.resourceCache), - newUserBuilder(d.client, d.resourceCache), - newWorkspaceBuilder(d.client, d.resourceCache, d.workspaces), - newRoleBuilder(d.client, d.resourceCache), + newAccountBuilder(d.client), + newGroupBuilder(d.client), + newServicePrincipalBuilder(d.client), + newUserBuilder(d.client), + newWorkspaceBuilder(d.client, d.workspaces), + newRoleBuilder(d.client), } } @@ -117,8 +116,7 @@ func New( } return &Databricks{ - client: client, - workspaces: workspaces, - resourceCache: NewResourceCache(client), + client: client, + workspaces: workspaces, }, nil } diff --git a/pkg/connector/groups.go b/pkg/connector/groups.go index c6589f59..2595d140 100644 --- a/pkg/connector/groups.go +++ b/pkg/connector/groups.go @@ -21,16 +21,23 @@ import ( const groupMemberEntitlement = "member" type groupBuilder struct { - client *databricks.Client - resourceType *v2.ResourceType - resourceCache *ResourceCache + client *databricks.Client + resourceType *v2.ResourceType } func (g *groupBuilder) ResourceType(ctx context.Context) *v2.ResourceType { return groupResourceType } -func groupResource(_ context.Context, group *databricks.Group, parent *v2.ResourceId) (*v2.Resource, error) { +func groupResourceId(_ context.Context, groupId string, parentResourceId *v2.ResourceId) string { + if parentResourceId == nil { + return strings.Join([]string{groupResourceType.Id, groupId}, "/") + } + + return strings.Join([]string{parentResourceId.ResourceType, parentResourceId.Resource, groupResourceType.Id, groupId}, "/") +} + +func groupResource(ctx context.Context, group *databricks.Group, parent *v2.ResourceId) (*v2.Resource, error) { members := make([]string, len(group.Members)) for i, member := range group.Members { @@ -54,11 +61,10 @@ func groupResource(_ context.Context, group *databricks.Group, parent *v2.Resour } var options []rs.ResourceOption - groupId := strings.Join([]string{groupResourceType.Id, group.ID}, "/") if parent != nil { - groupId = strings.Join([]string{parent.ResourceType, parent.Resource, groupResourceType.Id, group.ID}, "/") options = append(options, rs.WithParentResourceID(parent)) } + groupId := groupResourceId(ctx, group.ID, parent) resource, err := rs.NewGroupResource( group.DisplayName, @@ -110,7 +116,6 @@ func (g *groupBuilder) List(ctx context.Context, parentResourceID *v2.ResourceId if err != nil { return nil, "", nil, err } - g.resourceCache.Set(group.ID, gr) rv = append(rv, gr) } @@ -210,12 +215,12 @@ func (g *groupBuilder) Grants(ctx context.Context, resource *v2.Resource, pToken case "Users": resourceId = &v2.ResourceId{ResourceType: userResourceType.Id, Resource: memberID} case "Groups": - memberResource, annotation, err := g.resourceCache.ExpandGrantForGroup(ctx, workspaceId, memberID) + rid, expandAnnotation, err := groupGrantExpansion(ctx, memberID, parentId) if err != nil { - return nil, "", nil, fmt.Errorf("databricks-connector: failed to expand grant for group %s: %w", memberID, err) + return rv, "", nil, err } - anns = append(anns, annotation) - resourceId = memberResource.Id + resourceId = rid + anns = append(anns, expandAnnotation) case "ServicePrincipals": resourceId = &v2.ResourceId{ResourceType: servicePrincipalResourceType.Id, Resource: memberID} default: @@ -240,12 +245,12 @@ func (g *groupBuilder) Grants(ctx context.Context, resource *v2.Resource, pToken } var annotations []protoreflect.ProtoMessage if resourceId.ResourceType == groupResourceType.Id { - memberResource, annotation, err := g.resourceCache.ExpandGrantForGroup(ctx, workspaceId, resourceId.Resource) + rid, expandAnnotation, err := groupGrantExpansion(ctx, resourceId.Resource, resource.ParentResourceId) if err != nil { - return nil, "", nil, fmt.Errorf("databricks-connector: failed to expand grant for group %s: %w", resourceId.Resource, err) + return rv, "", nil, err } - annotations = append(annotations, annotation) - resourceId = memberResource.Id + resourceId = rid + annotations = append(annotations, expandAnnotation) } rv = append(rv, grant.NewGrant(resource, ruleSet.Role, resourceId, grant.WithAnnotation(annotations...))) @@ -471,10 +476,9 @@ func (g *groupBuilder) Revoke(ctx context.Context, grant *v2.Grant) (annotations return nil, nil } -func newGroupBuilder(client *databricks.Client, resourceCache *ResourceCache) *groupBuilder { +func newGroupBuilder(client *databricks.Client) *groupBuilder { return &groupBuilder{ - client: client, - resourceType: groupResourceType, - resourceCache: resourceCache, + client: client, + resourceType: groupResourceType, } } diff --git a/pkg/connector/helpers.go b/pkg/connector/helpers.go index 2f550525..54874a57 100644 --- a/pkg/connector/helpers.go +++ b/pkg/connector/helpers.go @@ -35,43 +35,15 @@ func parseResourceId(resourceId string) (*v2.ResourceId, *v2.ResourceId, error) return nil, nil, fmt.Errorf("invalid resource ID: %s", resourceId) } -type ResourceCache struct { - // Map of API IDs to resources - resources map[string]*v2.Resource - client *databricks.Client -} - -func (c *ResourceCache) Get(resourceId string) *v2.Resource { - return c.resources[resourceId] -} - -func (c *ResourceCache) Set(resourceId string, resource *v2.Resource) { - c.resources[resourceId] = resource -} - -func NewResourceCache(client *databricks.Client) *ResourceCache { - return &ResourceCache{ - resources: make(map[string]*v2.Resource), - client: client, - } -} - -func (c *ResourceCache) ExpandGrantForGroup(ctx context.Context, workspaceId, groupId string) (*v2.Resource, *v2.GrantExpandable, error) { - memberResource := c.Get(groupId) - if memberResource == nil { - group, _, err := c.client.GetGroup(context.Background(), workspaceId, groupId) - if err != nil { - return nil, nil, fmt.Errorf("databricks-connector: failed to get group %s: %w", groupId, err) - } - memberResource, err = groupResource(ctx, group, nil) - if err != nil { - return nil, nil, fmt.Errorf("databricks-connector: failed to get group %s: %w", groupId, err) - } - c.Set(groupId, memberResource) +func groupGrantExpansion(ctx context.Context, groupId string, parentResource *v2.ResourceId) (*v2.ResourceId, *v2.GrantExpandable, error) { + groupResourceStr := groupResourceId(ctx, groupId, parentResource) + resourceId, err := rs.NewResourceID(groupResourceType, groupResourceStr) + if err != nil { + return nil, nil, err } - return memberResource, &v2.GrantExpandable{ - EntitlementIds: []string{fmt.Sprintf("group:%s:%s", memberResource.Id.Resource, groupMemberEntitlement)}, + return resourceId, &v2.GrantExpandable{ + EntitlementIds: []string{fmt.Sprintf("group:%s:%s", groupResourceStr, groupMemberEntitlement)}, }, nil } diff --git a/pkg/connector/roles.go b/pkg/connector/roles.go index fb4fb72c..7710acd1 100644 --- a/pkg/connector/roles.go +++ b/pkg/connector/roles.go @@ -33,9 +33,8 @@ var entitlements = []string{ } type roleBuilder struct { - client *databricks.Client - resourceType *v2.ResourceType - resourceCache *ResourceCache + client *databricks.Client + resourceType *v2.ResourceType } func (r *roleBuilder) ResourceType(ctx context.Context) *v2.ResourceType { @@ -233,11 +232,17 @@ func (r *roleBuilder) Grants(ctx context.Context, resource *v2.Resource, pToken } if (!isWorkspaceRole && g.HaveRole(roleName)) || (isWorkspaceRole && g.HaveEntitlement(roleName)) { - memberResource, annotation, err := r.resourceCache.ExpandGrantForGroup(ctx, workspaceId, g.ID) + accountId := r.client.GetAccountId() + accountResourceId, err := rs.NewResourceID(accountResourceType, accountId) if err != nil { - return nil, "", nil, fmt.Errorf("databricks-connector: failed to expand grant for group %s: %w", g.ID, err) + return rv, "", nil, err } - rv = append(rv, grant.NewGrant(resource, RoleMemberEntitlement, memberResource.Id, grant.WithAnnotation(annotation))) + resourceId, expandAnnotation, err := groupGrantExpansion(ctx, g.ID, accountResourceId) + if err != nil { + return rv, "", nil, err + } + + rv = append(rv, grant.NewGrant(resource, RoleMemberEntitlement, resourceId, grant.WithAnnotation(expandAnnotation))) } } @@ -454,10 +459,9 @@ func (r *roleBuilder) Revoke(ctx context.Context, grant *v2.Grant) (annotations. return nil, nil } -func newRoleBuilder(client *databricks.Client, resourceCache *ResourceCache) *roleBuilder { +func newRoleBuilder(client *databricks.Client) *roleBuilder { return &roleBuilder{ - client: client, - resourceType: roleResourceType, - resourceCache: resourceCache, + client: client, + resourceType: roleResourceType, } } diff --git a/pkg/connector/service-principals.go b/pkg/connector/service-principals.go index 13b016ff..a7b1f7f8 100644 --- a/pkg/connector/service-principals.go +++ b/pkg/connector/service-principals.go @@ -18,9 +18,8 @@ import ( ) type servicePrincipalBuilder struct { - client *databricks.Client - resourceType *v2.ResourceType - resourceCache *ResourceCache + client *databricks.Client + resourceType *v2.ResourceType } func (s *servicePrincipalBuilder) ResourceType(ctx context.Context) *v2.ResourceType { @@ -57,7 +56,6 @@ func (s *servicePrincipalBuilder) servicePrincipalResource(ctx context.Context, return nil, err } - s.resourceCache.Set(servicePrincipal.ID, resource) return resource, nil } @@ -190,12 +188,14 @@ func (s *servicePrincipalBuilder) Grants(ctx context.Context, resource *v2.Resou var annotations []protoreflect.ProtoMessage if resourceId.ResourceType == groupResourceType.Id { - memberResource, annotation, err := s.resourceCache.ExpandGrantForGroup(ctx, workspaceId, resourceId.Resource) + groupResourceStr := groupResourceId(ctx, resourceId.Resource, resource.ParentResourceId) + annotations = append(annotations, &v2.GrantExpandable{ + EntitlementIds: []string{fmt.Sprintf("group:%s:%s", groupResourceStr, groupMemberEntitlement)}, + }) + resourceId, err = rs.NewResourceID(groupResourceType, groupResourceStr) if err != nil { - return nil, "", nil, fmt.Errorf("databricks-connector: failed to expand grant for group %s: %w", resourceId.Resource, err) + return rv, "", nil, err } - annotations = append(annotations, annotation) - resourceId = memberResource.Id } rv = append(rv, grant.NewGrant(resource, ruleSet.Role, resourceId, grant.WithAnnotation(annotations...))) @@ -376,10 +376,9 @@ func (s *servicePrincipalBuilder) Revoke(ctx context.Context, grant *v2.Grant) ( return nil, nil } -func newServicePrincipalBuilder(client *databricks.Client, resourceCache *ResourceCache) *servicePrincipalBuilder { +func newServicePrincipalBuilder(client *databricks.Client) *servicePrincipalBuilder { return &servicePrincipalBuilder{ - client: client, - resourceType: servicePrincipalResourceType, - resourceCache: resourceCache, + client: client, + resourceType: servicePrincipalResourceType, } } diff --git a/pkg/connector/users.go b/pkg/connector/users.go index 0eed6772..a51faeb1 100644 --- a/pkg/connector/users.go +++ b/pkg/connector/users.go @@ -12,9 +12,8 @@ import ( ) type userBuilder struct { - client *databricks.Client - resourceType *v2.ResourceType - resourceCache *ResourceCache + client *databricks.Client + resourceType *v2.ResourceType } func (u *userBuilder) ResourceType(ctx context.Context) *v2.ResourceType { @@ -78,8 +77,6 @@ func (u *userBuilder) userResource(ctx context.Context, user *databricks.User, p return nil, err } - u.resourceCache.Set(user.ID, resource) - return resource, nil } @@ -159,10 +156,9 @@ func (u *userBuilder) Grants( return nil, "", nil, nil } -func newUserBuilder(client *databricks.Client, resourceCache *ResourceCache) *userBuilder { +func newUserBuilder(client *databricks.Client) *userBuilder { return &userBuilder{ - client: client, - resourceType: userResourceType, - resourceCache: resourceCache, + client: client, + resourceType: userResourceType, } } diff --git a/pkg/connector/workspaces.go b/pkg/connector/workspaces.go index 9b178ca2..4fedaf1c 100644 --- a/pkg/connector/workspaces.go +++ b/pkg/connector/workspaces.go @@ -20,10 +20,9 @@ import ( const workspaceMemberEntitlement = "member" type workspaceBuilder struct { - client *databricks.Client - resourceType *v2.ResourceType - workspaces map[string]struct{} - resourceCache *ResourceCache + client *databricks.Client + resourceType *v2.ResourceType + workspaces map[string]struct{} } func (w *workspaceBuilder) ResourceType(ctx context.Context) *v2.ResourceType { @@ -155,12 +154,12 @@ func (w *workspaceBuilder) Grants(ctx context.Context, resource *v2.Resource, pT return nil, "", nil, fmt.Errorf("databricks-connector: failed to get group trait: %w", err) } - workspaceID, ok := rs.GetProfileInt64Value(groupTrait.Profile, "workspace_id") + workspaceId, ok := rs.GetProfileInt64Value(groupTrait.Profile, "workspace_id") if !ok { return nil, "", nil, fmt.Errorf("databricks-connector: failed to get workspace ID: %w", err) } - workspace := strconv.Itoa(int(workspaceID)) + workspace := strconv.Itoa(int(workspaceId)) assignments, _, err := w.client.ListWorkspaceMembers(ctx, workspace) if err != nil { return nil, "", nil, fmt.Errorf("databricks-connector: failed to list workspace members: %w", err) @@ -180,12 +179,12 @@ func (w *workspaceBuilder) Grants(ctx context.Context, resource *v2.Resource, pT var annotations []protoreflect.ProtoMessage if resourceType == groupResourceType { - memberResource, annotation, err := w.resourceCache.ExpandGrantForGroup(ctx, workspace, resourceID.Resource) + rid, expandAnnotation, err := groupGrantExpansion(ctx, resourceID.Resource, resource.ParentResourceId) if err != nil { - return nil, "", nil, fmt.Errorf("databricks-connector: failed to expand grant for group %s: %w", resourceID.Resource, err) + return rv, "", nil, err } - annotations = append(annotations, annotation) - resourceID = memberResource.Id + resourceID = rid + annotations = append(annotations, expandAnnotation) } rv = append(rv, grant.NewGrant(resource, workspaceMemberEntitlement, resourceID, grant.WithAnnotation(annotations...))) @@ -261,16 +260,15 @@ func (w *workspaceBuilder) Revoke(ctx context.Context, grant *v2.Grant) (annotat return nil, nil } -func newWorkspaceBuilder(client *databricks.Client, resourceCache *ResourceCache, workspaces []string) *workspaceBuilder { +func newWorkspaceBuilder(client *databricks.Client, workspaces []string) *workspaceBuilder { wMap := make(map[string]struct{}, len(workspaces)) for _, w := range workspaces { wMap[w] = struct{}{} } return &workspaceBuilder{ - client: client, - resourceType: workspaceResourceType, - workspaces: wMap, - resourceCache: resourceCache, + client: client, + resourceType: workspaceResourceType, + workspaces: wMap, } }