Skip to content

Commit 2526f27

Browse files
authored
[BB-1321] Ensure caches are initialized (#12)
* Initialize collaborator_cache with mutex This will allow us to initialize and build the cache in other places safely. * cleanup * Initialize role_cache with mutex * Ensure caches are initialized in Grants() This is the only method the caches are used.
1 parent 2a516d6 commit 2526f27

File tree

5 files changed

+86
-76
lines changed

5 files changed

+86
-76
lines changed

pkg/connector/collaborator_cache.go

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package connector
33
import (
44
"context"
55
"strconv"
6+
"sync"
67

78
"github.com/conductorone/baton-workato/pkg/connector/client"
89
"github.com/conductorone/baton-workato/pkg/connector/ucache"
@@ -28,6 +29,9 @@ type collaboratorCache struct {
2829
folderToUser *ucache.HashSet[int, string, CompoundUser]
2930
roleToUser *ucache.HashSet[string, string, CompoundUser]
3031
env workato.Environment
32+
33+
initialized bool
34+
mu sync.Mutex
3135
}
3236

3337
func newCollaboratorCache(workatoClient *client.WorkatoClient, env workato.Environment) *collaboratorCache {
@@ -40,9 +44,24 @@ func newCollaboratorCache(workatoClient *client.WorkatoClient, env workato.Envir
4044
}
4145
}
4246

47+
func (p *collaboratorCache) init(ctx context.Context) error {
48+
p.mu.Lock()
49+
defer p.mu.Unlock()
50+
51+
if p.initialized {
52+
return nil
53+
}
54+
55+
if err := p.buildCache(ctx); err != nil {
56+
return err
57+
}
58+
59+
p.initialized = true
60+
return nil
61+
}
62+
4363
func (p *collaboratorCache) buildCache(ctx context.Context) error {
4464
l := ctxzap.Extract(ctx)
45-
4665
l.Info("Building cache for collaborators")
4766

4867
p.privilegeToUser = ucache.NewUCache[string, string, CompoundUser]()
@@ -102,54 +121,29 @@ func (p *collaboratorCache) buildCache(ctx context.Context) error {
102121
}
103122

104123
l.Info("Cache built for collaborators")
105-
106124
return nil
107125
}
108126

109-
// GetAllFoldersRecur is a recursive function that gets all folders in a Workato instance.
110-
func (p *collaboratorCache) GetAllFoldersRecur(ctx context.Context, parentId *int, pToken string) ([]client.Folder, error) {
111-
l := ctxzap.Extract(ctx)
112-
113-
l.Info("Building cache for folders")
114-
115-
folders, nextToken, err := p.client.GetFolders(ctx, parentId, pToken)
116-
if err != nil {
117-
return nil, err
118-
}
119-
120-
response := make([]client.Folder, 0)
121-
122-
if len(folders) == 0 {
123-
return folders, nil
124-
} else {
125-
recurResult, err := p.GetAllFoldersRecur(ctx, parentId, nextToken)
126-
if err != nil {
127-
return nil, err
128-
}
129-
130-
response = append(response, recurResult...)
131-
}
132-
133-
for _, folder := range folders {
134-
recurResult, err := p.GetAllFoldersRecur(ctx, &folder.Id, "0")
135-
if err != nil {
136-
return nil, err
137-
}
138-
139-
response = append(response, recurResult...)
127+
func (p *collaboratorCache) getUsersByPrivilege(privilegeKey string) []*CompoundUser {
128+
if !p.initialized {
129+
return nil
140130
}
141131

142-
return response, nil
143-
}
144-
145-
func (p *collaboratorCache) getUsersByPrivilege(privilegeKey string) []*CompoundUser {
146132
return p.privilegeToUser.GetAll(privilegeKey)
147133
}
148134

149135
func (p *collaboratorCache) getUsersByFolder(folderId int) []*CompoundUser {
136+
if !p.initialized {
137+
return nil
138+
}
139+
150140
return p.folderToUser.GetAll(folderId)
151141
}
152142

153143
func (p *collaboratorCache) getUsersByRole(roleName string) []*CompoundUser {
144+
if !p.initialized {
145+
return nil
146+
}
147+
154148
return p.roleToUser.GetAll(roleName)
155149
}

pkg/connector/folder.go

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,6 @@ func (o *folderBuilder) List(ctx context.Context, parentResourceID *v2.ResourceI
4242
l := ctxzap.Extract(ctx)
4343
l.Debug("Listing folders")
4444

45-
// Init cache
46-
if pToken.Token == "" && parentResourceID == nil {
47-
err := o.cache.buildCache(ctx)
48-
if err != nil {
49-
return nil, "", nil, err
50-
}
51-
52-
if !o.disableCustomRolesSync {
53-
err = o.roleCache.buildCache(ctx)
54-
if err != nil {
55-
return nil, "", nil, err
56-
}
57-
}
58-
}
59-
6045
rv := make([]*v2.Resource, 0)
6146

6247
if parentResourceID == nil {
@@ -129,6 +114,16 @@ func (o *folderBuilder) Grants(ctx context.Context, resource *v2.Resource, pToke
129114
Page int
130115
}
131116

117+
// Ensure caches are initialized
118+
if err := o.cache.init(ctx); err != nil {
119+
return nil, "", nil, err
120+
}
121+
if !o.disableCustomRolesSync {
122+
if err := o.roleCache.init(ctx); err != nil {
123+
return nil, "", nil, err
124+
}
125+
}
126+
132127
bag, err := cpagination.GenBagFromToken[Bag](*pToken)
133128
if err != nil {
134129
return nil, "", nil, err

pkg/connector/privilege.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"github.com/conductorone/baton-workato/pkg/connector/client"
99
"github.com/conductorone/baton-workato/pkg/connector/workato"
1010
"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
11-
"go.uber.org/zap"
1211

1312
v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2"
1413
"github.com/conductorone/baton-sdk/pkg/annotations"
@@ -36,14 +35,6 @@ func (o *privilegeBuilder) List(ctx context.Context, parentResourceID *v2.Resour
3635
l := ctxzap.Extract(ctx)
3736
l.Debug("Listing privileges")
3837

39-
if pToken == nil || pToken.Token == "" {
40-
err := o.cache.buildCache(ctx)
41-
if err != nil {
42-
l.Error("Error building cache", zap.Error(err))
43-
return nil, "", nil, err
44-
}
45-
}
46-
4738
privileges := workato.AllCompoundPrivileges()
4839

4940
rv := make([]*v2.Resource, 0)
@@ -74,6 +65,11 @@ func (o *privilegeBuilder) Entitlements(_ context.Context, resource *v2.Resource
7465

7566
// Grants always returns an empty slice for users since they don't have any entitlements.
7667
func (o *privilegeBuilder) Grants(ctx context.Context, resource *v2.Resource, pToken *pagination.Token) ([]*v2.Grant, string, annotations.Annotations, error) {
68+
// Ensure cache is initialized
69+
if err := o.cache.init(ctx); err != nil {
70+
return nil, "", nil, err
71+
}
72+
7773
privilegeId := resource.Id.Resource
7874

7975
users := o.cache.getUsersByPrivilege(privilegeId)

pkg/connector/role.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,6 @@ func (o *roleBuilder) List(ctx context.Context, parentResourceID *v2.ResourceId,
4242
l := ctxzap.Extract(ctx)
4343
l.Debug("Listing roles")
4444

45-
if pToken.Token == "" {
46-
err := o.cache.buildCache(ctx)
47-
if err != nil {
48-
return nil, "", nil, err
49-
}
50-
51-
if !o.disableCustomRolesSync {
52-
err = o.roleCache.buildCache(ctx)
53-
if err != nil {
54-
return nil, "", nil, err
55-
}
56-
}
57-
}
58-
5945
rv := make([]*v2.Resource, 0)
6046

6147
var nextToken string
@@ -106,6 +92,17 @@ func (o *roleBuilder) Entitlements(_ context.Context, resource *v2.Resource, _ *
10692
// Grants always returns an empty slice for users since they don't have any entitlements.
10793
func (o *roleBuilder) Grants(ctx context.Context, resource *v2.Resource, pToken *pagination.Token) ([]*v2.Grant, string, annotations.Annotations, error) {
10894
l := ctxzap.Extract(ctx)
95+
96+
// Ensure caches are initialized
97+
if err := o.cache.init(ctx); err != nil {
98+
return nil, "", nil, err
99+
}
100+
if !o.disableCustomRolesSync {
101+
if err := o.roleCache.init(ctx); err != nil {
102+
return nil, "", nil, err
103+
}
104+
}
105+
109106
// Since roles names are unique, we can use the role name as the key to get all the users that have that role.
110107
collaborators := o.cache.getUsersByRole(resource.DisplayName)
111108

pkg/connector/role_cache.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package connector
33
import (
44
"context"
55
"strconv"
6+
"sync"
67

78
"github.com/conductorone/baton-workato/pkg/connector/client"
89
"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
@@ -13,6 +14,9 @@ type roleCache struct {
1314
client *client.WorkatoClient
1415
folderToRole map[int][]*client.Role
1516
roles map[string]*client.Role
17+
18+
initialized bool
19+
mu sync.Mutex
1620
}
1721

1822
func newRoleCache(workatoClient *client.WorkatoClient) *roleCache {
@@ -23,6 +27,22 @@ func newRoleCache(workatoClient *client.WorkatoClient) *roleCache {
2327
}
2428
}
2529

30+
func (p *roleCache) init(ctx context.Context) error {
31+
p.mu.Lock()
32+
defer p.mu.Unlock()
33+
34+
if p.initialized {
35+
return nil
36+
}
37+
38+
if err := p.buildCache(ctx); err != nil {
39+
return err
40+
}
41+
42+
p.initialized = true
43+
return nil
44+
}
45+
2646
func (p *roleCache) buildCache(ctx context.Context) error {
2747
l := ctxzap.Extract(ctx)
2848

@@ -61,15 +81,23 @@ func (p *roleCache) buildCache(ctx context.Context) error {
6181
}
6282

6383
func (p *roleCache) getRoleByFolder(folderId int) []*client.Role {
84+
if !p.initialized {
85+
return nil
86+
}
87+
6488
value, ok := p.folderToRole[folderId]
6589
if !ok {
66-
return make([]*client.Role, 0)
90+
return nil
6791
}
6892

6993
return value
7094
}
7195

7296
func (p *roleCache) getRoleById(id string) *client.Role {
97+
if !p.initialized {
98+
return nil
99+
}
100+
73101
value, ok := p.roles[id]
74102
if !ok {
75103
return nil

0 commit comments

Comments
 (0)