Skip to content

Commit

Permalink
Remove legacy pool.dataset.permission endpoint
Browse files Browse the repository at this point in the history
This functionality has been superseded by filesystem ACL and
permissions endpoints since TrueNAS 12. Endpoint is no longer
used by the webui and so it is safe to remove.
  • Loading branch information
anodos325 committed Aug 8, 2024
1 parent 0de447b commit a8a770e
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 588 deletions.
175 changes: 0 additions & 175 deletions src/middlewared/middlewared/plugins/pool_/dataset_quota_and_perms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,181 +10,6 @@ class PoolDatasetService(Service):
class Config:
namespace = 'pool.dataset'

@accepts(
Str('id', required=True),
Dict(
'pool_dataset_permission',
Str('user'),
Str('group'),
UnixPerm('mode', null=True),
OROperator(
Ref('nfs4_acl'),
Ref('posix1e_acl'),
name='acl'
),
Dict(
'options',
Bool('set_default_acl', default=False),
Bool('stripacl', default=False),
Bool('recursive', default=False),
Bool('traverse', default=False),
),
register=True,
),
roles=['DATASET_WRITE']
)
@returns(Ref('pool_dataset_permission'))
@item_method
@job(lock="dataset_permission_change")
async def permission(self, job, id_, data):
"""
Set permissions for a dataset `id`. Permissions may be specified as
either a posix `mode` or an `acl`. This method is a wrapper around
`filesystem.setperm`, `filesystem.setacl`, and `filesystem.chown`
`filesystem.setperm` is called if `mode` is specified.
`filesystem.setacl` is called if `acl` is specified or if the
option `set_default_acl` is selected.
`filesystem.chown` is called if neither `mode` nor `acl` is
specified.
The following `options` are supported:
`set_default_acl` - apply a default ACL appropriate for specified
dataset. Default ACL is `NFS4_RESTRICTED` or `POSIX_RESTRICTED`
ACL template builtin with additional entries builtin_users group
and builtin_administrators group. See documentation for
`filesystem.acltemplate` for more details.
`stripacl` - this option must be set in order to apply a POSIX
mode to a dataset that has a non-trivial ACL. The effect will
be to remove existing ACL and replace with specified mode.
`recursive` - apply permissions recursively to dataset (all files
and directories will be impacted.
`traverse` - permit recursive job to traverse filesystem boundaries
(child datasets).
.. examples(websocket)::
Change permissions of dataset "tank/myuser" to myuser:wheel and 755.
:::javascript
{
"id": "6841f242-840a-11e6-a437-00e04d680384",
"msg": "method",
"method": "pool.dataset.permission",
"params": ["tank/myuser", {
"user": "myuser",
"acl": [],
"group": "builtin_users",
"mode": "755",
"options": {"recursive": true, "stripacl": true},
}]
}
"""
dataset_info = await self.middleware.call('pool.dataset.get_instance', id_)
path = dataset_info['mountpoint']
acltype = dataset_info['acltype']['value']
user = data.get('user', None)
group = data.get('group', None)
uid = gid = -1
mode = data.get('mode', None)
options = data.get('options', {})
set_default_acl = options.pop('set_default_acl')
acl = data.get('acl', [])

if mode is None and set_default_acl:
acl_template = 'POSIX_RESTRICTED' if acltype == 'POSIX' else 'NFS4_RESTRICTED'
acl = (await self.middleware.call('filesystem.acltemplate.by_path', {
'query-filters': [('name', '=', acl_template)],
'format-options': {'canonicalize': True, 'ensure_builtins': True},
}))[0]['acl']

pjob = None

verrors = ValidationErrors()
if user is not None:
try:
uid = (await self.middleware.call('user.get_user_obj', {'username': user}))['pw_uid']
except Exception as e:
verrors.add('pool_dataset_permission.user', str(e))

if group is not None:
try:
gid = (await self.middleware.call('group.get_group_obj', {'groupname': group}))['gr_gid']
except Exception as e:
verrors.add('pool_dataset_permission.group', str(e))

if acl and mode:
verrors.add('pool_dataset_permission.mode',
'setting mode and ACL simultaneously is not permitted.')

if acl and options['stripacl']:
verrors.add('pool_dataset_permissions.acl',
'Simultaneously setting and removing ACL is not permitted.')

if mode and not options['stripacl']:
if not await self.middleware.call('filesystem.acl_is_trivial', path):
verrors.add('pool_dataset_permissions.options',
f'{path} has an extended ACL. The option "stripacl" must be selected.')
verrors.check()

if not acl and mode is None and not options['stripacl']:
"""
Neither an ACL, mode, or removing the existing ACL are
specified in `data`. Perform a simple chown.
"""
options.pop('stripacl', None)
pjob = await self.middleware.call('filesystem.chown', {
'path': path,
'uid': uid,
'gid': gid,
'options': options
})

elif acl:
pjob = await self.middleware.call('filesystem.setacl', {
'path': path,
'dacl': acl,
'uid': uid,
'gid': gid,
'options': options
})

elif mode or options['stripacl']:
"""
`setperm` performs one of two possible actions. If
`mode` is not set, but `stripacl` is specified, then
the existing ACL on the file is converted in place via
`acl_strip_np()`. This preserves the existing posix mode
while removing any extended ACL entries.
If `mode` is set, then the ACL is removed from the file
and the new `mode` is applied.
"""
pjob = await self.middleware.call('filesystem.setperm', {
'path': path,
'mode': mode,
'uid': uid,
'gid': gid,
'options': options
})
else:
"""
This should never occur, but fail safely to avoid undefined
or unintended behavior.
"""
raise CallError(f"Unexpected parameter combination: {data}",
errno.EINVAL)

await pjob.wait()
if pjob.error:
raise CallError(pjob.error)
return data

# TODO: Document this please
@accepts(
Str('ds', required=True),
Expand Down
11 changes: 5 additions & 6 deletions tests/api2/test_011_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,11 @@ def test_031_create_user_with_homedir(request):
newly-created home directory."""
# create the dataset
call('pool.dataset.create', HomeAssets.Dataset01['create_payload'])
call(
'pool.dataset.permission',
HomeAssets.Dataset01['create_payload']['name'],
{'acl': HomeAssets.Dataset01['home_acl']},
job=True
)
call('filesystem.setacl', {
'path': os.path.join('/mnt', HomeAssets.Dataset01['create_payload']['name']),
'acl': HomeAssets.Dataset01['home_acl']
}, job=True)

# now create the user
UserAssets.TestUser02['create_payload']['uid'] = call('user.get_next_uid')
call('user.create', UserAssets.TestUser02['create_payload'])
Expand Down
8 changes: 4 additions & 4 deletions tests/api2/test_345_acl_nfs4.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,10 @@ def test_02_create_dataset(initialize_for_acl_tests):

def test_04_basic_set_acl_for_dataset(request):
depends(request, ["HAS_NFS4_ACLS"])
call('pool.dataset.permission', TEST_INFO['dataset'], {
'acl': default_acl,
'group': group,
'user': 'nobody'
call('filesystem.setacl', {
'uid': 65534,
'gid': 65534,
'acl': default_acl
}, job=True)

acl_result = call('filesystem.getacl', TEST_INFO['dataset_path'], True)
Expand Down
Loading

0 comments on commit a8a770e

Please sign in to comment.