Skip to content

Commit

Permalink
Add ACL operations to FS interface
Browse files Browse the repository at this point in the history
  • Loading branch information
iychoi committed Mar 8, 2021
1 parent 4591f87 commit 8b1d6df
Show file tree
Hide file tree
Showing 3 changed files with 284 additions and 9 deletions.
41 changes: 33 additions & 8 deletions fs/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,32 @@ import (
"fmt"
"time"

"github.com/cyverse/go-irodsclient/irods/types"
"github.com/cyverse/go-irodsclient/irods/util"
gocache "github.com/patrickmn/go-cache"
)

// FileSystemCache ...
type FileSystemCache struct {
CacheTimeout time.Duration
CleanupTimeout time.Duration
EntryCache *gocache.Cache
DirCache *gocache.Cache
CacheTimeout time.Duration
CleanupTimeout time.Duration
EntryCache *gocache.Cache
DirCache *gocache.Cache
GroupUsersCache *gocache.Cache
}

// NewFileSystemCache creates a new FileSystemCache
func NewFileSystemCache(cacheTimeout time.Duration, cleanup time.Duration) *FileSystemCache {
entryCache := gocache.New(cacheTimeout, cleanup)
dirCache := gocache.New(cacheTimeout, cleanup)
groupUsersCache := gocache.New(cacheTimeout, cleanup)

return &FileSystemCache{
CacheTimeout: cacheTimeout,
CleanupTimeout: cleanup,
EntryCache: entryCache,
DirCache: dirCache,
CacheTimeout: cacheTimeout,
CleanupTimeout: cleanup,
EntryCache: entryCache,
DirCache: dirCache,
GroupUsersCache: groupUsersCache,
}
}

Expand Down Expand Up @@ -110,3 +114,24 @@ func (cache *FileSystemCache) GetDirCache(path string) []string {
func (cache *FileSystemCache) ClearDirCache() {
cache.DirCache.Flush()
}

// AddGroupUsersCache ...
func (cache *FileSystemCache) AddGroupUsersCache(group string, users []types.IRODSUser) {
cache.GroupUsersCache.Set(group, users, 0)
}

// RemoveGroupUsersCache ...
func (cache *FileSystemCache) RemoveGroupUsersCache(group string) {
cache.GroupUsersCache.Delete(group)
}

// GetGroupUsersCache ...
func (cache *FileSystemCache) GetGroupUsersCache(group string) []types.IRODSUser {
users, exist := cache.GroupUsersCache.Get(group)
if exist {
if irodsUsers, ok := users.([]types.IRODSUser); ok {
return irodsUsers
}
}
return nil
}
230 changes: 230 additions & 0 deletions fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,43 @@ func (fs *FileSystem) Release() {
fs.Session.Release()
}

func (fs *FileSystem) ListGroupUsers(group string) ([]*types.IRODSUser, error) {
// check cache first
cachedUsers := fs.Cache.GetGroupUsersCache(group)
if cachedUsers != nil {
// convert it to pointer arrays
userArray := []*types.IRODSUser{}
for _, cu := range cachedUsers {
userArray = append(userArray, &cu)
}

return userArray, nil
}

// otherwise, retrieve it and add it to cache
conn, err := fs.Session.AcquireConnection()
if err != nil {
return nil, err
}
defer fs.Session.ReturnConnection(conn)

users, err := irods_fs.ListGroupUsers(conn, group)
if err != nil {
return nil, err
}

// cache it
// convert it to arrays
userArray := []types.IRODSUser{}
for _, u := range users {
userArray = append(userArray, *u)
}

fs.Cache.AddGroupUsersCache(group, userArray)

return users, nil
}

// Stat returns file status
func (fs *FileSystem) Stat(path string) (*FSEntry, error) {
dirStat, err := fs.StatDir(path)
Expand Down Expand Up @@ -127,6 +164,199 @@ func (fs *FileSystem) ExistsFile(path string) bool {
return false
}

// ListACLs returns ACLs
func (fs *FileSystem) ListACLs(path string) ([]*types.IRODSAccess, error) {
stat, err := fs.Stat(path)
if err != nil {
return nil, err
}

if stat.Type == FSDirectoryEntry {
return fs.ListDirACLs(path)
} else if stat.Type == FSFileEntry {
return fs.ListFileACLs(path)
} else {
return nil, fmt.Errorf("Unknown type - %s", stat.Type)
}
}

// ListACLsWithGroupUsers returns ACLs
func (fs *FileSystem) ListACLsWithGroupUsers(path string) ([]*types.IRODSAccess, error) {
stat, err := fs.Stat(path)
if err != nil {
return nil, err
}

accesses := []*types.IRODSAccess{}
if stat.Type == FSDirectoryEntry {
accessList, err := fs.ListDirACLsWithGroupUsers(path)
if err != nil {
return nil, err
}

accesses = append(accesses, accessList...)
} else if stat.Type == FSFileEntry {
accessList, err := fs.ListFileACLsWithGroupUsers(path)
if err != nil {
return nil, err
}

accesses = append(accesses, accessList...)
} else {
return nil, fmt.Errorf("Unknown type - %s", stat.Type)
}

return accesses, nil
}

// ListDirACLs returns ACLs of a directory
func (fs *FileSystem) ListDirACLs(path string) ([]*types.IRODSAccess, error) {
irodsPath := util.GetCorrectIRODSPath(path)

conn, err := fs.Session.AcquireConnection()
if err != nil {
return nil, err
}
defer fs.Session.ReturnConnection(conn)

accesses, err := irods_fs.ListCollectionAccess(conn, irodsPath)
if err != nil {
return nil, err
}

return accesses, nil
}

// ListDirACLsWithGroupUsers returns ACLs of a directory
func (fs *FileSystem) ListDirACLsWithGroupUsers(path string) ([]*types.IRODSAccess, error) {
irodsPath := util.GetCorrectIRODSPath(path)

conn, err := fs.Session.AcquireConnection()
if err != nil {
return nil, err
}
defer fs.Session.ReturnConnection(conn)

accesses, err := irods_fs.ListCollectionAccess(conn, irodsPath)
if err != nil {
return nil, err
}

newAccesses := []*types.IRODSAccess{}
newAccessesMap := map[string]*types.IRODSAccess{}

for _, access := range accesses {
if access.UserType == types.IRODSUserRodsGroup {
// retrieve all users in the group
users, err := fs.ListGroupUsers(access.UserName)
if err != nil {
return nil, err
}

for _, user := range users {
userAccess := &types.IRODSAccess{
Path: access.Path,
UserName: user.Name,
UserZone: user.Zone,
UserType: user.Type,
AccessLevel: access.AccessLevel,
}

// remove duplicates
newAccessesMap[fmt.Sprintf("%s||%s", user.Name, access.AccessLevel)] = userAccess
}
} else {
newAccessesMap[fmt.Sprintf("%s||%s", access.UserName, access.AccessLevel)] = access
}
}

// convert map to array
for _, access := range newAccessesMap {
newAccesses = append(newAccesses, access)
}

return newAccesses, nil
}

// ListFileACLs returns ACLs of a file
func (fs *FileSystem) ListFileACLs(path string) ([]*types.IRODSAccess, error) {
irodsPath := util.GetCorrectIRODSPath(path)

conn, err := fs.Session.AcquireConnection()
if err != nil {
return nil, err
}
defer fs.Session.ReturnConnection(conn)

collection, err := fs.getCollection(util.GetIRODSPathDirname(irodsPath))
if err != nil {
return nil, err
}

accesses, err := irods_fs.ListDataObjectAccess(conn, collection.Internal.(*types.IRODSCollection), util.GetIRODSPathFileName(irodsPath))
if err != nil {
return nil, err
}

return accesses, nil
}

// ListFileACLsWithGroupUsers returns ACLs of a file
func (fs *FileSystem) ListFileACLsWithGroupUsers(path string) ([]*types.IRODSAccess, error) {
irodsPath := util.GetCorrectIRODSPath(path)

conn, err := fs.Session.AcquireConnection()
if err != nil {
return nil, err
}
defer fs.Session.ReturnConnection(conn)

collection, err := fs.getCollection(util.GetIRODSPathDirname(irodsPath))
if err != nil {
return nil, err
}

accesses, err := irods_fs.ListDataObjectAccess(conn, collection.Internal.(*types.IRODSCollection), util.GetIRODSPathFileName(irodsPath))
if err != nil {
return nil, err
}

newAccesses := []*types.IRODSAccess{}
newAccessesMap := map[string]*types.IRODSAccess{}

for _, access := range accesses {
if access.UserType == types.IRODSUserRodsGroup {
// retrieve all users in the group
users, err := fs.ListGroupUsers(access.UserName)
if err != nil {
return nil, err
}

for _, user := range users {
userAccess := &types.IRODSAccess{
Path: access.Path,
UserName: user.Name,
UserZone: user.Zone,
UserType: user.Type,
AccessLevel: access.AccessLevel,
}

// remove duplicates
newAccessesMap[fmt.Sprintf("%s||%s", user.Name, access.AccessLevel)] = userAccess
}
} else {
newAccessesMap[fmt.Sprintf("%s||%s", access.UserName, access.AccessLevel)] = access
}
}

// convert map to array
for _, access := range newAccessesMap {
newAccesses = append(newAccesses, access)
}

return newAccesses, nil
}

// List lists all file system entries under the given path
func (fs *FileSystem) List(path string) ([]*FSEntry, error) {
irodsPath := util.GetCorrectIRODSPath(path)
Expand Down
22 changes: 21 additions & 1 deletion fs/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var (
func setup() {
util.SetLogLevel(9)

yaml, err := ioutil.ReadFile("../../config/test_account.yml")
yaml, err := ioutil.ReadFile("../config/test_account.yml")
if err != nil {
util.LogErrorf("err - %v", err)
panic(err)
Expand Down Expand Up @@ -59,6 +59,26 @@ func TestListEntries(t *testing.T) {
shutdown()
}

func TestListACLs(t *testing.T) {
setup()

acls, err := fs.ListACLsWithGroupUsers("/iplant/home/iychoi/bench.tmp")
if err != nil {
t.Errorf("err - %v", err)
panic(err)
}

if len(acls) == 0 {
util.LogDebug("There is no acls")
} else {
for _, acl := range acls {
util.LogDebugf("ACL : %v", acl)
}
}

shutdown()
}

func TestReadWrite(t *testing.T) {
setup()

Expand Down

0 comments on commit 8b1d6df

Please sign in to comment.