diff --git a/src/frostfs_testlib/cli/netmap_parser.py b/src/frostfs_testlib/cli/netmap_parser.py index 6d2eaaa..94d12b8 100644 --- a/src/frostfs_testlib/cli/netmap_parser.py +++ b/src/frostfs_testlib/cli/netmap_parser.py @@ -1,7 +1,7 @@ import re from frostfs_testlib.storage.cluster import ClusterNode -from frostfs_testlib.storage.dataclasses.storage_object_info import NodeNetInfo, NodeNetmapInfo +from frostfs_testlib.storage.dataclasses.storage_object_info import NodeNetInfo, NodeNetmapInfo, NodeStatus class NetmapParser: @@ -44,7 +44,7 @@ class NetmapParser: regexes = { "node_id": r"\d+: (?P\w+)", "node_data_ips": r"(?P/ip4/.+?)$", - "node_status": r"(?PONLINE|OFFLINE)", + "node_status": r"(?PONLINE|MAINTENANCE|OFFLINE)", "cluster_name": r"ClusterName: (?P\w+)", "continent": r"Continent: (?P\w+)", "country": r"Country: (?P\w+)", @@ -62,14 +62,17 @@ class NetmapParser: for node in netmap_nodes: for key, regex in regexes.items(): search_result = re.search(regex, node, flags=re.MULTILINE) + if search_result == None: + result_netmap[key] = None + continue if key == "node_data_ips": result_netmap[key] = search_result[key].strip().split(" ") continue if key == "external_address": result_netmap[key] = search_result[key].strip().split(",") continue - if search_result == None: - result_netmap[key] = None + if key == "node_status": + result_netmap[key] = NodeStatus(search_result[key].strip().lower()) continue result_netmap[key] = search_result[key].strip() diff --git a/src/frostfs_testlib/storage/controllers/cluster_state_controller.py b/src/frostfs_testlib/storage/controllers/cluster_state_controller.py index 9e07914..03648f5 100644 --- a/src/frostfs_testlib/storage/controllers/cluster_state_controller.py +++ b/src/frostfs_testlib/storage/controllers/cluster_state_controller.py @@ -17,6 +17,7 @@ from frostfs_testlib.steps.network import IpHelper from frostfs_testlib.storage.cluster import Cluster, ClusterNode, S3Gate, StorageNode from frostfs_testlib.storage.controllers.disk_controller import DiskController from frostfs_testlib.storage.dataclasses.node_base import NodeBase, ServiceClass +from frostfs_testlib.storage.dataclasses.storage_object_info import NodeStatus from frostfs_testlib.storage.dataclasses.wallet import WalletInfo from frostfs_testlib.testing import parallel from frostfs_testlib.testing.test_control import retry, run_optionally, wait_for_success @@ -413,41 +414,39 @@ class ClusterStateController: ) frostfs_adm.morph.set_config(set_key_value=f"MaintenanceModeAllowed={status}") - @reporter.step("Set mode node to {status}") - def set_mode_node(self, cluster_node: ClusterNode, wallet: WalletInfo, status: str, await_tick: bool = True) -> None: + @reporter.step("Set node status to {status} in CSC") + def set_node_status(self, cluster_node: ClusterNode, wallet: WalletInfo, status: NodeStatus, await_tick: bool = True) -> None: rpc_endpoint = cluster_node.storage_node.get_rpc_endpoint() control_endpoint = cluster_node.service(StorageNode).get_control_endpoint() - frostfs_adm, frostfs_cli, frostfs_cli_remote = self._get_cli(local_shell=self.shell, local_wallet=wallet, cluster_node=cluster_node) - node_netinfo = NetmapParser.netinfo(frostfs_cli.netmap.netinfo(rpc_endpoint=rpc_endpoint).stdout) + frostfs_adm, frostfs_cli, frostfs_cli_remote = self._get_cli(self.shell, wallet, cluster_node) + node_netinfo = NetmapParser.netinfo(frostfs_cli.netmap.netinfo(rpc_endpoint).stdout) - with reporter.step("If status maintenance, then check that the option is enabled"): - if node_netinfo.maintenance_mode_allowed == "false": - frostfs_adm.morph.set_config(set_key_value="MaintenanceModeAllowed=true") + if node_netinfo.maintenance_mode_allowed == "false": + with reporter.step("Enable maintenance mode"): + frostfs_adm.morph.set_config("MaintenanceModeAllowed=true") - with reporter.step(f"Change the status to {status}"): - frostfs_cli_remote.control.set_status(endpoint=control_endpoint, status=status) + with reporter.step(f"Set node status to {status} using FrostfsCli"): + frostfs_cli_remote.control.set_status(control_endpoint, status.value) if not await_tick: return - with reporter.step("Tick 1 epoch, and await 2 block"): + with reporter.step("Tick 1 epoch and await 2 block"): frostfs_adm.morph.force_new_epoch() time.sleep(parse_time(MORPH_BLOCK_TIME) * 2) - self.check_node_status(status=status, wallet=wallet, cluster_node=cluster_node) + self.await_node_status(status, wallet, cluster_node) - @wait_for_success(80, 8, title="Wait for storage status become {status}") - def check_node_status(self, status: str, wallet: WalletInfo, cluster_node: ClusterNode): + @wait_for_success(80, 8, title="Wait for node status become {status}") + def await_node_status(self, status: NodeStatus, wallet: WalletInfo, cluster_node: ClusterNode): frostfs_cli = FrostfsCli(self.shell, FROSTFS_CLI_EXEC, wallet.config_path) - netmap = NetmapParser.snapshot_all_nodes( - frostfs_cli.netmap.snapshot(rpc_endpoint=cluster_node.storage_node.get_rpc_endpoint()).stdout - ) + netmap = NetmapParser.snapshot_all_nodes(frostfs_cli.netmap.snapshot(cluster_node.storage_node.get_rpc_endpoint()).stdout) netmap = [node for node in netmap if cluster_node.host_ip == node.node] - if status == "offline": + if status == NodeStatus.OFFLINE: assert cluster_node.host_ip not in netmap, f"{cluster_node.host_ip} not in Offline" else: - assert netmap[0].node_status == status.upper(), f"Node state - {netmap[0].node_status} != {status} expect" + assert netmap[0].node_status == status, f"Node status should be '{status}', but was '{netmap[0].node_status}'" def _get_cli( self, local_shell: Shell, local_wallet: WalletInfo, cluster_node: ClusterNode diff --git a/src/frostfs_testlib/storage/dataclasses/storage_object_info.py b/src/frostfs_testlib/storage/dataclasses/storage_object_info.py index f4d729d..28fdaa5 100644 --- a/src/frostfs_testlib/storage/dataclasses/storage_object_info.py +++ b/src/frostfs_testlib/storage/dataclasses/storage_object_info.py @@ -28,7 +28,7 @@ class StorageObjectInfo(ObjectRef): locks: Optional[list[LockObjectInfo]] = None -class ModeNode(HumanReadableEnum): +class NodeStatus(HumanReadableEnum): MAINTENANCE: str = "maintenance" ONLINE: str = "online" OFFLINE: str = "offline" @@ -37,7 +37,7 @@ class ModeNode(HumanReadableEnum): @dataclass class NodeNetmapInfo: node_id: str = None - node_status: ModeNode = None + node_status: NodeStatus = None node_data_ips: list[str] = None cluster_name: str = None continent: str = None