diff --git a/src/frostfs_testlib/hosting/docker_host.py b/src/frostfs_testlib/hosting/docker_host.py index d5824186..0e4ea11c 100644 --- a/src/frostfs_testlib/hosting/docker_host.py +++ b/src/frostfs_testlib/hosting/docker_host.py @@ -126,6 +126,14 @@ class DockerHost(Host): timeout=service_attributes.stop_timeout, ) + def mask_service(self, service_name: str) -> None: + # Not required for Docker + return + + def unmask_service(self, service_name: str) -> None: + # Not required for Docker + return + def wait_success_suspend_process(self, service_name: str): raise NotImplementedError("Not supported for docker") diff --git a/src/frostfs_testlib/hosting/interfaces.py b/src/frostfs_testlib/hosting/interfaces.py index 43887917..84b79117 100644 --- a/src/frostfs_testlib/hosting/interfaces.py +++ b/src/frostfs_testlib/hosting/interfaces.py @@ -118,6 +118,26 @@ class Host(ABC): service_name: Name of the service to stop. """ + @abstractmethod + def mask_service(self, service_name: str) -> None: + """Prevent the service from start by any activity by masking it. + + The service must be hosted on this host. + + Args: + service_name: Name of the service to mask. + """ + + @abstractmethod + def unmask_service(self, service_name: str) -> None: + """Allow the service to start by any activity by unmasking it. + + The service must be hosted on this host. + + Args: + service_name: Name of the service to unmask. + """ + @abstractmethod def restart_service(self, service_name: str) -> None: """Restarts the service with specified name and waits until it starts. diff --git a/src/frostfs_testlib/steps/node_management.py b/src/frostfs_testlib/steps/node_management.py index 4b46b629..9c0c6b0b 100644 --- a/src/frostfs_testlib/steps/node_management.py +++ b/src/frostfs_testlib/steps/node_management.py @@ -15,8 +15,7 @@ from frostfs_testlib.resources.cli import ( ) from frostfs_testlib.resources.common import MORPH_BLOCK_TIME from frostfs_testlib.shell import Shell -from frostfs_testlib.steps.epoch import tick_epoch -from frostfs_testlib.steps.epoch import wait_for_epochs_align +from frostfs_testlib.steps.epoch import tick_epoch, wait_for_epochs_align from frostfs_testlib.storage.cluster import Cluster, StorageNode from frostfs_testlib.storage.dataclasses.frostfs_services import S3Gate from frostfs_testlib.utils import datetime_utils @@ -41,44 +40,6 @@ class HealthStatus: return HealthStatus(network, health) -@reporter.step_deco("Stop random storage nodes") -def stop_random_storage_nodes(number: int, nodes: list[StorageNode]) -> list[StorageNode]: - """ - Shuts down the given number of randomly selected storage nodes. - Args: - number: the number of storage nodes to stop - nodes: the list of storage nodes to stop - Returns: - the list of nodes that were stopped - """ - nodes_to_stop = random.sample(nodes, number) - for node in nodes_to_stop: - node.stop_service() - return nodes_to_stop - - -@reporter.step_deco("Start storage node") -def start_storage_nodes(nodes: list[StorageNode]) -> None: - """ - The function starts specified storage nodes. - Args: - nodes: the list of nodes to start - """ - for node in nodes: - node.start_service() - - -@reporter.step_deco("Stop storage node") -def stop_storage_nodes(nodes: list[StorageNode]) -> None: - """ - The function starts specified storage nodes. - Args: - nodes: the list of nodes to start - """ - for node in nodes: - node.stop_service() - - @reporter.step_deco("Get Locode from random storage node") def get_locode_from_random_node(cluster: Cluster) -> str: node = random.choice(cluster.services(StorageNode)) @@ -329,25 +290,3 @@ def _run_control_command(node: StorageNode, command: str) -> None: f"--wallet {wallet_path} --config {wallet_config_path}" ) return result.stdout - - -@reporter.step_deco("Start services s3gate ") -def start_s3gates(cluster: Cluster) -> None: - """ - The function starts specified storage nodes. - Args: - cluster: cluster instance under test - """ - for gate in cluster.services(S3Gate): - gate.start_service() - - -@reporter.step_deco("Stop services s3gate ") -def stop_s3gates(cluster: Cluster) -> None: - """ - The function starts specified storage nodes. - Args: - cluster: cluster instance under test - """ - for gate in cluster.services(S3Gate): - gate.stop_service() diff --git a/src/frostfs_testlib/storage/controllers/cluster_state_controller.py b/src/frostfs_testlib/storage/controllers/cluster_state_controller.py index 7304f5d9..c18b8d84 100644 --- a/src/frostfs_testlib/storage/controllers/cluster_state_controller.py +++ b/src/frostfs_testlib/storage/controllers/cluster_state_controller.py @@ -135,9 +135,9 @@ class ClusterStateController: @run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED) @reporter.step_deco("Stop storage service on {node}") - def stop_storage_service(self, node: ClusterNode): + def stop_storage_service(self, node: ClusterNode, mask: bool = True): self.stopped_storage_nodes.append(node) - node.storage_node.stop_service() + node.storage_node.stop_service(mask) @run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED) @reporter.step_deco("Stop all {service_type} services") @@ -171,9 +171,11 @@ class ClusterStateController: @run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED) @reporter.step_deco("Stop {service_type} service on {node}") - def stop_service_of_type(self, node: ClusterNode, service_type: type[ServiceClass]): + def stop_service_of_type( + self, node: ClusterNode, service_type: type[ServiceClass], mask: bool = True + ): service = node.service(service_type) - service.stop_service() + service.stop_service(mask) self.stopped_services.add(service) @run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED) @@ -207,8 +209,8 @@ class ClusterStateController: @run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED) @reporter.step_deco("Stop s3 gate on {node}") - def stop_s3_gate(self, node: ClusterNode): - node.s3_gate.stop_service() + def stop_s3_gate(self, node: ClusterNode, mask: bool = True): + node.s3_gate.stop_service(mask) self.stopped_s3_gates.append(node) @run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED) diff --git a/src/frostfs_testlib/storage/dataclasses/node_base.py b/src/frostfs_testlib/storage/dataclasses/node_base.py index ecfe61c0..87085205 100644 --- a/src/frostfs_testlib/storage/dataclasses/node_base.py +++ b/src/frostfs_testlib/storage/dataclasses/node_base.py @@ -57,6 +57,9 @@ class NodeBase(HumanReadableABC): return self._process_name def start_service(self): + with reporter.step(f"Unmask {self.name} service on {self.host.config.address}"): + self.host.unmask_service(self.name) + with reporter.step(f"Start {self.name} service on {self.host.config.address}"): self.host.start_service(self.name) @@ -67,7 +70,11 @@ class NodeBase(HumanReadableABC): def get_metrics_endpoint(self) -> str: return self._get_attribute(ConfigAttributes.ENDPOINT_PROMETHEUS) - def stop_service(self): + def stop_service(self, mask: bool = True): + if mask: + with reporter.step(f"Mask {self.name} service on {self.host.config.address}"): + self.host.mask_service(self.name) + with reporter.step(f"Stop {self.name} service on {self.host.config.address}"): self.host.stop_service(self.name)