Add mask/unmask for services #104
5 changed files with 45 additions and 69 deletions
|
@ -126,6 +126,14 @@ class DockerHost(Host):
|
||||||
timeout=service_attributes.stop_timeout,
|
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):
|
def wait_success_suspend_process(self, service_name: str):
|
||||||
raise NotImplementedError("Not supported for docker")
|
raise NotImplementedError("Not supported for docker")
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,26 @@ class Host(ABC):
|
||||||
service_name: Name of the service to stop.
|
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
|
@abstractmethod
|
||||||
def restart_service(self, service_name: str) -> None:
|
def restart_service(self, service_name: str) -> None:
|
||||||
"""Restarts the service with specified name and waits until it starts.
|
"""Restarts the service with specified name and waits until it starts.
|
||||||
|
|
|
@ -15,8 +15,7 @@ from frostfs_testlib.resources.cli import (
|
||||||
)
|
)
|
||||||
from frostfs_testlib.resources.common import MORPH_BLOCK_TIME
|
from frostfs_testlib.resources.common import MORPH_BLOCK_TIME
|
||||||
from frostfs_testlib.shell import Shell
|
from frostfs_testlib.shell import Shell
|
||||||
from frostfs_testlib.steps.epoch import tick_epoch
|
from frostfs_testlib.steps.epoch import tick_epoch, wait_for_epochs_align
|
||||||
from frostfs_testlib.steps.epoch import wait_for_epochs_align
|
|
||||||
from frostfs_testlib.storage.cluster import Cluster, StorageNode
|
from frostfs_testlib.storage.cluster import Cluster, StorageNode
|
||||||
from frostfs_testlib.storage.dataclasses.frostfs_services import S3Gate
|
from frostfs_testlib.storage.dataclasses.frostfs_services import S3Gate
|
||||||
from frostfs_testlib.utils import datetime_utils
|
from frostfs_testlib.utils import datetime_utils
|
||||||
|
@ -41,44 +40,6 @@ class HealthStatus:
|
||||||
return HealthStatus(network, health)
|
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")
|
@reporter.step_deco("Get Locode from random storage node")
|
||||||
def get_locode_from_random_node(cluster: Cluster) -> str:
|
def get_locode_from_random_node(cluster: Cluster) -> str:
|
||||||
node = random.choice(cluster.services(StorageNode))
|
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}"
|
f"--wallet {wallet_path} --config {wallet_config_path}"
|
||||||
)
|
)
|
||||||
return result.stdout
|
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()
|
|
||||||
|
|
|
@ -135,9 +135,9 @@ class ClusterStateController:
|
||||||
|
|
||||||
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
||||||
@reporter.step_deco("Stop storage service on {node}")
|
@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)
|
self.stopped_storage_nodes.append(node)
|
||||||
node.storage_node.stop_service()
|
node.storage_node.stop_service(mask)
|
||||||
|
|
||||||
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
||||||
@reporter.step_deco("Stop all {service_type} services")
|
@reporter.step_deco("Stop all {service_type} services")
|
||||||
|
@ -171,9 +171,11 @@ class ClusterStateController:
|
||||||
|
|
||||||
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
||||||
@reporter.step_deco("Stop {service_type} service on {node}")
|
@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 = node.service(service_type)
|
||||||
service.stop_service()
|
service.stop_service(mask)
|
||||||
self.stopped_services.add(service)
|
self.stopped_services.add(service)
|
||||||
|
|
||||||
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
||||||
|
@ -207,8 +209,8 @@ class ClusterStateController:
|
||||||
|
|
||||||
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
||||||
@reporter.step_deco("Stop s3 gate on {node}")
|
@reporter.step_deco("Stop s3 gate on {node}")
|
||||||
def stop_s3_gate(self, node: ClusterNode):
|
def stop_s3_gate(self, node: ClusterNode, mask: bool = True):
|
||||||
node.s3_gate.stop_service()
|
node.s3_gate.stop_service(mask)
|
||||||
self.stopped_s3_gates.append(node)
|
self.stopped_s3_gates.append(node)
|
||||||
|
|
||||||
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
@run_optionally(optionals.OPTIONAL_FAILOVER_ENABLED)
|
||||||
|
|
|
@ -57,6 +57,9 @@ class NodeBase(HumanReadableABC):
|
||||||
return self._process_name
|
return self._process_name
|
||||||
|
|
||||||
def start_service(self):
|
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}"):
|
with reporter.step(f"Start {self.name} service on {self.host.config.address}"):
|
||||||
self.host.start_service(self.name)
|
self.host.start_service(self.name)
|
||||||
|
|
||||||
|
@ -67,7 +70,11 @@ class NodeBase(HumanReadableABC):
|
||||||
def get_metrics_endpoint(self) -> str:
|
def get_metrics_endpoint(self) -> str:
|
||||||
return self._get_attribute(ConfigAttributes.ENDPOINT_PROMETHEUS)
|
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}"):
|
with reporter.step(f"Stop {self.name} service on {self.host.config.address}"):
|
||||||
self.host.stop_service(self.name)
|
self.host.stop_service(self.name)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue