Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
28 changes: 26 additions & 2 deletions lib/vsc/administration/vo.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from vsc.config.base import (
VSC, VSC_HOME, VSC_DATA, VSC_DATA_SHARED, NEW, MODIFIED, MODIFY, ACTIVE, GENT, DATA_KEY, SCRATCH_KEY,
DEFAULT_VOS_ALL, VSC_PRODUCTION_SCRATCH, INSTITUTE_VOS_BY_INSTITUTE, VO_SHARED_PREFIX_BY_INSTITUTE,
VO_PREFIX_BY_INSTITUTE, STORAGE_SHARED_SUFFIX
VO_PREFIX_BY_INSTITUTE, STORAGE_ACL_VO_MOD_GRP_KEY, STORAGE_SHARED_SUFFIX,
)
from vsc.utils.missing import Monoid, MonoidDict

Expand Down Expand Up @@ -92,7 +92,7 @@ def __init__(self, vo_id, storage=None, rest_client=None, host_institute=GENT):
self._vo_data_shared_quota_cache = None
self._vo_scratch_quota_cache = None
self._institute_quota_cache = None

self._modgroup_cache = None
self._sharing_group_cache = None

@property
Expand Down Expand Up @@ -164,6 +164,20 @@ def members(self):
"""Return a list with all the VO members in it."""
return self.vo.members

@property
def modgroup(self):
"""
Return dict with Moderator group of the VO
{vsc_id: str, vsc_id_number: int, status: str, institute: {name: str},
members: [], moderators: [], description: str, active: bool, isactive: bool}
"""
if not self._modgroup_cache:
self._modgroup_cache = whenHTTPErrorRaise(
self.rest_client.vo[self.vo.vsc_id].modgroup.get,
f"Could not get modgroup information from accountpage for VO {self.vo.vsc_id}"
)[1]
return self._modgroup_cache

def _get_path(self, storage_name, mount_point=MOUNT_POINT_DEFAULT):
"""Get the path for the (if any) user directory on the given storage."""
(path, _) = self.storage.path_templates[self.host_institute][storage_name]['vo'](self.vo.vsc_id)
Expand Down Expand Up @@ -200,6 +214,16 @@ def _create_vo_fileset(self, storage, path, parent_fileset=None, fileset_name=No
else:
storage.operator().chown(moderator.vsc_id_number, fileset_group_owner_id, path)

# add ACLs to control access to VO by moderator group
if storage.acl_permissions_vo:
# replace placeholders in ACLs with actual values
acl_template_values = {
STORAGE_ACL_VO_MOD_GRP_KEY: self.modgroup['vsc_id_number'],
}
acl_rules = [rule.format(**acl_template_values) for rule in storage.acl_permissions_vo]
logging.debug(f"Setting ACLs on VO {self.vo.vsc_id} root directory: {', '.join(acl_rules)}")
storage.operator().replace_acl(path, acl_rules)

def create_data_fileset(self):
"""Create the VO's directory on the HPC data filesystem. Always set the quota."""
path = self._data_path()
Expand Down
6 changes: 6 additions & 0 deletions test/filesystem_info.conf
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ quota_user_inode=40000
quota_vo_inode=1048576
user_path=/data
operator_config_file=test/oceanstor_api.conf
acl_permissions_vo=
A:d:OWNER@:rwaDdxtTnNcoy
A:fdg:{vo_mod_gid}:rwaDdxtTnNcoy

[BRUSSEL_VSC_SCRATCH_RHEA]
cluster=storage
Expand All @@ -127,6 +130,9 @@ quota_user_inode=40000
quota_vo_inode=1048576
data_replication_factor=1
user_path=/rhea/scratch
acl_permissions_vo=
A:d:OWNER@:rwaDdxtTnNcoy
A:fdg:{vo_mod_gid}:rwaDdxtTnNcoy

[GENT_VSC_SCRATCH_MUK]
cluster=muk
Expand Down
26 changes: 26 additions & 0 deletions test/vo.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,13 @@ def test_process_brussel_vo(self, mock_client):
},
],
)
mc.vo[test_vo_id].modgroup.get.return_value = (
200,
{
'vsc_id': 'bvo99999_mods',
'vsc_id_number': 9999999,
},
)

with patch('vsc.administration.base.StorageOperator') as mock_storage_operator:
operator = mock.MagicMock()
Expand Down Expand Up @@ -489,6 +496,10 @@ def test_process_brussel_vo(self, mock_client):
operator().create_stat_directory.assert_called_with(
"/vscmnt/brussel_pixiu_data/_data_brussel/brussel/vo/000/bvo00005/vsc10001", 448, 2510001, 1, override_permissions=False
)
operator().replace_acl.assert_called_with(
"/vscmnt/brussel_pixiu_data/_data_brussel/brussel/vo/000/bvo00005",
['A:d:OWNER@:rwaDdxtTnNcoy', 'A:fdg:9999999:rwaDdxtTnNcoy']
)

# VSC_SCRATCH test
ok, errors = vo.process_vos(
Expand All @@ -510,6 +521,10 @@ def test_process_brussel_vo(self, mock_client):
operator().create_stat_directory.assert_called_with(
"/rhea/scratch/brussel/vo/000/bvo00005/vsc10001", 448, 2510001, 1, override_permissions=False
)
operator().replace_acl.assert_called_with(
"/rhea/scratch/brussel/vo/000/bvo00005",
['A:d:OWNER@:rwaDdxtTnNcoy', 'A:fdg:9999999:rwaDdxtTnNcoy']
)

@patch("vsc.accountpage.client.AccountpageClient", autospec=True)
def test_process_brussel_default_vo(self, mock_client):
Expand Down Expand Up @@ -793,6 +808,13 @@ def test_process_brussel_default_vo_gent_user(self, mock_client):
},
],
)
mc.vo[test_vo_id].modgroup.get.return_value = (
200,
{
'vsc_id': 'bvo99999_mods',
'vsc_id_number': 9999999,
},
)

with patch('vsc.administration.base.StorageOperator') as mock_storage_operator:
operator = mock.MagicMock()
Expand Down Expand Up @@ -828,3 +850,7 @@ def test_process_brussel_default_vo_gent_user(self, mock_client):
operator().create_stat_directory.assert_called_with(
"/rhea/scratch/brussel/vo/000/bvo00003/vsc40002", 448, 2540002, 1, override_permissions=False
)
operator().replace_acl.assert_called_with(
"/rhea/scratch/brussel/vo/000/bvo00003",
['A:d:OWNER@:rwaDdxtTnNcoy', 'A:fdg:9999999:rwaDdxtTnNcoy']
)