From abd810cef64205c4723ba172c40419db15397951 Mon Sep 17 00:00:00 2001 From: "a.berezin" Date: Wed, 20 Nov 2024 17:11:04 +0300 Subject: [PATCH] [#327] Remove basic-acl from APE tests Signed-off-by: a.berezin --- pytest.ini | 11 +- pytest_tests/helpers/container_creation.py | 45 +- pytest_tests/helpers/container_request.py | 12 + pytest_tests/testsuites/ape/__init__.py | 0 pytest_tests/testsuites/ape/conftest.py | 52 + pytest_tests/testsuites/ape/test_ape.py | 1006 ----------------- .../ape/test_ape_local_container.py | 212 ++++ .../ape/test_ape_local_object_allow.py | 254 +++++ .../ape/test_ape_local_object_deny.py | 333 ++++++ pytest_tests/testsuites/conftest.py | 29 +- .../testsuites/container/test_container.py | 1 - .../container/test_policy_with_price.py | 2 +- .../testsuites/object/test_object_api.py | 4 +- .../object/test_object_api_bearer.py | 2 +- .../testsuites/object/test_object_lock.py | 2 +- 15 files changed, 934 insertions(+), 1031 deletions(-) create mode 100644 pytest_tests/testsuites/ape/__init__.py create mode 100644 pytest_tests/testsuites/ape/conftest.py delete mode 100644 pytest_tests/testsuites/ape/test_ape.py create mode 100644 pytest_tests/testsuites/ape/test_ape_local_container.py create mode 100644 pytest_tests/testsuites/ape/test_ape_local_object_allow.py create mode 100644 pytest_tests/testsuites/ape/test_ape_local_object_deny.py diff --git a/pytest.ini b/pytest.ini index 2468250b..11047c40 100644 --- a/pytest.ini +++ b/pytest.ini @@ -37,11 +37,12 @@ markers = session_token: tests for operations with session token static_session: tests for operations with static session token bearer: tests for bearer tokens - acl: All tests for ACL - acl_basic: tests for basic ACL - acl_bearer: tests for ACL with bearer - acl_extended: tests for extended ACL - acl_filters: tests for extended ACL with filters and headers + ape: tests for APE + ape_allow: tests for APE allow rules + ape_deny: tests for APE deny rules + ape_container: tests for APE on container operations + ape_object: tests for APE on object operations + ape_namespace: tests for APE on namespace scope storage_group: tests for storage groups failover: tests for system recovery after a failure failover_panic: tests for system recovery after panic reboot of a node diff --git a/pytest_tests/helpers/container_creation.py b/pytest_tests/helpers/container_creation.py index a881339c..5b4bcddb 100644 --- a/pytest_tests/helpers/container_creation.py +++ b/pytest_tests/helpers/container_creation.py @@ -9,23 +9,29 @@ from frostfs_testlib.steps.cli.container import create_container, search_nodes_w from frostfs_testlib.storage.cluster import Cluster from frostfs_testlib.storage.dataclasses import ape from frostfs_testlib.storage.dataclasses.wallet import WalletInfo +from frostfs_testlib.testing.parallel import parallel from frostfs_testlib.utils import datetime_utils -from .container_request import ContainerRequest +from .container_request import ContainerRequest, MultipleContainersRequest def create_container_with_ape( - frostfs_cli: FrostfsCli, wallet: WalletInfo, shell: Shell, cluster: Cluster, endpoint: str, container_request: ContainerRequest -): + container_request: ContainerRequest, + frostfs_cli: FrostfsCli, + wallet: WalletInfo, + shell: Shell, + cluster: Cluster, + endpoint: str, +) -> str: with reporter.step("Create container"): - cid = _create_container_by_spec(wallet, shell, cluster, endpoint, container_request) + cid = _create_container_by_spec(container_request, wallet, shell, cluster, endpoint) - with reporter.step("Apply APE rules for container"): - if container_request.ape_rules: - _apply_ape_rules(frostfs_cli, endpoint, cid, container_request.ape_rules) + if container_request.ape_rules: + with reporter.step("Apply APE rules for container"): + _apply_ape_rules(cid, frostfs_cli, endpoint, container_request.ape_rules) - with reporter.step("Wait for one block"): - time.sleep(datetime_utils.parse_time(MORPH_BLOCK_TIME)) + with reporter.step("Wait for one block"): + time.sleep(datetime_utils.parse_time(MORPH_BLOCK_TIME)) with reporter.step("Search nodes holding the container"): container_holder_nodes = search_nodes_with_container(wallet, cid, shell, cluster.default_rpc_endpoint, cluster) @@ -36,14 +42,31 @@ def create_container_with_ape( return cid +@reporter.step("Create multiple containers with APE") +def create_containers_with_ape( + frostfs_cli: FrostfsCli, + wallet: WalletInfo, + shell: Shell, + cluster: Cluster, + endpoint: str, + multiple_containers_request: MultipleContainersRequest, +) -> list[str]: + cids_futures = parallel(create_container_with_ape, multiple_containers_request, frostfs_cli, wallet, shell, cluster, endpoint) + return [future.result() for future in cids_futures] + + @reporter.step("Create container by spec {container_request}") def _create_container_by_spec( - wallet: WalletInfo, shell: Shell, cluster: Cluster, endpoint: str, container_request: ContainerRequest + container_request: ContainerRequest, + wallet: WalletInfo, + shell: Shell, + cluster: Cluster, + endpoint: str, ) -> str: return create_container(wallet, shell, endpoint, container_request.parsed_rule(cluster), wait_for_creation=False) -def _apply_ape_rules(frostfs_cli: FrostfsCli, endpoint: str, cid: str, ape_rules: list[ape.Rule]): +def _apply_ape_rules(cid: str, frostfs_cli: FrostfsCli, endpoint: str, ape_rules: list[ape.Rule]): for ape_rule in ape_rules: rule_str = ape_rule.as_string() with reporter.step(f"Apply APE rule '{rule_str}' for container {cid}"): diff --git a/pytest_tests/helpers/container_request.py b/pytest_tests/helpers/container_request.py index 72740b3a..8d217ed6 100644 --- a/pytest_tests/helpers/container_request.py +++ b/pytest_tests/helpers/container_request.py @@ -54,6 +54,18 @@ class ContainerRequest: return f"({', '.join(spec_info)})" +class MultipleContainersRequest(list[ContainerRequest]): + def __init__(self, iterable=None): + """Override initializer which can accept iterable""" + super(MultipleContainersRequest, self).__init__() + if iterable: + self.extend(iterable) + self.__set_name() + + def __set_name(self): + self.__name__ = ", ".join([s.__name__ for s in self]) + + PUBLIC_WITH_POLICY = partial(ContainerRequest, ape_rules=APE_EVERYONE_ALLOW_ALL, short_name="Custom_policy_with_allow_all_ape_rule") EVERYONE_ALLOW_ALL = ContainerRequest(policy=DEFAULT_PLACEMENT_RULE, ape_rules=APE_EVERYONE_ALLOW_ALL, short_name="Everyone_Allow_All") OWNER_ALLOW_ALL = ContainerRequest(policy=DEFAULT_PLACEMENT_RULE, ape_rules=APE_OWNER_ALLOW_ALL, short_name="Owner_Allow_All") diff --git a/pytest_tests/testsuites/ape/__init__.py b/pytest_tests/testsuites/ape/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pytest_tests/testsuites/ape/conftest.py b/pytest_tests/testsuites/ape/conftest.py new file mode 100644 index 00000000..091b0011 --- /dev/null +++ b/pytest_tests/testsuites/ape/conftest.py @@ -0,0 +1,52 @@ +import pytest +from frostfs_testlib import reporter +from frostfs_testlib.cli import FrostfsCli +from frostfs_testlib.resources.cli import FROSTFS_CLI_EXEC +from frostfs_testlib.shell.interfaces import Shell +from frostfs_testlib.steps.cli.object import put_object +from frostfs_testlib.storage.cluster import Cluster +from frostfs_testlib.storage.dataclasses.object_size import ObjectSize +from frostfs_testlib.storage.dataclasses.wallet import WalletInfo +from frostfs_testlib.utils.file_utils import generate_file + + +@pytest.fixture(scope="session") +def frostfs_cli_on_first_node(cluster: Cluster) -> FrostfsCli: + node = cluster.cluster_nodes[0] + shell = node.host.get_shell() + + return FrostfsCli(shell, FROSTFS_CLI_EXEC, node.storage_node.get_remote_wallet_config_path()) + + +@pytest.fixture +def object_id( + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + simple_object_size: ObjectSize, + cluster: Cluster, + client_shell: Shell, + container: str, +) -> str: + test_file = generate_file(simple_object_size.value) + + with reporter.step("Allow PutObject on first node via local override"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowPutObject", + rule=f"allow Object.Put *", + ) + + with reporter.step("Put objects in container on the first node"): + object_id = put_object(default_wallet, test_file, container, client_shell, cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Remove PutObject local override from first node"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowPutObject", + ) + + return object_id diff --git a/pytest_tests/testsuites/ape/test_ape.py b/pytest_tests/testsuites/ape/test_ape.py deleted file mode 100644 index 467f05fa..00000000 --- a/pytest_tests/testsuites/ape/test_ape.py +++ /dev/null @@ -1,1006 +0,0 @@ -import allure -import pytest -from frostfs_testlib.cli import FrostfsAdm, FrostfsCli -from frostfs_testlib.credentials.interfaces import User -from frostfs_testlib.reporter import get_reporter -from frostfs_testlib.resources.cli import FROSTFS_ADM_CONFIG_PATH, FROSTFS_ADM_EXEC, FROSTFS_CLI_EXEC -from frostfs_testlib.resources.error_patterns import ( - NO_RULE_FOUND_OBJECT, - OBJECT_ACCESS_DENIED, - RULE_ACCESS_DENIED_CONTAINER, - RULE_ACCESS_DENIED_OBJECT, -) -from frostfs_testlib.shell.interfaces import Shell -from frostfs_testlib.steps.cli.object import delete_object, get_object, get_range, get_range_hash, head_object, put_object, search_object -from frostfs_testlib.storage.cluster import Cluster, ClusterNode -from frostfs_testlib.storage.dataclasses.ape import Operations -from frostfs_testlib.storage.dataclasses.object_size import ObjectSize -from frostfs_testlib.testing.cluster_test_base import ClusterTestBase -from frostfs_testlib.testing.parallel import parallel -from frostfs_testlib.testing.test_control import expect_not_raises -from frostfs_testlib.utils.file_utils import generate_file - -reporter = get_reporter() - - -@pytest.fixture(scope="session") -def remote_frostfs_cli_first_node(cluster: Cluster): - node = cluster.cluster_nodes[0] - shell = node.host.get_shell() - cli = FrostfsCli( - shell=shell, - frostfs_cli_exec_path=FROSTFS_CLI_EXEC, - config_file=node.storage_node.get_remote_wallet_config_path(), - ) - return cli - - -def local_overrides_on_node(node: ClusterNode): - target = "Chain ID" - shell: Shell = node.host.get_shell() - remote_config: str = node.storage_node.get_remote_wallet_config_path() - cli = FrostfsCli(shell=shell, frostfs_cli_exec_path=FROSTFS_CLI_EXEC, config_file=remote_config) - with reporter.step(f"Check local overrides on {node.storage_node.id} node"): - rules = cli.control.list_rules( - endpoint=node.storage_node.get_control_endpoint(), target_name="root", target_type="namespace" - ).stdout - if target in rules: - with reporter.step("Delete rules"): - chain_ids = [i.split(" ")[2].strip() for i in rules.split("\n") if "Chain ID" in i] - for chain_id in chain_ids: - cli.control.remove_rule( - endpoint=node.storage_node.get_control_endpoint(), - target_type="namespace", - target_name="root", - chain_id=chain_id, - ) - - -@pytest.fixture(scope="session") -def remove_rule_ape_in_system(cluster: Cluster) -> None: - yield - with reporter.step("Check local overrides on nodes."): - parallel(local_overrides_on_node, cluster.cluster_nodes) - - -def pre_create_container_object_cli( - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - shell: Shell, - cluster: Cluster, -): - - test_file = generate_file(simple_object_size.value) - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 1 IN MOW CBF 1 SELECT 1 FROM MSK AS MOW FILTER SubDivCode EQ MOW AS MSK", - name="dcl1", - await_mode=True, - basic_acl="0", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowPutObject", - rule=f"allow Object.Put *", - ) - - with reporter.step("Put objects in container on the first node"): - oid = put_object(default_user.wallet, test_file, cid, shell, cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowPutObject", - ) - - return cid, oid - - -@pytest.mark.ape -@pytest.mark.ape_local -class TestApeLocalOverride(ClusterTestBase): - @allure.title("LocalOverride: Deny to GetContainer in root tenant") - def test_local_override_deny_to_get_container_root( - self, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - remove_rule_ape_in_system: None, - ): - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 4", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="namespace", - target_name="root", - chain_id="denyContainerGet", - rule="deny Container.Get *", - ) - - with reporter.step("Check get the container property on the first node, expected denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_CONTAINER.format(operation=Operations.GET_CONTAINER)): - frostfs_cli.container.get(self.cluster.storage_nodes[0].get_rpc_endpoint(), cid) - - with reporter.step("Check get the container property on the second node, expected allow"): - with expect_not_raises(): - frostfs_cli.container.get(self.cluster.storage_nodes[1].get_rpc_endpoint(), cid) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="namespace", - target_name="root", - chain_id="denyContainerGet", - ) - - with reporter.step("Check get the container property on the first node, expected allow"): - with expect_not_raises(): - frostfs_cli.container.get(self.cluster.storage_nodes[0].get_rpc_endpoint(), cid) - - @allure.title("LocalOverride: Deny to PutContainer in root tenant") - def test_local_override_deny_to_put_container_root( - self, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - remove_rule_ape_in_system: None, - ): - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="namespace", - target_name="root", - chain_id="denyContainerPut", - rule="deny Container.Put *", - ) - - with reporter.step("Check create container on the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_CONTAINER.format(operation=Operations.PUT_CONTAINER)): - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 4", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - - with reporter.step("Check create a container on the second node, expected allow"): - with expect_not_raises(): - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[1].get_rpc_endpoint(), - policy="REP 4", - name="dcl2", - await_mode=True, - basic_acl="public-read-write", - ) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="namespace", - target_name="root", - chain_id="denyContainerPut", - ) - - with reporter.step("Check create a container on the first node, expected allow"): - with expect_not_raises(): - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 4", - name="dcl3", - await_mode=True, - basic_acl="public-read-write", - ) - - @allure.title("LocalOverride: Deny to ListContainer in root tenant") - def test_local_override_deny_to_list_container_root( - self, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - remove_rule_ape_in_system: None, - ): - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="namespace", - target_name="root", - chain_id="denyContainerList", - rule="deny Container.List *", - ) - - with reporter.step("Check list the container properties on the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_CONTAINER.format(operation=Operations.LIST_CONTAINER)): - frostfs_cli.container.list(rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), ttl=1) - - with reporter.step("Check list the container properties on the second node, expected allow"): - with expect_not_raises(): - frostfs_cli.container.list(rpc_endpoint=self.cluster.storage_nodes[1].get_rpc_endpoint(), ttl=1) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="namespace", - target_name="root", - chain_id="denyContainerList", - ) - - with reporter.step("Check display a list of containers on the first node, expected allow"): - with expect_not_raises(): - frostfs_cli.container.list(rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), ttl=1) - - @allure.title("LocalOverride: Deny to DeleteContainer in root tenant") - def test_local_override_deny_to_delete_container_root( - self, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - remove_rule_ape_in_system: None, - ): - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="namespace", - target_name="root", - chain_id="denyContainerDelete", - rule="deny Container.Delete *", - ) - - with reporter.step("Create containers on the first node"): - cid_1 = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 4", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - cid_2 = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 4", - name="dcl2", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Check delete first container from the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_CONTAINER.format(operation=Operations.DELETE_CONTAINER)): - frostfs_cli.container.delete(self.cluster.storage_nodes[0].get_rpc_endpoint(), cid_1, ttl=1) - - with reporter.step("Check delete a second container from the second node, expected allow"): - with expect_not_raises(): - frostfs_cli.container.delete(self.cluster.storage_nodes[1].get_rpc_endpoint(), cid_2, ttl=1) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="namespace", - target_name="root", - chain_id="denyContainerDelete", - ) - - with reporter.step("Check delete first container from the first node, expected allow"): - with expect_not_raises(): - frostfs_cli.container.delete(self.cluster.storage_nodes[0].get_rpc_endpoint(), cid_1, ttl=1) - - @allure.title("LocalOverride: Deny to GetObject in root tenant") - def test_local_override_deny_to_get_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - test_file = generate_file(simple_object_size.value) - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 4", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a container rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyGetObject", - rule=f"deny Object.Get /{cid}/*", - ) - - with reporter.step("Put object in container on the first node"): - oid = put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check get object from container on the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT.format(operation=Operations.GET_OBJECT)): - get_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check get object from container on the second node, expected allow"): - with expect_not_raises(): - get_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyGetObject", - ) - - with reporter.step("Check get object in container on the first node, expected allow"): - with expect_not_raises(): - get_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - @allure.title("LocalOverride: Deny to PutObject in root tenant") - def test_local_override_deny_to_put_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - test_file = generate_file(simple_object_size.value) - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 4", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a container rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyPutObject", - rule=f"deny Object.Put /{cid}/*", - ) - - with reporter.step("Check put object from container on the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=OBJECT_ACCESS_DENIED): - put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check put object from container on the second node, expected allow"): - with expect_not_raises(): - put_object( - default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint(), copies_number=3 - ) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyPutObject", - ) - - with reporter.step("Check get object in container on the first node, expected allow"): - with expect_not_raises(): - put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - @allure.title("LocalOverride: Deny to HeadObject in root tenant") - def test_local_override_deny_to_head_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - test_file = generate_file(simple_object_size.value) - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 2", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a container rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyHeadObject", - rule=f"deny Object.Head /{cid}/*", - ) - - with reporter.step("Put object in container on the first node"): - oid = put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check head object from container on the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT.format(operation=Operations.HEAD_OBJECT)): - head_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check head object from container on the second node, expected allow"): - with expect_not_raises(): - head_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyHeadObject", - ) - - with reporter.step("Check head object in container on the first node, expected allow"): - with expect_not_raises(): - head_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - @allure.title("LocalOverride: Deny to SearchObject in root tenant") - def test_local_override_deny_to_search_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - test_file = generate_file(simple_object_size.value) - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 2", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a container rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denySearchObject", - rule=f"deny Object.Search /{cid}/*", - ) - - with reporter.step("Check search object from container on the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT.format(operation=Operations.SEARCH_OBJECT)): - search_object(default_user.wallet, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check search object from container on the second node, expected allow"): - with expect_not_raises(): - search_object(default_user.wallet, cid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denySearchObject", - ) - - with reporter.step("Check search object in container on the first node, expected allow"): - with expect_not_raises(): - search_object(default_user.wallet, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - @allure.title("LocalOverride: Deny to RangeObject in root tenant") - def test_local_override_deny_to_range_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - test_file = generate_file(simple_object_size.value) - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 2", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a container rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyRangeObject", - rule=f"deny Object.Range /{cid}/*", - ) - - with reporter.step("Put object in container on the first node"): - oid = put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check range object from container on the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT.format(operation=Operations.RANGE_OBJECT)): - get_range(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check get range object from container on the second node, expected allow"): - with expect_not_raises(): - get_range(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyRangeObject", - ) - - with reporter.step("Check get range object in container on the first node, expected allow"): - with expect_not_raises(): - get_range(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - @allure.title("LocalOverride: Deny to HashObject in root tenant") - def test_local_override_deny_to_hash_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - test_file = generate_file(simple_object_size.value) - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 2", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a container rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyHashObject", - rule=f"deny Object.Hash /{cid}/*", - ) - - with reporter.step("Put object in container on the first node"): - oid = put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check get range hash object from container on the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT.format(operation=Operations.HASH_OBJECT)): - get_range_hash(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check get range hash object from container on the second node, expected allow"): - with expect_not_raises(): - get_range_hash(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyHashObject", - ) - - with reporter.step("Check get range hash object in container on the first node, expected allow"): - with expect_not_raises(): - get_range_hash(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - @allure.title("LocalOverride: Deny to DeleteObject in root tenant") - def test_local_override_deny_to_delete_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - test_file = generate_file(simple_object_size.value) - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 2", - name="dcl1", - await_mode=True, - basic_acl="public-read-write", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a container rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyDeleteObject", - rule=f"deny Object.Delete /{cid}/*", - ) - - with reporter.step("Put objects in container on the first node"): - oid_1 = put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - oid_2 = put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Search object in container on the first node"): - search_object_in_container_1 = search_object( - default_user.wallet, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint() - ) - assert oid_1 in search_object_in_container_1, f"Object {oid_1} was not found" - assert oid_2 in search_object_in_container_1, f"Object {oid_2} was not found" - - with reporter.step("Search object from container on the second node"): - search_object_in_container_2 = search_object( - default_user.wallet, cid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint() - ) - assert oid_1 in search_object_in_container_2, f"Object {oid_1} was not found" - assert oid_2 in search_object_in_container_2, f"Object {oid_2} was not found" - - with reporter.step("Check delete object from container on the first node, expected access denied error"): - with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT.format(operation=Operations.DELETE_OBJECT)): - delete_object(default_user.wallet, cid, oid_1, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check delete object from container on the second node, expected allow"): - with expect_not_raises(): - delete_object(default_user.wallet, cid, oid_2, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="denyDeleteObject", - ) - - with reporter.step("Check delete object in container on the first node, expected allow"): - with expect_not_raises(): - delete_object(default_user.wallet, cid, oid_1, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - @allure.title("LocalOverride: Allow to GetObject in root tenant") - def test_local_override_allow_to_get_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - cid, oid = pre_create_container_object_cli( - default_user, remote_frostfs_cli_first_node, frostfs_cli, simple_object_size, self.shell, self.cluster - ) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowGetObject", - rule=f"allow Object.Get *", - ) - - with reporter.step("Check get object in container on the first node, expected allow"): - with expect_not_raises(): - get_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check get object in container on the second node, epxected access denied error"): - with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT.format(operation=Operations.GET_OBJECT)): - get_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowGetObject", - ) - - @allure.title("LocalOverride: Allow to PutObject in root tenant") - def test_local_override_allow_to_put_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - test_file = generate_file(simple_object_size.value) - - with reporter.step("Create a container on the first node"): - cid = ( - frostfs_cli.container.create( - rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), - policy="REP 1 IN MOW CBF 1 SELECT 1 FROM MSK AS MOW FILTER SubDivCode EQ MOW AS MSK", - name="dcl1", - await_mode=True, - basic_acl="0", - ) - .stdout.split(" ")[1] - .strip() - .split("\n")[0] - ) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowPutObject", - rule=f"allow Object.Put *", - ) - - with reporter.step("Check put object in container on the first node, expected allow"): - with expect_not_raises(): - put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check get object in container on the second node, epxected access denied error"): - with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT.format(operation=Operations.PUT_OBJECT)): - put_object(default_user.wallet, test_file, cid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowPutObject", - ) - - @allure.title("LocalOverride: Allow to HeadObject in root tenant") - def test_local_override_allow_to_head_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - cid, oid = pre_create_container_object_cli( - default_user, remote_frostfs_cli_first_node, frostfs_cli, simple_object_size, self.shell, self.cluster - ) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowHeadObject", - rule=f"allow Object.Head *", - ) - - with reporter.step("Check head object in container on the first node, expected allow"): - with expect_not_raises(): - head_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check head object in container on the second node, expected access denied error"): - with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT.format(operation=Operations.HEAD_OBJECT)): - head_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowHeadObject", - ) - - @allure.title("LocalOverride: Allow to SearchObject in root tenant") - def test_local_override_allow_to_search_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - cid, oid = pre_create_container_object_cli( - default_user, remote_frostfs_cli_first_node, frostfs_cli, simple_object_size, self.shell, self.cluster - ) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowSearchObject", - rule=f"allow Object.Search *", - ) - - with reporter.step("Check search object in container on the first node, expected allow"): - with expect_not_raises(): - search_object(default_user.wallet, cid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check search object from container on the second node, expected access denied error"): - with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT.format(operation=Operations.SEARCH_OBJECT)): - search_object(default_user.wallet, cid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowSearchObject", - ) - - @allure.title("LocalOverride: Allow to RangeObject in root tenant") - def test_local_override_allow_to_range_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - cid, oid = pre_create_container_object_cli( - default_user, remote_frostfs_cli_first_node, frostfs_cli, simple_object_size, self.shell, self.cluster - ) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowRangeObject", - rule=f"allow Object.Range *", - ) - - with reporter.step("Check get range object in container on the first node, expected allow"): - with expect_not_raises(): - get_range(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check range object in container on the second node. expected access denied error"): - with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT.format(operation=Operations.RANGE_OBJECT)): - get_range(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowRangeObject", - ) - - @allure.title("LocalOverride: Allow to HashObject in root tenant") - def test_local_override_allow_to_hash_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - cid, oid = pre_create_container_object_cli( - default_user, remote_frostfs_cli_first_node, frostfs_cli, simple_object_size, self.shell, self.cluster - ) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowHashObject", - rule=f"allow Object.Hash *", - ) - - with reporter.step("Check get range hash object in container on the first node, expected allow"): - with expect_not_raises(): - get_range_hash(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Check get range hash object in container on the second node, expected access denied error"): - with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT.format(operation=Operations.HASH_OBJECT)): - get_range_hash(default_user.wallet, cid, oid, "0:10", self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowHashObject", - ) - - @allure.title("LocalOverride: Allow to DeleteObject in root tenant") - def test_local_override_allow_to_delete_object_root( - self, - default_user: User, - remote_frostfs_cli_first_node: FrostfsCli, - frostfs_cli: FrostfsCli, - simple_object_size: ObjectSize, - ): - - cid, oid = pre_create_container_object_cli( - default_user, remote_frostfs_cli_first_node, frostfs_cli, simple_object_size, self.shell, self.cluster - ) - - with reporter.step("Create a namespace rule for the first node"): - remote_frostfs_cli_first_node.control.add_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowDeleteObject", - rule=f"allow Object.Head Object.Delete *", - ) - - with reporter.step("Check delete object from container on the second node, expected access denied error"): - with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT.format(operation=Operations.HEAD_OBJECT)): - delete_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) - - with reporter.step("Check delete object in container on the first node, expected allow"): - with expect_not_raises(): - delete_object(default_user.wallet, cid, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) - - with reporter.step("Delete a rule"): - remote_frostfs_cli_first_node.control.remove_rule( - endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), - target_type="container", - target_name=f"{cid}", - chain_id="allowDeleteObject", - ) diff --git a/pytest_tests/testsuites/ape/test_ape_local_container.py b/pytest_tests/testsuites/ape/test_ape_local_container.py new file mode 100644 index 00000000..4dd70c0f --- /dev/null +++ b/pytest_tests/testsuites/ape/test_ape_local_container.py @@ -0,0 +1,212 @@ +from time import sleep + +import allure +import pytest +from frostfs_testlib import reporter +from frostfs_testlib.cli import FrostfsCli +from frostfs_testlib.resources.cli import FROSTFS_CLI_EXEC +from frostfs_testlib.resources.common import MORPH_BLOCK_TIME +from frostfs_testlib.resources.error_patterns import RULE_ACCESS_DENIED_CONTAINER +from frostfs_testlib.shell.interfaces import Shell +from frostfs_testlib.storage.cluster import Cluster, ClusterNode +from frostfs_testlib.storage.dataclasses.ape import Operations +from frostfs_testlib.testing.cluster_test_base import ClusterTestBase +from frostfs_testlib.testing.parallel import parallel +from frostfs_testlib.testing.test_control import expect_not_raises +from frostfs_testlib.utils import datetime_utils + +from ...helpers.container_request import APE_EVERYONE_ALLOW_ALL, ContainerRequest, MultipleContainersRequest + +REP2 = ContainerRequest("REP 2", ape_rules=APE_EVERYONE_ALLOW_ALL, short_name="REP2_allow_all_ape") + + +def remove_local_overrides_on_node(node: ClusterNode): + target = "Chain ID" + shell: Shell = node.host.get_shell() + remote_config: str = node.storage_node.get_remote_wallet_config_path() + cli = FrostfsCli(shell=shell, frostfs_cli_exec_path=FROSTFS_CLI_EXEC, config_file=remote_config) + with reporter.step(f"Check local overrides on {node.storage_node.id} node"): + rules = cli.control.list_rules( + endpoint=node.storage_node.get_control_endpoint(), target_name="root", target_type="namespace" + ).stdout + if target in rules: + with reporter.step("Delete rules"): + chain_ids = [i.split(" ")[2].strip() for i in rules.split("\n") if "Chain ID" in i] + for chain_id in chain_ids: + cli.control.remove_rule( + endpoint=node.storage_node.get_control_endpoint(), + target_type="namespace", + target_name="root", + chain_id=chain_id, + ) + with reporter.step("Wait for one block"): + sleep(datetime_utils.parse_time(MORPH_BLOCK_TIME)) + + +@pytest.fixture(scope="session") +def remove_local_ape_overrides(cluster: Cluster) -> None: + yield + with reporter.step("Check local overrides on nodes."): + parallel(remove_local_overrides_on_node, cluster.cluster_nodes) + + +@pytest.mark.ape +@pytest.mark.ape_local +@pytest.mark.ape_container +@pytest.mark.ape_namespace +class TestApeLocalOverrideContainer(ClusterTestBase): + @allure.title("LocalOverride: Deny to GetContainer in root tenant") + def test_local_override_deny_to_get_container_root( + self, + frostfs_cli_on_first_node: FrostfsCli, + frostfs_cli: FrostfsCli, + container: str, + remove_local_ape_overrides: None, + ): + with reporter.step("Create a namespace rule for the first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="namespace", + target_name="root", + chain_id="denyContainerGet", + rule="deny Container.Get *", + ) + + with reporter.step("Check get the container property on the first node, expected denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_CONTAINER.format(operation=Operations.GET_CONTAINER)): + frostfs_cli.container.get(self.cluster.storage_nodes[0].get_rpc_endpoint(), container) + + with reporter.step("Check get the container property on the second node, expected allow"): + with expect_not_raises(): + frostfs_cli.container.get(self.cluster.storage_nodes[1].get_rpc_endpoint(), container) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="namespace", + target_name="root", + chain_id="denyContainerGet", + ) + + with reporter.step("Check get the container property on the first node, expected allow"): + with expect_not_raises(): + frostfs_cli.container.get(self.cluster.storage_nodes[0].get_rpc_endpoint(), container) + + @allure.title("LocalOverride: Deny to PutContainer in root tenant") + def test_local_override_deny_to_put_container_root( + self, + frostfs_cli_on_first_node: FrostfsCli, + frostfs_cli: FrostfsCli, + remove_local_ape_overrides: None, + ): + with reporter.step("Create a namespace rule for the first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="namespace", + target_name="root", + chain_id="denyContainerPut", + rule="deny Container.Put *", + ) + + with reporter.step("Check create container on the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_CONTAINER.format(operation=Operations.PUT_CONTAINER)): + frostfs_cli.container.create( + rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), + policy="REP 1", + ) + + with reporter.step("Check create a container on the second node, expected allow"): + with expect_not_raises(): + frostfs_cli.container.create( + rpc_endpoint=self.cluster.storage_nodes[1].get_rpc_endpoint(), + policy="REP 1", + ) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="namespace", + target_name="root", + chain_id="denyContainerPut", + ) + + with reporter.step("Check create a container on the first node, expected allow"): + with expect_not_raises(): + frostfs_cli.container.create( + rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), + policy="REP 1", + ) + + @allure.title("LocalOverride: Deny to ListContainer in root tenant") + def test_local_override_deny_to_list_container_root( + self, + frostfs_cli_on_first_node: FrostfsCli, + frostfs_cli: FrostfsCli, + remove_local_ape_overrides: None, + ): + with reporter.step("Create a namespace rule for the first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="namespace", + target_name="root", + chain_id="denyContainerList", + rule="deny Container.List *", + ) + + with reporter.step("Check list the container properties on the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_CONTAINER.format(operation=Operations.LIST_CONTAINER)): + frostfs_cli.container.list(rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), ttl=1) + + with reporter.step("Check list the container properties on the second node, expected allow"): + with expect_not_raises(): + frostfs_cli.container.list(rpc_endpoint=self.cluster.storage_nodes[1].get_rpc_endpoint(), ttl=1) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="namespace", + target_name="root", + chain_id="denyContainerList", + ) + + with reporter.step("Check display a list of containers on the first node, expected allow"): + with expect_not_raises(): + frostfs_cli.container.list(rpc_endpoint=self.cluster.storage_nodes[0].get_rpc_endpoint(), ttl=1) + + @allure.title("LocalOverride: Deny to DeleteContainer in root tenant") + @pytest.mark.parametrize("multiple_containers_request", [MultipleContainersRequest([REP2, REP2])], indirect=True) + def test_local_override_deny_to_delete_container_root( + self, + frostfs_cli_on_first_node: FrostfsCli, + frostfs_cli: FrostfsCli, + remove_local_ape_overrides: None, + containers: list[str], + ): + with reporter.step("Create a namespace rule for the first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="namespace", + target_name="root", + chain_id="denyContainerDelete", + rule="deny Container.Delete *", + ) + + with reporter.step("Check delete first container from the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_CONTAINER.format(operation=Operations.DELETE_CONTAINER)): + frostfs_cli.container.delete(self.cluster.storage_nodes[0].get_rpc_endpoint(), containers[0], ttl=1) + + with reporter.step("Check delete a second container from the second node, expected allow"): + with expect_not_raises(): + frostfs_cli.container.delete(self.cluster.storage_nodes[1].get_rpc_endpoint(), containers[1], ttl=1) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="namespace", + target_name="root", + chain_id="denyContainerDelete", + ) + + with reporter.step("Check delete first container from the first node, expected allow"): + with expect_not_raises(): + frostfs_cli.container.delete(self.cluster.storage_nodes[0].get_rpc_endpoint(), containers[0], ttl=1) diff --git a/pytest_tests/testsuites/ape/test_ape_local_object_allow.py b/pytest_tests/testsuites/ape/test_ape_local_object_allow.py new file mode 100644 index 00000000..f9624951 --- /dev/null +++ b/pytest_tests/testsuites/ape/test_ape_local_object_allow.py @@ -0,0 +1,254 @@ +import allure +import pytest +from frostfs_testlib import reporter +from frostfs_testlib.cli import FrostfsCli +from frostfs_testlib.resources.error_patterns import NO_RULE_FOUND_OBJECT +from frostfs_testlib.steps.cli.object import delete_object, get_object, get_range, get_range_hash, head_object, put_object, search_object +from frostfs_testlib.storage.dataclasses.object_size import ObjectSize +from frostfs_testlib.storage.dataclasses.wallet import WalletInfo +from frostfs_testlib.testing.cluster_test_base import ClusterTestBase +from frostfs_testlib.testing.test_control import expect_not_raises +from frostfs_testlib.utils.file_utils import generate_file + +from ...helpers.container_request import ContainerRequest + +REP1_MSK = ContainerRequest("REP 1 IN MOW CBF 1 SELECT 1 FROM MSK AS MOW FILTER SubDivCode EQ MOW AS MSK", short_name="REP1_MSK_no_ape") + + +@pytest.mark.ape +@pytest.mark.ape_local +@pytest.mark.ape_object +@pytest.mark.ape_allow +@pytest.mark.parametrize("container_request", [REP1_MSK], indirect=True) +class TestApeLocalOverrideAllow(ClusterTestBase): + @allure.title("LocalOverride: Allow to GetObject in root tenant") + def test_local_override_allow_to_get_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + container: str, + object_id: str, + ): + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowGetObject", + rule=f"allow Object.Get *", + ) + + with reporter.step("Check get object in container on the first node, expected allow"): + with expect_not_raises(): + get_object(default_wallet, container, object_id, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check get object in container on the second node, epxected access denied error"): + with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT): + get_object(default_wallet, container, object_id, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowGetObject", + ) + + @allure.title("LocalOverride: Allow to PutObject in root tenant") + def test_local_override_allow_to_put_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + simple_object_size: ObjectSize, + container: str, + ): + test_file = generate_file(simple_object_size.value) + + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowPutObject", + rule=f"allow Object.Put *", + ) + + with reporter.step("Check put object in container on the first node, expected allow"): + with expect_not_raises(): + put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check get object in container on the second node, epxected access denied error"): + with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT): + put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowPutObject", + ) + + @allure.title("LocalOverride: Allow to HeadObject in root tenant") + def test_local_override_allow_to_head_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + container: str, + object_id: str, + ): + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowHeadObject", + rule=f"allow Object.Head *", + ) + + with reporter.step("Check head object in container on the first node, expected allow"): + with expect_not_raises(): + head_object(default_wallet, container, object_id, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check head object in container on the second node, expected access denied error"): + with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT): + head_object(default_wallet, container, object_id, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowHeadObject", + ) + + @allure.title("LocalOverride: Allow to SearchObject in root tenant") + def test_local_override_allow_to_search_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + container: str, + ): + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowSearchObject", + rule=f"allow Object.Search *", + ) + + with reporter.step("Check search object in container on the first node, expected allow"): + with expect_not_raises(): + search_object(default_wallet, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check search object from container on the second node, expected access denied error"): + with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT): + search_object(default_wallet, container, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowSearchObject", + ) + + @allure.title("LocalOverride: Allow to RangeObject in root tenant") + def test_local_override_allow_to_range_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + container: str, + object_id: str, + ): + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowRangeObject", + rule=f"allow Object.Range *", + ) + + with reporter.step("Check get range object in container on the first node, expected allow"): + with expect_not_raises(): + get_range(default_wallet, container, object_id, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check range object in container on the second node. expected access denied error"): + with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT): + get_range(default_wallet, container, object_id, "0:10", self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowRangeObject", + ) + + @allure.title("LocalOverride: Allow to HashObject in root tenant") + def test_local_override_allow_to_hash_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + container: str, + object_id: str, + ): + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowHashObject", + rule=f"allow Object.Hash *", + ) + + with reporter.step("Check get range hash object in container on the first node, expected allow"): + with expect_not_raises(): + get_range_hash(default_wallet, container, object_id, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check get range hash object in container on the second node, expected access denied error"): + with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT): + get_range_hash(default_wallet, container, object_id, "0:10", self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowHashObject", + ) + + @allure.title("LocalOverride: Allow to DeleteObject in root tenant") + def test_local_override_allow_to_delete_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + container: str, + object_id: str, + ): + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowDeleteObject", + rule=f"allow Object.Head Object.Delete *", + ) + + with reporter.step("Check delete object from container on the second node, expected access denied error"): + with pytest.raises(RuntimeError, match=NO_RULE_FOUND_OBJECT): + delete_object(default_wallet, container, object_id, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Check delete object in container on the first node, expected allow"): + with expect_not_raises(): + delete_object(default_wallet, container, object_id, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="allowDeleteObject", + ) diff --git a/pytest_tests/testsuites/ape/test_ape_local_object_deny.py b/pytest_tests/testsuites/ape/test_ape_local_object_deny.py new file mode 100644 index 00000000..70131cd5 --- /dev/null +++ b/pytest_tests/testsuites/ape/test_ape_local_object_deny.py @@ -0,0 +1,333 @@ +import allure +import pytest +from frostfs_testlib.cli import FrostfsCli +from frostfs_testlib.reporter import get_reporter +from frostfs_testlib.resources.error_patterns import OBJECT_ACCESS_DENIED, RULE_ACCESS_DENIED_OBJECT +from frostfs_testlib.steps.cli.object import delete_object, get_object, get_range, get_range_hash, head_object, put_object, search_object +from frostfs_testlib.storage.dataclasses.ape import Operations +from frostfs_testlib.storage.dataclasses.object_size import ObjectSize +from frostfs_testlib.storage.dataclasses.wallet import WalletInfo +from frostfs_testlib.testing.cluster_test_base import ClusterTestBase +from frostfs_testlib.testing.test_control import expect_not_raises +from frostfs_testlib.utils.file_utils import generate_file + +from ...helpers.container_request import APE_EVERYONE_ALLOW_ALL, ContainerRequest + +reporter = get_reporter() + +REP2 = ContainerRequest("REP 2", ape_rules=APE_EVERYONE_ALLOW_ALL, short_name="REP2_allow_all_ape") + + +@pytest.mark.ape +@pytest.mark.ape_local +@pytest.mark.ape_object +@pytest.mark.ape_deny +class TestApeLocalOverrideDeny(ClusterTestBase): + @allure.title("LocalOverride: Deny to GetObject in root tenant") + @pytest.mark.parametrize("container_request", [REP2], indirect=True) + def test_local_override_deny_to_get_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + simple_object_size: ObjectSize, + container: str, + ): + test_file = generate_file(simple_object_size.value) + + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyGetObject", + rule=f"deny Object.Get /{container}/*", + ) + + with reporter.step("Put object in container on the first node"): + oid = put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check get object from container on the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT): + get_object(default_wallet, container, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check get object from container on the second node, expected allow"): + with expect_not_raises(): + get_object(default_wallet, container, oid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyGetObject", + ) + + with reporter.step("Check get object in container on the first node, expected allow"): + with expect_not_raises(): + get_object(default_wallet, container, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + @allure.title("LocalOverride: Deny to PutObject in root tenant") + @pytest.mark.parametrize("container_request", [REP2], indirect=True) + def test_local_override_deny_to_put_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + simple_object_size: ObjectSize, + container: str, + ): + test_file = generate_file(simple_object_size.value) + + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyPutObject", + rule=f"deny Object.Put /{container}/*", + ) + + with reporter.step("Check put object from container on the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=OBJECT_ACCESS_DENIED): + put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check put object from container on the second node, expected allow"): + with expect_not_raises(): + put_object( + default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint(), copies_number=3 + ) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyPutObject", + ) + + with reporter.step("Check get object in container on the first node, expected allow"): + with expect_not_raises(): + put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + @allure.title("LocalOverride: Deny to HeadObject in root tenant") + @pytest.mark.parametrize("container_request", [REP2], indirect=True) + def test_local_override_deny_to_head_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + simple_object_size: ObjectSize, + container: str, + ): + test_file = generate_file(simple_object_size.value) + + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyHeadObject", + rule=f"deny Object.Head /{container}/*", + ) + + with reporter.step("Put object in container on the first node"): + oid = put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check head object from container on the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT): + head_object(default_wallet, container, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check head object from container on the second node, expected allow"): + with expect_not_raises(): + head_object(default_wallet, container, oid, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyHeadObject", + ) + + with reporter.step("Check head object in container on the first node, expected allow"): + with expect_not_raises(): + head_object(default_wallet, container, oid, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + @allure.title("LocalOverride: Deny to SearchObject in root tenant") + @pytest.mark.parametrize("container_request", [REP2], indirect=True) + def test_local_override_deny_to_search_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + container: str, + ): + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denySearchObject", + rule=f"deny Object.Search /{container}/*", + ) + + with reporter.step("Check search object from container on the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT.format(operation=Operations.SEARCH_OBJECT)): + search_object(default_wallet, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check search object from container on the second node, expected allow"): + with expect_not_raises(): + search_object(default_wallet, container, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denySearchObject", + ) + + with reporter.step("Check search object in container on the first node, expected allow"): + with expect_not_raises(): + search_object(default_wallet, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + @allure.title("LocalOverride: Deny to RangeObject in root tenant") + @pytest.mark.parametrize("container_request", [REP2], indirect=True) + def test_local_override_deny_to_range_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + simple_object_size: ObjectSize, + container: str, + ): + test_file = generate_file(simple_object_size.value) + + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyRangeObject", + rule=f"deny Object.Range /{container}/*", + ) + + with reporter.step("Put object in container on the first node"): + oid = put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check range object from container on the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT.format(operation=Operations.RANGE_OBJECT)): + get_range(default_wallet, container, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check get range object from container on the second node, expected allow"): + with expect_not_raises(): + get_range(default_wallet, container, oid, "0:10", self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyRangeObject", + ) + + with reporter.step("Check get range object in container on the first node, expected allow"): + with expect_not_raises(): + get_range(default_wallet, container, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + @allure.title("LocalOverride: Deny to HashObject in root tenant") + @pytest.mark.parametrize("container_request", [REP2], indirect=True) + def test_local_override_deny_to_hash_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + simple_object_size: ObjectSize, + container: str, + ): + test_file = generate_file(simple_object_size.value) + + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyHashObject", + rule=f"deny Object.Hash /{container}/*", + ) + + with reporter.step("Put object in container on the first node"): + oid = put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check get range hash object from container on the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT.format(operation=Operations.HASH_OBJECT)): + get_range_hash(default_wallet, container, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check get range hash object from container on the second node, expected allow"): + with expect_not_raises(): + get_range_hash(default_wallet, container, oid, "0:10", self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyHashObject", + ) + + with reporter.step("Check get range hash object in container on the first node, expected allow"): + with expect_not_raises(): + get_range_hash(default_wallet, container, oid, "0:10", self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + @allure.title("LocalOverride: Deny to DeleteObject in root tenant") + @pytest.mark.parametrize("container_request", [REP2], indirect=True) + def test_local_override_deny_to_delete_object_root( + self, + default_wallet: WalletInfo, + frostfs_cli_on_first_node: FrostfsCli, + simple_object_size: ObjectSize, + container: str, + ): + test_file = generate_file(simple_object_size.value) + + with reporter.step("Create local override on first node"): + frostfs_cli_on_first_node.control.add_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyDeleteObject", + rule=f"deny Object.Delete /{container}/*", + ) + + with reporter.step("Put objects in container on the first node"): + oid_1 = put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + oid_2 = put_object(default_wallet, test_file, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Search object in container on the first node"): + search_object_in_container_1 = search_object( + default_wallet, container, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint() + ) + assert oid_1 in search_object_in_container_1, f"Object {oid_1} was not found" + assert oid_2 in search_object_in_container_1, f"Object {oid_2} was not found" + + with reporter.step("Search object from container on the second node"): + search_object_in_container_2 = search_object( + default_wallet, container, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint() + ) + assert oid_1 in search_object_in_container_2, f"Object {oid_1} was not found" + assert oid_2 in search_object_in_container_2, f"Object {oid_2} was not found" + + with reporter.step("Check delete object from container on the first node, expected access denied error"): + with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT): + delete_object(default_wallet, container, oid_1, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) + + with reporter.step("Check delete object from container on the second node, expected allow"): + with expect_not_raises(): + delete_object(default_wallet, container, oid_2, self.shell, self.cluster.storage_nodes[1].get_rpc_endpoint()) + + with reporter.step("Delete a rule"): + frostfs_cli_on_first_node.control.remove_rule( + endpoint=self.cluster.storage_nodes[0].get_control_endpoint(), + target_type="container", + target_name=container, + chain_id="denyDeleteObject", + ) + + with reporter.step("Check delete object in container on the first node, expected allow"): + with expect_not_raises(): + delete_object(default_wallet, container, oid_1, self.shell, self.cluster.storage_nodes[0].get_rpc_endpoint()) diff --git a/pytest_tests/testsuites/conftest.py b/pytest_tests/testsuites/conftest.py index ba6ac7a4..6e778dfa 100644 --- a/pytest_tests/testsuites/conftest.py +++ b/pytest_tests/testsuites/conftest.py @@ -34,8 +34,8 @@ from frostfs_testlib.testing.test_control import cached_fixture, run_optionally, from frostfs_testlib.utils import env_utils, string_utils, version_utils from frostfs_testlib.utils.file_utils import TestFile, generate_file -from ..helpers.container_creation import create_container_with_ape -from ..helpers.container_request import EVERYONE_ALLOW_ALL, ContainerRequest +from ..helpers.container_creation import create_container_with_ape, create_containers_with_ape +from ..helpers.container_request import EVERYONE_ALLOW_ALL, ContainerRequest, MultipleContainersRequest from ..resources.common import TEST_CYCLES_COUNT logger = logging.getLogger("NeoLogger") @@ -511,6 +511,17 @@ def container_request(request: pytest.FixtureRequest) -> ContainerRequest: return container_request +@pytest.fixture(scope="session") +def multiple_containers_request(request: pytest.FixtureRequest) -> ContainerRequest: + if "param" in request.__dict__: + return request.param + + raise RuntimeError( + f"""Container specification is empty. + Add @pytest.mark.parametrize("container_requests", [[ContainerRequest(...), ..., ContainerRequest(...)]], indirect=True) decorator.""" + ) + + @pytest.fixture def container( default_wallet: WalletInfo, @@ -520,7 +531,19 @@ def container( rpc_endpoint: str, container_request: ContainerRequest, ) -> str: - return create_container_with_ape(frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint, container_request) + return create_container_with_ape(container_request, frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint) + + +@pytest.fixture +def containers( + default_wallet: WalletInfo, + frostfs_cli: FrostfsCli, + client_shell: Shell, + cluster: Cluster, + rpc_endpoint: str, + multiple_containers_request: MultipleContainersRequest, +) -> list[str]: + return create_containers_with_ape(frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint, multiple_containers_request) @pytest.fixture() diff --git a/pytest_tests/testsuites/container/test_container.py b/pytest_tests/testsuites/container/test_container.py index 0790e043..685d55b7 100644 --- a/pytest_tests/testsuites/container/test_container.py +++ b/pytest_tests/testsuites/container/test_container.py @@ -37,7 +37,6 @@ class TestContainer(ClusterTestBase): container_info = container_info.casefold() # To ignore case when comparing with expected values info_to_check = { - f"basic ACL: {PRIVATE_ACL_F} (private)", f"owner ID: {wallet.get_address_from_json(0)}", f"CID: {cid}", } diff --git a/pytest_tests/testsuites/container/test_policy_with_price.py b/pytest_tests/testsuites/container/test_policy_with_price.py index b1734c08..a431dfd8 100644 --- a/pytest_tests/testsuites/container/test_policy_with_price.py +++ b/pytest_tests/testsuites/container/test_policy_with_price.py @@ -72,7 +72,7 @@ class TestPolicyWithPrice(ClusterTestBase): # In these set of tests containers should be created after the fill_field_price fixture fill_field_price, ) -> str: - return create_container_with_ape(frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint, container_request) + return create_container_with_ape(container_request, frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint) @allure.title("Policy with SELECT and FILTER results with 25% of available nodes") @pytest.mark.parametrize( diff --git a/pytest_tests/testsuites/object/test_object_api.py b/pytest_tests/testsuites/object/test_object_api.py index 1023e68e..cce5ba6f 100755 --- a/pytest_tests/testsuites/object/test_object_api.py +++ b/pytest_tests/testsuites/object/test_object_api.py @@ -103,7 +103,7 @@ def common_container( rpc_endpoint: str, ) -> str: container_request = ContainerRequest(COMMON_CONTAINER_RULE, APE_EVERYONE_ALLOW_ALL) - return create_container_with_ape(frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint, container_request) + return create_container_with_ape(container_request, frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint) @pytest.fixture(scope="module") @@ -131,7 +131,7 @@ def storage_objects( rpc_endpoint: str, ) -> list[StorageObjectInfo]: cid = create_container_with_ape( - frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint, ContainerRequest(placement_policy.value, APE_EVERYONE_ALLOW_ALL) + ContainerRequest(placement_policy.value, APE_EVERYONE_ALLOW_ALL), frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint ) with reporter.step("Generate file"): diff --git a/pytest_tests/testsuites/object/test_object_api_bearer.py b/pytest_tests/testsuites/object/test_object_api_bearer.py index ba031326..be679c2c 100644 --- a/pytest_tests/testsuites/object/test_object_api_bearer.py +++ b/pytest_tests/testsuites/object/test_object_api_bearer.py @@ -32,7 +32,7 @@ def user_container( ) -> StorageContainer: policy = request.param if "param" in request.__dict__ else SINGLE_PLACEMENT_RULE container_request = ContainerRequest(policy) - container_id = create_container_with_ape(frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint, container_request) + container_id = create_container_with_ape(container_request, frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint) # Deliberately using s3gate wallet here to test bearer token s3_gate_wallet = WalletInfo.from_node(cluster.s3_gates[0]) diff --git a/pytest_tests/testsuites/object/test_object_lock.py b/pytest_tests/testsuites/object/test_object_lock.py index 0b9fe488..2c708a9f 100755 --- a/pytest_tests/testsuites/object/test_object_lock.py +++ b/pytest_tests/testsuites/object/test_object_lock.py @@ -43,7 +43,7 @@ FIXTURE_OBJECT_LIFETIME = 10 def user_container( frostfs_cli: FrostfsCli, default_wallet: WalletInfo, client_shell: Shell, cluster: Cluster, rpc_endpoint: str ) -> StorageContainer: - cid = create_container_with_ape(frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint, EVERYONE_ALLOW_ALL) + cid = create_container_with_ape(EVERYONE_ALLOW_ALL, frostfs_cli, default_wallet, client_shell, cluster, rpc_endpoint) return StorageContainer(StorageContainerInfo(cid, default_wallet), client_shell, cluster)