2022-08-01 06:16:36 +00:00
|
|
|
import logging
|
|
|
|
from time import sleep
|
|
|
|
|
|
|
|
import allure
|
2023-05-03 08:45:44 +00:00
|
|
|
from frostfs_testlib.hosting import Host
|
|
|
|
from frostfs_testlib.shell import CommandOptions, Shell
|
2023-02-27 16:54:27 +00:00
|
|
|
|
|
|
|
from pytest_tests.helpers.cluster import Cluster, StorageNode
|
|
|
|
from pytest_tests.helpers.node_management import storage_node_healthcheck
|
|
|
|
from pytest_tests.helpers.storage_policy import get_nodes_with_object
|
2023-05-03 08:45:44 +00:00
|
|
|
from pytest_tests.helpers.test_control import retry
|
2022-08-01 06:16:36 +00:00
|
|
|
|
2022-09-28 12:07:16 +00:00
|
|
|
logger = logging.getLogger("NeoLogger")
|
2022-08-01 06:16:36 +00:00
|
|
|
|
|
|
|
|
2022-09-28 12:07:16 +00:00
|
|
|
@allure.step("Wait for object replication")
|
2022-12-05 22:31:45 +00:00
|
|
|
def wait_object_replication(
|
2022-09-28 12:07:16 +00:00
|
|
|
cid: str,
|
|
|
|
oid: str,
|
|
|
|
expected_copies: int,
|
2022-10-13 18:53:44 +00:00
|
|
|
shell: Shell,
|
2022-12-05 22:31:45 +00:00
|
|
|
nodes: list[StorageNode],
|
2023-05-03 08:45:44 +00:00
|
|
|
sleep_interval: int = 15,
|
|
|
|
attempts: int = 20,
|
2022-12-05 22:31:45 +00:00
|
|
|
) -> list[StorageNode]:
|
|
|
|
nodes_with_object = []
|
|
|
|
for _ in range(attempts):
|
|
|
|
nodes_with_object = get_nodes_with_object(cid, oid, shell=shell, nodes=nodes)
|
|
|
|
if len(nodes_with_object) >= expected_copies:
|
|
|
|
return nodes_with_object
|
2022-08-01 06:16:36 +00:00
|
|
|
sleep(sleep_interval)
|
2022-09-28 12:07:16 +00:00
|
|
|
raise AssertionError(
|
2022-12-05 22:31:45 +00:00
|
|
|
f"Expected {expected_copies} copies of object, but found {len(nodes_with_object)}. "
|
2022-09-28 12:07:16 +00:00
|
|
|
f"Waiting time {sleep_interval * attempts}"
|
|
|
|
)
|
2022-08-01 06:16:36 +00:00
|
|
|
|
|
|
|
|
2022-12-05 22:31:45 +00:00
|
|
|
@allure.step("Wait for storage nodes returned to cluster")
|
|
|
|
def wait_all_storage_nodes_returned(cluster: Cluster) -> None:
|
2022-10-13 08:04:42 +00:00
|
|
|
sleep_interval, attempts = 15, 20
|
2022-08-01 06:16:36 +00:00
|
|
|
for __attempt in range(attempts):
|
2022-12-05 22:31:45 +00:00
|
|
|
if is_all_storage_nodes_returned(cluster):
|
2022-08-01 06:16:36 +00:00
|
|
|
return
|
|
|
|
sleep(sleep_interval)
|
2022-09-28 12:07:16 +00:00
|
|
|
raise AssertionError("Storage node(s) is broken")
|
2022-08-01 06:16:36 +00:00
|
|
|
|
|
|
|
|
2022-12-05 22:31:45 +00:00
|
|
|
def is_all_storage_nodes_returned(cluster: Cluster) -> bool:
|
2022-09-28 12:07:16 +00:00
|
|
|
with allure.step("Run health check for all storage nodes"):
|
2022-12-05 22:31:45 +00:00
|
|
|
for node in cluster.storage_nodes:
|
2022-08-01 06:16:36 +00:00
|
|
|
try:
|
2022-12-05 22:31:45 +00:00
|
|
|
health_check = storage_node_healthcheck(node)
|
2022-08-01 06:16:36 +00:00
|
|
|
except Exception as err:
|
2022-09-28 12:07:16 +00:00
|
|
|
logger.warning(f"Node healthcheck fails with error {err}")
|
2022-08-01 06:16:36 +00:00
|
|
|
return False
|
2022-09-28 12:07:16 +00:00
|
|
|
if health_check.health_status != "READY" or health_check.network_status != "ONLINE":
|
2022-08-01 06:16:36 +00:00
|
|
|
return False
|
|
|
|
return True
|
2023-05-03 08:45:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
@allure.step("Ping node")
|
|
|
|
def ping_host(shell: Shell, host: Host):
|
|
|
|
options = CommandOptions(check=False)
|
|
|
|
return shell.exec(f"ping {host.config.address} -c 1", options).return_code
|
|
|
|
|
|
|
|
|
|
|
|
@retry(max_attempts=60, sleep_interval=5, expected_result=1)
|
|
|
|
@allure.step("Waiting for host of {node} to go offline")
|
|
|
|
def wait_for_host_offline(shell: Shell, node: StorageNode):
|
|
|
|
try:
|
|
|
|
# TODO: Quick solution for now, should be replaced by lib interactions
|
|
|
|
return ping_host(shell, node.host)
|
|
|
|
except Exception as err:
|
|
|
|
logger.warning(f"Host ping fails with error {err}")
|
|
|
|
return 0
|