From a8a770eee55308df6e67a15cf2003a2c132d0bdc Mon Sep 17 00:00:00 2001 From: Andrew Walker Date: Thu, 8 Aug 2024 08:26:45 -0700 Subject: [PATCH] Remove legacy pool.dataset.permission endpoint 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. --- .../plugins/pool_/dataset_quota_and_perms.py | 175 ------ tests/api2/test_011_user.py | 11 +- tests/api2/test_345_acl_nfs4.py | 8 +- tests/api2/test_347_posix_mode.py | 586 ++++++------------ tests/api2/test_348_posix_acl.py | 19 +- 5 files changed, 211 insertions(+), 588 deletions(-) diff --git a/src/middlewared/middlewared/plugins/pool_/dataset_quota_and_perms.py b/src/middlewared/middlewared/plugins/pool_/dataset_quota_and_perms.py index 486b5359208be..e62dd34d35831 100644 --- a/src/middlewared/middlewared/plugins/pool_/dataset_quota_and_perms.py +++ b/src/middlewared/middlewared/plugins/pool_/dataset_quota_and_perms.py @@ -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), diff --git a/tests/api2/test_011_user.py b/tests/api2/test_011_user.py index 32c88c8d76e23..02c01ad67dbd8 100644 --- a/tests/api2/test_011_user.py +++ b/tests/api2/test_011_user.py @@ -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']) diff --git a/tests/api2/test_345_acl_nfs4.py b/tests/api2/test_345_acl_nfs4.py index f38e3ab93c7f2..fc7d0a9820a69 100644 --- a/tests/api2/test_345_acl_nfs4.py +++ b/tests/api2/test_345_acl_nfs4.py @@ -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) diff --git a/tests/api2/test_347_posix_mode.py b/tests/api2/test_347_posix_mode.py index c7fb7cce2b72e..d1af58cbfc0aa 100644 --- a/tests/api2/test_347_posix_mode.py +++ b/tests/api2/test_347_posix_mode.py @@ -2,20 +2,19 @@ # License: BSD -import sys -import os import pytest import stat -apifolder = os.getcwd() -sys.path.append(apifolder) -from functions import DELETE, GET, POST, SSH_TEST, wait_on_job -from auto_config import pool_name, user, password -from pytest_dependency import depends -MODE_DATASET = f'{pool_name}/modetest' +from functions import SSH_TEST +from middlewared.test.integration.assets.account import user, group +from middlewared.test.integration.assets.pool import dataset +from middlewared.test.integration.utils import call, ssh + + +MODE_DATASET_NAME = 'modetest' dataset_url = MODE_DATASET.replace('/', '%2F') -MODE_SUBDATASET = f'{pool_name}/modetest/sub1' +MODE_SUBDATASET_NAME = 'modetest/sub1' subdataset_url = MODE_SUBDATASET.replace('/', '%2F') OWNER_BITS = { @@ -43,202 +42,117 @@ MODE_PWD = "modetesting" -def test_01_check_dataset_endpoint(): - assert isinstance(GET('/pool/dataset/').json(), list) +@pytest.fixture(scope='module'): +def get_dataset(): + with dataset(MODE_DATASET_NAME) as ds: + path = os.path.join('/mnt', ds) + ssh(f'mkdir -p {path}/dir1/dir2') + ssh(f'touch {path}/dir1/dir2/testfile') + + with dataset(MODE_SUBDATASET_NAME): + yield ds -@pytest.mark.dependency(name="DATASET_CREATED") -def test_02_create_dataset(request): - result = POST( - '/pool/dataset/', { - 'name': MODE_DATASET - } - ) - assert result.status_code == 200, result.text +@pytest.fixture(scope='module'): +def get_user(): + with group(MODE_GROUP) as g: + with user({ + 'username': MODE_USER, + 'password': MODE_PWD, + 'group_create': True, + 'shell': '/usr/bin/bash', + 'ssh_password_enabled': True, + 'groups': [g['id']] + ) as u: + yield u | {'group_gid': g['gid']} + + +def get_mode_octal(path): + mode = call('filesystem.stat', path)['mode'] + server_mode = f"{stat.S_IMODE(mode):03o}" @pytest.mark.dependency(name="IS_TRIVIAL") -def test_03_verify_acl_is_trivial(request): +def test_verify_acl_is_trivial(get_dataset): depends(request, ["DATASET_CREATED"]) - results = POST('/filesystem/stat/', f'/mnt/{MODE_DATASET}') - assert results.status_code == 200, results.text - assert results.json()['acl'] is False, results.text + st = call('filesystem.stat', os.path.join('/mnt', get_dataset)) + assert st['acl'] is False + + +def get_mode_octal(path): + mode = call('filesystem.stat', path)['mode'] + return f"{stat.S_IMODE(mode):03o}" @pytest.mark.parametrize('mode_bit', MODE.keys()) -def test_04_verify_setting_mode_bits_nonrecursive(request, mode_bit): +def test_verify_setting_mode_bits_nonrecursive(get_dataset, mode_bit): """ This test iterates through possible POSIX permissions bits and verifies that they are properly set on the remote server. """ - depends(request, ["IS_TRIVIAL"]) new_mode = f"{MODE[mode_bit]:03o}" - result = POST( - f'/pool/dataset/id/{dataset_url}/permission/', { - 'acl': [], - 'mode': new_mode, - 'group': 'nogroup', - 'user': 'nobody' - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - results = POST('/filesystem/stat/', f'/mnt/{MODE_DATASET}') - assert results.status_code == 200, results.text - server_mode = f"{stat.S_IMODE(results.json()['mode']):03o}" - assert new_mode == server_mode, results.text - - -@pytest.mark.dependency(name="RECURSIVE_PREPARED") -def test_05_prepare_recursive_tests(request): - depends(request, ["IS_TRIVIAL"], scope="session") - result = POST( - '/pool/dataset/', { - 'name': MODE_SUBDATASET - } - ) - assert result.status_code == 200, result.text - - cmd = f'mkdir -p /mnt/{MODE_DATASET}/dir1/dir2' - results = SSH_TEST(cmd, user, password) - assert results['result'] is True, results['output'] + path = os.path.join('/mnt', get_dataset) - cmd = f'touch /mnt/{MODE_DATASET}/dir1/dir2/testfile' - results = SSH_TEST(cmd, user, password) - assert results['result'] is True, results['output'] + call('filesystem.setperm', { + 'path': path, + 'mode': new_mode, + 'uid': 65534, + 'gid': 65534 + }, job=True) - results = POST('/filesystem/stat/', f'/mnt/{MODE_SUBDATASET}') - assert results.status_code == 200, results.text - current_mode = results.json()['mode'] - # new datasets should be created with 755 permissions" - assert f"{stat.S_IMODE(current_mode):03o}" == "755", results.text + server_mode = get_mode_octal(path) + assert new_mode == server_mode @pytest.mark.parametrize('mode_bit', MODE.keys()) -def test_06_verify_setting_mode_bits_recursive_no_traverse(request, mode_bit): +def test_verify_setting_mode_bits_recursive_no_traverse(get_dataset, mode_bit): """ Perform recursive permissions change and verify new mode written to files and subdirectories. """ - depends(request, ["RECURSIVE_PREPARED"]) + ds_path = os.path.join('/mnt', get_dataset) + sub_ds_path = os.path.join(ds_path, 'sub1') + new_mode = f"{MODE[mode_bit]:03o}" - result = POST( - f'/pool/dataset/id/{dataset_url}/permission/', { - 'acl': [], - 'mode': new_mode, - 'group': 'nogroup', - 'user': 'nobody', - 'options': {'recursive': True} - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - results = POST('/filesystem/stat/', f'/mnt/{MODE_DATASET}') - assert results.status_code == 200, results.text - server_mode = f"{stat.S_IMODE(results.json()['mode']):03o}" - assert new_mode == server_mode, results.text - - results = POST('/filesystem/stat/', f'/mnt/{MODE_DATASET}/dir1/dir2') - assert results.status_code == 200, results.text - server_mode = f"{stat.S_IMODE(results.json()['mode']):03o}" - assert new_mode == server_mode, results.text - - results = POST('/filesystem/stat/', - f'/mnt/{MODE_DATASET}/dir1/dir2/testfile') - assert results.status_code == 200, results.text - server_mode = f"{stat.S_IMODE(results.json()['mode']):03o}" - assert new_mode == server_mode, results.text - - -def test_07_verify_mode_not_set_on_child_dataset(request): - depends(request, ["RECURSIVE_PREPARED"]) - results = POST('/filesystem/stat/', f'/mnt/{MODE_SUBDATASET}') - assert results.status_code == 200, results.text - current_mode = results.json()['mode'] - # new datasets should be created with 755 permissions" - assert f"{stat.S_IMODE(current_mode):03o}" == "755", results.text - - -def test_08_verify_traverse_to_child_dataset(request): - depends(request, ["RECURSIVE_PREPARED"]) - result = POST( - f'/pool/dataset/id/{dataset_url}/permission/', { - 'acl': [], - 'mode': 777, - 'group': 'nogroup', - 'user': 'nobody', - 'options': {'recursive': True, 'traverse': True} - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - results = POST('/filesystem/stat/', f'/mnt/{MODE_SUBDATASET}') - assert results.status_code == 200, results.text - current_mode = results.json()['mode'] - assert f"{stat.S_IMODE(current_mode):03o}" == "777", results.text - - -""" -Create user and group for testing function of POSIX permission bits. -""" - - -@pytest.mark.dependency(name="GROUP_CREATED") -def test_09_create_test_group(request): - depends(request, ["IS_TRIVIAL"]) - global next_gid - global groupid - results = GET('/group/get_next_gid/') - assert results.status_code == 200, results.text - next_gid = results.json() - global groupid - payload = { - "gid": next_gid, - "name": MODE_GROUP, - } - results = POST("/group/", payload) - assert results.status_code == 200, results.text - groupid = results.json() - - -@pytest.mark.dependency(name="USER_CREATED") -def test_10_creating_shareuser_to_test_acls(request): - depends(request, ["GROUP_CREATED"]) - global modeuser_id - global next_uid - results = GET('/user/get_next_uid/') - assert results.status_code == 200, results.text - next_uid = results.json() - payload = { - "username": MODE_USER, - "full_name": "Mode User", - "group_create": True, - "password": MODE_PWD, - "uid": next_uid, - "groups": [groupid], - "shell": '/usr/bin/bash', - "ssh_password_enabled": True, - } - results = POST("/user/", payload) - assert results.status_code == 200, results.text - modeuser_id = results.json() - - -""" -Next series of tests are for correct behavior of POSIX permissions -""" - - -def dir_mode_check(mode_bit): + call('filesystem.setperm', { + 'path': ds_path, + 'mode': new_mode, + 'uid': 65534, + 'gid': 65534 + 'options': {'recursive': True} + }, job=True) + + server_mode = get_mode_octal(ds_path) + assert new_mode == server_mode + + server_mode = get_mode_octal(os.path.join(ds_path, 'dir1', 'dir2')) + assert new_mode == server_mode + + server_mode = get_mode_octal(os.path.join(ds_path, 'dir1', 'dir2', 'testfile')) + assert new_mode == server_mode + + # child dataset shouldn't be touched + server_mode = get_mode_octal(sub_ds_path) + assert server_mode == "755" + + +def test_verify_traverse_to_child_dataset(get_dataset): + ds_path = os.path.join('/mnt', get_dataset) + sub_ds_path = os.path.join(ds_path, 'sub1') + + call('filesystem.setperm', { + 'path': ds_path, + 'mode': '777', + 'uid': 65534, + 'gid': 65534 + 'options': {'recursive': True, 'traverse': True} + }, job=True) + + server_mode = get_mode_octal(sub_ds_path) + assert server_mode == "777" + + +def dir_mode_check(mode_bit, MODE_DATASET): if mode_bit.endswith("READ"): cmd = f'ls /mnt/{MODE_DATASET}' results = SSH_TEST(cmd, MODE_USER, MODE_PWD) @@ -279,7 +193,7 @@ def dir_mode_check(mode_bit): assert results['result'] is False, results['output'] -def file_mode_check(mode_bit): +def file_mode_check(mode_bit, MODE_DATASET): if mode_bit.endswith("READ"): cmd = f'cat /mnt/{MODE_DATASET}/canary' results = SSH_TEST(cmd, MODE_USER, MODE_PWD) @@ -329,7 +243,7 @@ def file_mode_check(mode_bit): assert results['result'] is False, results['output'] -def file_mode_check_xor(mode_bit): +def file_mode_check_xor(mode_bit, MODE_DATASET): """ when this method is called, all permissions bits are set except for the one being tested. @@ -351,306 +265,196 @@ def file_mode_check_xor(mode_bit): @pytest.mark.parametrize('mode_bit', OWNER_BITS.keys()) -def test_11_test_directory_owner_bits_function_allow(mode_bit, request): +def test_directory_owner_bits_function_allow(mode_bit, get_dataset, get_user): """ Verify mode behavior correct when it's the only bit set. In case of directory, Execute must be set concurrently with write in order to verify correct write behavior. """ - depends(request, ["USER_CREATED"], scope="session") + ds_path = os.path.join('/mnt', get_dataset) new_mode = MODE[mode_bit] if new_mode == stat.S_IWUSR: new_mode |= stat.S_IXUSR - result = POST( - f'/pool/dataset/id/{dataset_url}/permission/', { - 'acl': [], - 'mode': f'{new_mode:03o}', - 'group': 'nogroup', - 'user': MODE_USER - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - if job_status['state'] != 'SUCCESS': - return + call('filesystem.setperm', { + 'path': ds_path, + 'mode': f'{new_mode:03o}', + 'uid': get_user['uid'], + 'gid': 65534, + }, job=True) - dir_mode_check(mode_bit) + dir_mode_check(mode_bit, get_dataset) @pytest.mark.parametrize('mode_bit', GROUP_BITS.keys()) -def test_12_test_directory_group_bits_function_allow(mode_bit, request): +def test_directory_group_bits_function_allow(mode_bit, get_dataset, get_user): """ Verify mode behavior correct when it's the only bit set. In case of directory, Execute must be set concurrently with write in order to verify correct write behavior. """ - depends(request, ["USER_CREATED"], scope="session") + ds_path = os.path.join('/mnt', get_dataset) + new_mode = MODE[mode_bit] if new_mode == stat.S_IWGRP: new_mode |= stat.S_IXGRP - result = POST( - f'/pool/dataset/id/{dataset_url}/permission/', { - 'acl': [], - 'mode': f'{new_mode:03o}', - 'group': MODE_GROUP, - 'user': 'root' - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - if job_status['state'] != 'SUCCESS': - return + call('filesystem.setperm', { + 'path': ds_path, + 'mode': f'{new_mode:03o}', + 'uid': 0, + 'gid': get_user['group_gid'], + }, job=True) - dir_mode_check(mode_bit) + dir_mode_check(mode_bit, get_dataset) @pytest.mark.parametrize('mode_bit', OTHER_BITS.keys()) -def test_13_test_directory_other_bits_function_allow(mode_bit, request): +def test_directory_other_bits_function_allow(mode_bit, get_dataset): """ Verify mode behavior correct when it's the only bit set. In case of directory, Execute must be set concurrently with write in order to verify correct write behavior. """ - depends(request, ["USER_CREATED"], scope="session") + ds_path = os.path.join('/mnt', get_dataset) + new_mode = MODE[mode_bit] if new_mode == stat.S_IWOTH: new_mode |= stat.S_IXOTH - result = POST( - f'/pool/dataset/id/{dataset_url}/permission/', { - 'acl': [], - 'mode': f'{new_mode:03o}', - 'group': 'root', - 'user': 'root' - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - if job_status['state'] != 'SUCCESS': - return - - dir_mode_check(mode_bit) - - -def test_14_setup_file_test(request): - depends(request, ["USER_CREATED"], scope="session") - result = POST( - '/filesystem/setperm/', { - 'path': f'/mnt/{MODE_DATASET}', - 'mode': "001", - 'gid': 0, - 'uid': 0, - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - cmd = f'echo "echo CANARY" > /mnt/{MODE_DATASET}/canary' + call('filesystem.setperm', { + 'path': ds_path, + 'mode': f'{new_mode:03o}', + 'uid': 0, + 'gid': 0, + }, job=True) + + dir_mode_check(mode_bit, get_dataset) + + +def test_setup_file_test(get_dataset): + ds_path = os.path.join('/mnt', get_dataset) + + call('filesystem.setperm', { + 'path': ds_path, + 'mode': '001', + 'uid': 0, + 'gid': 0, + }, job=True) + + cmd = f'echo "echo CANARY" > {ds_path}/canary' results = SSH_TEST(cmd, user, password) assert results['result'] is True, results['output'] @pytest.mark.parametrize('mode_bit', OWNER_BITS.keys()) -def test_15_test_file_owner_bits_function_allow(mode_bit, request): +def test_file_owner_bits_function_allow(mode_bit, get_dataset, get_user): """ Verify mode behavior correct when it's the only bit set. """ - depends(request, ["USER_CREATED"], scope="session") + ds_path = os.path.join('/mnt', get_dataset) new_mode = MODE[mode_bit] - result = POST( - '/filesystem/setperm/', { - 'path': f'/mnt/{MODE_DATASET}/canary', - 'mode': f'{new_mode:03o}', - 'gid': 0, - 'uid': next_uid - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - if job_status['state'] != 'SUCCESS': - return + call('filesystem.setperm', { + 'path': ds_path, + 'mode': f'{new_mode:03o}', + 'uid': get_user['uid'], + 'gid': 0, + }, job=True) - file_mode_check(mode_bit) + file_mode_check(mode_bit, get_dataset) @pytest.mark.parametrize('mode_bit', GROUP_BITS.keys()) -def test_16_test_file_group_bits_function_allow(mode_bit, request): +def test_file_group_bits_function_allow(mode_bit, get_dataset, get_user): """ Verify mode behavior correct when it's the only bit set. """ - depends(request, ["USER_CREATED"], scope="session") + ds_path = os.path.join('/mnt', get_dataset) new_mode = MODE[mode_bit] - result = POST( - '/filesystem/setperm/', { - 'path': f'/mnt/{MODE_DATASET}/canary', - 'mode': f'{new_mode:03o}', - 'gid': next_gid, - 'uid': 0, - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) + call('filesystem.setperm', { + 'path': ds_path, + 'mode': f'{new_mode:03o}', + 'gid': get_user['group_gid'], + 'uid': 0, + }, job=True) - if job_status['state'] != 'SUCCESS': - return - - file_mode_check(mode_bit) + file_mode_check(mode_bit, get_dataset) @pytest.mark.parametrize('mode_bit', OTHER_BITS.keys()) -def test_17_test_file_other_bits_function_allow(mode_bit, request): +def test_file_other_bits_function_allow(mode_bit, get_dataset, get_user): """ Verify mode behavior correct when it's the only bit set. """ - depends(request, ["USER_CREATED"], scope="session") + ds_path = os.path.join('/mnt', get_dataset) new_mode = MODE[mode_bit] - result = POST( - '/filesystem/setperm/', { - 'path': f'/mnt/{MODE_DATASET}/canary', - 'mode': f'{new_mode:03o}', - 'gid': 0, - 'uid': 0, - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - if job_status['state'] != 'SUCCESS': - return + call('filesystem.setperm', { + 'path': ds_path, + 'mode': f'{new_mode:03o}', + 'gid': 0, + 'uid': 0, + }, job=True) - file_mode_check(mode_bit) + file_mode_check(mode_bit, get_dataset) @pytest.mark.parametrize('mode_bit', OWNER_BITS.keys()) -def test_18_test_file_owner_bits_xor(mode_bit, request): +def test_file_owner_bits_xor(mode_bit, get_dataset, get_user): """ Verify mode behavior correct when it's the only bit set. """ - depends(request, ["USER_CREATED"], scope="session") + ds_path = os.path.join('/mnt', get_dataset) new_mode = stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO new_mode = new_mode ^ MODE[mode_bit] - result = POST( - '/filesystem/setperm/', { - 'path': f'/mnt/{MODE_DATASET}/canary', - 'mode': f'{new_mode:03o}', - 'gid': 0, - 'uid': next_uid - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) + new_mode = MODE[mode_bit] - if job_status['state'] != 'SUCCESS': - return + call('filesystem.setperm', { + 'path': ds_path, + 'mode': f'{new_mode:03o}', + 'gid': 0, + 'uid': get_user['uid'], + }, job=True) - file_mode_check_xor(mode_bit) + file_mode_check_xor(mode_bit, get_dataset) @pytest.mark.parametrize('mode_bit', GROUP_BITS.keys()) -def test_19_test_file_group_bits_xor(mode_bit, request): +def test_file_group_bits_xor(mode_bit, get_dataset, get_user): """ Verify mode behavior correct when it's the only bit set. """ - depends(request, ["USER_CREATED"], scope="session") + ds_path = os.path.join('/mnt', get_dataset) new_mode = stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO new_mode = new_mode ^ MODE[mode_bit] - result = POST( - '/filesystem/setperm/', { - 'path': f'/mnt/{MODE_DATASET}/canary', - 'mode': f'{new_mode:03o}', - 'gid': next_gid, - 'uid': 0 - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) + call('filesystem.setperm', { + 'path': ds_path, + 'mode': f'{new_mode:03o}', + 'gid': get_user['group_gid'], + 'uid': 0, + }, job=True) - if job_status['state'] != 'SUCCESS': - return - - file_mode_check_xor(mode_bit) + file_mode_check_xor(mode_bit, get_dataset) @pytest.mark.parametrize('mode_bit', OTHER_BITS.keys()) -def test_20_test_file_other_bits_xor(mode_bit, request): +def test_20_test_file_other_bits_xor(mode_bit, get_dataset, get_user): """ Verify mode behavior correct when it's the only bit set. """ - depends(request, ["USER_CREATED"], scope="session") + ds_path = os.path.join('/mnt', get_dataset) new_mode = stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO new_mode = new_mode ^ MODE[mode_bit] - result = POST( - '/filesystem/setperm/', { - 'path': f'/mnt/{MODE_DATASET}/canary', - 'mode': f'{new_mode:03o}', - 'gid': 0, - 'uid': 0 - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) - - if job_status['state'] != 'SUCCESS': - return - - file_mode_check_xor(mode_bit) - - -def test_21_delete_child_dataset(request): - depends(request, ["RECURSIVE_PREPARED"]) - result = DELETE( - f'/pool/dataset/id/{subdataset_url}/' - ) - assert result.status_code == 200, result.text - + call('filesystem.setperm', { + 'path': ds_path, + 'mode': f'{new_mode:03o}', + 'gid': 0, + 'uid': 0, + }, job=True) -def test_22_delete_group(request): - depends(request, ["GROUP_CREATED"]) - results = DELETE(f"/group/id/{groupid}/", {"delete_users": True}) - assert results.status_code == 200, results.text - - -def test_23_delete_user(request): - depends(request, ["USER_CREATED"]) - results = DELETE(f"/user/id/{modeuser_id}/", {"delete_group": True}) - assert results.status_code == 200, results.text - - -def test_24_delete_dataset(request): - depends(request, ["DATASET_CREATED"]) - result = DELETE( - f'/pool/dataset/id/{dataset_url}/' - ) - assert result.status_code == 200, result.text + file_mode_check_xor(mode_bit, get_dataset) diff --git a/tests/api2/test_348_posix_acl.py b/tests/api2/test_348_posix_acl.py index bb6825e522d8c..7ad7afd830a03 100644 --- a/tests/api2/test_348_posix_acl.py +++ b/tests/api2/test_348_posix_acl.py @@ -11,6 +11,7 @@ from functions import DELETE, GET, POST, SSH_TEST, wait_on_job from auto_config import pool_name, user, password from pytest_dependency import depends +from middlewared.test.integration.utils import call ACLTEST_DATASET = f'{pool_name}/posixacltest' @@ -463,22 +464,16 @@ def test_14_recursive_with_traverse(request): def test_15_strip_acl_from_dataset(request): """ - Strip ACL via pool.dataset.permission endpoint. + Strip ACL via filesystem.setperm endpoint. This should work even for POSIX1E ACLs. """ depends(request, ["HAS_POSIX_ACLS"]) - result = POST( - f'/pool/dataset/id/{DATASET_URL}/permission/', { - 'acl': [], - 'mode': '777', - 'options': {'stripacl': True, 'recursive': True} - } - ) - assert result.status_code == 200, result.text - JOB_ID = result.json() - job_status = wait_on_job(JOB_ID, 180) - assert job_status['state'] == 'SUCCESS', str(job_status['results']) + call('filesystem.setperm', { + 'path': os.path.join('/mnt', DATASET), + 'mode': '777', + 'options': {'stripacl': True, 'recursive': True} + }, job=True) """