import allure import pytest from frostfs_testlib import reporter from frostfs_testlib.cli import FrostfsCli from frostfs_testlib.resources.error_patterns import RULE_ACCESS_DENIED_OBJECT from frostfs_testlib.storage.grpc_operations.interfaces import GrpcClientWrapper 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 TestFile from ...helpers.container_request import APE_EVERYONE_ALLOW_ALL, ContainerRequest 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) @pytest.mark.parametrize("object_size", ["simple"], indirect=True) def test_local_override_deny_to_get_object_root( self, frostfs_cli_on_first_node: FrostfsCli, grpc_client: GrpcClientWrapper, container: str, test_file: TestFile, ): 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 = grpc_client.object.put(test_file, container, 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): grpc_client.object.get(container, oid, 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(): grpc_client.object.get(container, oid, 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(): grpc_client.object.get(container, oid, 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) @pytest.mark.parametrize("object_size", ["simple"], indirect=True) def test_local_override_deny_to_put_object_root( self, frostfs_cli_on_first_node: FrostfsCli, grpc_client: GrpcClientWrapper, container: str, test_file: TestFile, ): 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=RULE_ACCESS_DENIED_OBJECT): grpc_client.object.put(test_file, container, 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(): grpc_client.object.put(test_file, container, 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="denyPutObject", ) with reporter.step("Check get object in container on the first node, expected allow"): with expect_not_raises(): grpc_client.object.put(test_file, container, 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) @pytest.mark.parametrize("object_size", ["simple"], indirect=True) def test_local_override_deny_to_head_object_root( self, frostfs_cli_on_first_node: FrostfsCli, grpc_client: GrpcClientWrapper, container: str, test_file: TestFile, ): 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 = grpc_client.object.put(test_file, container, 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): grpc_client.object.head(container, oid, 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(): grpc_client.object.head(container, oid, 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(): grpc_client.object.head(container, oid, 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, frostfs_cli_on_first_node: FrostfsCli, grpc_client: GrpcClientWrapper, 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): grpc_client.object.search(container, 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(): grpc_client.object.search(container, 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(): grpc_client.object.search(container, 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) @pytest.mark.parametrize("object_size", ["simple"], indirect=True) def test_local_override_deny_to_range_object_root( self, frostfs_cli_on_first_node: FrostfsCli, grpc_client: GrpcClientWrapper, container: str, test_file: TestFile, ): 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 = grpc_client.object.put(test_file, container, 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): grpc_client.object.range(container, oid, "0:10", 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(): grpc_client.object.range(container, oid, "0:10", 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(): grpc_client.object.range(container, oid, "0:10", 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) @pytest.mark.parametrize("object_size", ["simple"], indirect=True) def test_local_override_deny_to_hash_object_root( self, frostfs_cli_on_first_node: FrostfsCli, grpc_client: GrpcClientWrapper, container: str, test_file: TestFile, ): 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 = grpc_client.object.put(test_file, container, 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): grpc_client.object.hash(self.cluster.storage_nodes[0].get_rpc_endpoint(), container, oid, range="0:10") with reporter.step("Check get range hash object from container on the second node, expected allow"): with expect_not_raises(): grpc_client.object.hash(self.cluster.storage_nodes[1].get_rpc_endpoint(), container, oid, range="0:10") 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(): grpc_client.object.hash(self.cluster.storage_nodes[0].get_rpc_endpoint(), container, oid, range="0:10") @allure.title("LocalOverride: Deny to DeleteObject in root tenant") @pytest.mark.parametrize("container_request", [REP2], indirect=True) @pytest.mark.parametrize("object_size", ["simple"], indirect=True) def test_local_override_deny_to_delete_object_root( self, frostfs_cli_on_first_node: FrostfsCli, grpc_client: GrpcClientWrapper, container: str, test_file: TestFile, ): 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 = grpc_client.object.put(test_file, container, self.cluster.storage_nodes[0].get_rpc_endpoint()) oid_2 = grpc_client.object.put(test_file, container, self.cluster.storage_nodes[0].get_rpc_endpoint()) with reporter.step("Search object in container on the first node"): search_object_in_container_1 = grpc_client.object.search(container, 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 = grpc_client.object.search(container, 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): grpc_client.object.delete(container, oid_1, 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(): grpc_client.object.delete(container, oid_2, 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(): grpc_client.object.delete(container, oid_1, self.cluster.storage_nodes[0].get_rpc_endpoint()) @allure.title("LocalOverride: Deny to PatchObject in root tenant") @pytest.mark.parametrize("container_request", [REP2], indirect=True) @pytest.mark.parametrize("object_size", ["simple"], indirect=True) def test_local_override_deny_to_patch_object_root( self, frostfs_cli_on_first_node: FrostfsCli, grpc_client: GrpcClientWrapper, test_file: TestFile, 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="denyPatchObject", rule=f"deny Object.Patch /{container}/*", ) with reporter.step("Check patch object from container on the first node, expected access denied error"): with pytest.raises(RuntimeError, match=RULE_ACCESS_DENIED_OBJECT): grpc_client.object.patch( container, object_id, self.cluster.storage_nodes[0].get_rpc_endpoint(), ranges=["0:350"], payloads=[test_file], new_attrs="patched_by_first_node=false", timeout="200s", ) with reporter.step("Check patch object from container on the second node, expected allow"): with expect_not_raises(): patched_oid_1 = grpc_client.object.patch( container, object_id, self.cluster.storage_nodes[1].get_rpc_endpoint(), ranges=["200:400"], payloads=[test_file], new_attrs="patched_by_second_node=true", timeout="200s", ) assert patched_oid_1 != object_id, "OID of patched object must be different from original one" 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="denyPatchObject", ) with reporter.step("Check patch object in container on the first node, expected allow"): with expect_not_raises(): patched_oid_2 = grpc_client.object.patch( container, patched_oid_1, self.cluster.storage_nodes[0].get_rpc_endpoint(), ranges=["600:0"], payloads=[test_file], new_attrs="patched_by_first_node=true", timeout="200s", ) assert patched_oid_1 != patched_oid_2, "OID of patched object must be different from original one"