a.berezin
fe17f2236b
Some checks reported warnings
DCO check / Commits Check (pull_request) Has been cancelled
Signed-off-by: a.berezin <a.berezin@yadro.com>
226 lines
11 KiB
Python
226 lines
11 KiB
Python
import allure
|
|
import pytest
|
|
from frostfs_testlib import reporter
|
|
from frostfs_testlib.cli.frostfs_cli.cli import FrostfsCli
|
|
from frostfs_testlib.resources.wellknown_acl import PUBLIC_ACL
|
|
from frostfs_testlib.steps.cli.container import create_container
|
|
from frostfs_testlib.steps.cli.object import put_object_to_random_node
|
|
from frostfs_testlib.steps.node_management import drop_object
|
|
from frostfs_testlib.storage.dataclasses import ape
|
|
from frostfs_testlib.storage.dataclasses.wallet import WalletInfo
|
|
from frostfs_testlib.testing.cluster_test_base import ClusterTestBase
|
|
from frostfs_testlib.utils import wallet_utils
|
|
from frostfs_testlib.utils.failover_utils import wait_object_replication
|
|
from frostfs_testlib.utils.file_utils import TestFile
|
|
|
|
from pytest_tests.helpers.container_access import (
|
|
ALL_OBJECT_OPERATIONS,
|
|
assert_access_to_container,
|
|
assert_full_access_to_container,
|
|
assert_no_access_to_container,
|
|
)
|
|
|
|
|
|
@pytest.mark.ape
|
|
class TestApeContainer(ClusterTestBase):
|
|
@pytest.fixture(scope="function")
|
|
def full_placement_container_with_object(self, default_wallet: WalletInfo, file_path: str) -> tuple[str, str, str]:
|
|
storage_nodes = self.cluster.storage_nodes
|
|
node_count = len(storage_nodes)
|
|
with reporter.step("Create public container with full placement rule"):
|
|
full_placement_rule = f"REP {node_count} IN X CBF 1 SELECT {node_count} FROM * AS X"
|
|
cid = create_container(default_wallet, self.shell, self.cluster.default_rpc_endpoint, full_placement_rule, PUBLIC_ACL)
|
|
|
|
with reporter.step("Put object to container"):
|
|
oid = put_object_to_random_node(default_wallet, file_path, cid, shell=self.shell, cluster=self.cluster)
|
|
wait_object_replication(cid, oid, node_count, shell=self.shell, nodes=storage_nodes)
|
|
|
|
yield cid, oid
|
|
|
|
@pytest.mark.sanity
|
|
@allure.title("Deny operations via APE by role (role={role}, obj_size={object_size})")
|
|
@pytest.mark.parametrize("role", [ape.Role.OWNER, ape.Role.OTHERS], indirect=True)
|
|
def test_deny_operations_via_ape_by_role(
|
|
self,
|
|
default_wallet: WalletInfo,
|
|
other_wallet: WalletInfo,
|
|
frostfs_cli: FrostfsCli,
|
|
container_with_objects: tuple[str, list[str], str],
|
|
role: ape.Role,
|
|
file_path: TestFile,
|
|
):
|
|
denied_wallet = other_wallet if role == ape.Role.OTHERS else default_wallet
|
|
allowed_wallet = default_wallet if role == ape.Role.OTHERS else other_wallet
|
|
allowed_role = ape.Role.OWNER if role == ape.Role.OTHERS else ape.Role.OTHERS
|
|
cid, object_oids, file_path = container_with_objects
|
|
endpoint = self.cluster.default_rpc_endpoint
|
|
|
|
role_condition = ape.Condition.by_role(role.value)
|
|
|
|
with reporter.step(f"Deny all operations for {role} via APE"):
|
|
deny_rule = ape.Rule(ape.Verb.DENY, ALL_OBJECT_OPERATIONS, role_condition)
|
|
frostfs_cli.ape_manager.add(endpoint, deny_rule.chain_id, target_name=cid, target_type="container", rule=deny_rule.as_string())
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step(f"Assert {role} have no access to public container"):
|
|
assert_no_access_to_container(denied_wallet, cid, object_oids[0], file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step(f"Assert {allowed_role} have full access to public container"):
|
|
assert_full_access_to_container(allowed_wallet, cid, object_oids.pop(), file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step(f"Remove deny rule from APE"):
|
|
frostfs_cli.ape_manager.remove(endpoint, deny_rule.chain_id, target_name=cid, target_type="container")
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step("Assert owner have full access to public container"):
|
|
assert_full_access_to_container(default_wallet, cid, object_oids.pop(), file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step("Assert others have full access to public container"):
|
|
assert_full_access_to_container(other_wallet, cid, object_oids.pop(), file_path, self.shell, self.cluster)
|
|
|
|
@allure.title("Deny operations for others via APE excluding single pubkey (obj_size={object_size})")
|
|
def test_deny_opeartions_excluding_pubkey(
|
|
self,
|
|
frostfs_cli: FrostfsCli,
|
|
default_wallet: WalletInfo,
|
|
other_wallet: WalletInfo,
|
|
other_wallet_2: WalletInfo,
|
|
container_with_objects: tuple[str, list[str], str],
|
|
):
|
|
endpoint = self.cluster.default_rpc_endpoint
|
|
cid, object_oids, file_path = container_with_objects
|
|
|
|
with reporter.step("Add deny APE rules for others except single wallet"):
|
|
rule_conditions = [
|
|
ape.Condition.by_role(ape.Role.OTHERS),
|
|
ape.Condition.by_key(
|
|
wallet_utils.get_wallet_public_key(other_wallet_2.path, other_wallet_2.password),
|
|
match_type=ape.MatchType.NOT_EQUAL,
|
|
),
|
|
]
|
|
rule = ape.Rule(ape.Verb.DENY, ALL_OBJECT_OPERATIONS, rule_conditions)
|
|
frostfs_cli.ape_manager.add(endpoint, rule.chain_id, target_name=cid, target_type="container", rule=rule.as_string())
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step("Assert others have no access to public container"):
|
|
assert_no_access_to_container(other_wallet, cid, object_oids[0], file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step("Assert owner have full access to public container"):
|
|
assert_full_access_to_container(default_wallet, cid, object_oids.pop(), file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step("Assert allowed wallet have full access to public container"):
|
|
assert_full_access_to_container(other_wallet_2, cid, object_oids.pop(), file_path, self.shell, self.cluster)
|
|
|
|
@allure.title("Replication works with APE deny rules on OWNER and OTHERS (obj_size={object_size})")
|
|
def test_replication_works_with_deny_rules(
|
|
self,
|
|
frostfs_cli: FrostfsCli,
|
|
full_placement_container_with_object: tuple[str, list[str], str],
|
|
):
|
|
endpoint = self.cluster.default_rpc_endpoint
|
|
cid, oid = full_placement_container_with_object
|
|
storage_nodes = self.cluster.storage_nodes
|
|
|
|
with reporter.step("Add deny APE rules for owner and others"):
|
|
rule_conditions = [
|
|
ape.Condition.by_role(ape.Role.OWNER),
|
|
ape.Condition.by_role(ape.Role.OTHERS),
|
|
]
|
|
for rule_condition in rule_conditions:
|
|
rule = ape.Rule(ape.Verb.DENY, ALL_OBJECT_OPERATIONS, rule_condition)
|
|
frostfs_cli.ape_manager.add(endpoint, rule.chain_id, target_name=cid, target_type="container", rule=rule.as_string())
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step("Drop object"):
|
|
drop_object(storage_nodes[0], cid, oid)
|
|
|
|
with reporter.step("Wait for dropped object to be replicated"):
|
|
wait_object_replication(cid, oid, len(storage_nodes), self.shell, storage_nodes)
|
|
|
|
@allure.title("Deny operations via APE by role (role=ir, obj_size={object_size})")
|
|
def test_deny_operations_via_ape_by_role_ir(
|
|
self, frostfs_cli: FrostfsCli, ir_wallet: WalletInfo, container_with_objects: tuple[str, list[str], str]
|
|
):
|
|
cid, object_oids, file_path = container_with_objects
|
|
endpoint = self.cluster.default_rpc_endpoint
|
|
|
|
default_ir_access = {
|
|
ape.ObjectOperations.PUT: False,
|
|
ape.ObjectOperations.GET: True,
|
|
ape.ObjectOperations.HEAD: True,
|
|
ape.ObjectOperations.GET_RANGE: False,
|
|
ape.ObjectOperations.GET_RANGE_HASH: True,
|
|
ape.ObjectOperations.SEARCH: True,
|
|
ape.ObjectOperations.DELETE: False,
|
|
}
|
|
|
|
with reporter.step("Assert IR wallet access in default state"):
|
|
assert_access_to_container(default_ir_access, ir_wallet, cid, object_oids[0], file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step("Add deny APE rule with deny all operations for IR role"):
|
|
rule = ape.Rule(ape.Verb.DENY, ALL_OBJECT_OPERATIONS, [ape.Condition.by_role(ape.Role.IR.value)])
|
|
frostfs_cli.ape_manager.add(endpoint, rule.chain_id, target_name=cid, target_type="container", rule=rule.as_string())
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step("Assert IR wallet ignores APE rules"):
|
|
assert_access_to_container(default_ir_access, ir_wallet, cid, object_oids[0], file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step("Remove APE rule"):
|
|
frostfs_cli.ape_manager.remove(endpoint, rule.chain_id, target_name=cid, target_type="container")
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step("Assert IR wallet access is restored"):
|
|
assert_access_to_container(default_ir_access, ir_wallet, cid, object_oids[0], file_path, self.shell, self.cluster)
|
|
|
|
@allure.title("Deny operations via APE by role (role=container, obj_size={object_size})")
|
|
def test_deny_operations_via_ape_by_role_container(
|
|
self, frostfs_cli: FrostfsCli, storage_wallet: WalletInfo, container_with_objects: tuple[str, list[str], str]
|
|
):
|
|
|
|
cid, object_oids, file_path = container_with_objects
|
|
endpoint = self.cluster.default_rpc_endpoint
|
|
|
|
default_container_access = {
|
|
ape.ObjectOperations.PUT: True,
|
|
ape.ObjectOperations.GET: True,
|
|
ape.ObjectOperations.HEAD: True,
|
|
ape.ObjectOperations.GET_RANGE: False,
|
|
ape.ObjectOperations.GET_RANGE_HASH: True,
|
|
ape.ObjectOperations.SEARCH: True,
|
|
ape.ObjectOperations.DELETE: False,
|
|
}
|
|
|
|
with reporter.step("Assert CONTAINER wallet access in default state"):
|
|
assert_access_to_container(default_container_access, storage_wallet, cid, object_oids[0], file_path, self.shell, self.cluster)
|
|
|
|
rule = ape.Rule(ape.Verb.DENY, ALL_OBJECT_OPERATIONS, ape.Condition.by_role(ape.Role.CONTAINER.value))
|
|
|
|
with reporter.step(f"Add APE rule with deny all operations for CONTAINER and IR roles"):
|
|
frostfs_cli.ape_manager.add(endpoint, rule.chain_id, target_name=cid, target_type="container", rule=rule.as_string())
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step("Assert CONTAINER wallet ignores APE rule"):
|
|
assert_access_to_container(default_container_access, storage_wallet, cid, object_oids[0], file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step("Remove APE rules"):
|
|
frostfs_cli.ape_manager.remove(endpoint, rule.chain_id, target_name=cid, target_type="container")
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step("Assert CONTAINER wallet access is restored"):
|
|
assert_access_to_container(default_container_access, storage_wallet, cid, object_oids[0], file_path, self.shell, self.cluster)
|