2021-11-16 08:38:49 +00:00
|
|
|
import pytest
|
2021-11-29 12:35:28 +00:00
|
|
|
|
|
|
|
import functools
|
2021-11-16 08:38:49 +00:00
|
|
|
import time
|
|
|
|
|
|
|
|
from helpers.cluster import ClickHouseCluster
|
|
|
|
|
|
|
|
cluster = ClickHouseCluster(__file__)
|
|
|
|
|
2022-08-09 17:53:32 +00:00
|
|
|
shard_configs = {
|
2022-08-12 11:05:13 +00:00
|
|
|
"node0": "config/config.xml",
|
|
|
|
"node1": "config/config_shard1.xml",
|
|
|
|
"node2": "config/config.xml",
|
|
|
|
"node3": "config/config_shard3.xml",
|
|
|
|
"node4": "config/config.xml",
|
2022-08-11 15:42:32 +00:00
|
|
|
"node_observer": "config/config_observer.xml",
|
2022-08-09 17:53:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nodes = {
|
2022-08-11 15:42:32 +00:00
|
|
|
node_name: cluster.add_instance(
|
|
|
|
node_name,
|
2022-08-09 17:53:32 +00:00
|
|
|
main_configs=[shard_config],
|
2021-11-16 08:38:49 +00:00
|
|
|
stay_alive=True,
|
2022-03-22 16:39:58 +00:00
|
|
|
with_zookeeper=True,
|
|
|
|
)
|
2022-08-11 15:42:32 +00:00
|
|
|
for node_name, shard_config in shard_configs.items()
|
2022-08-09 17:53:32 +00:00
|
|
|
}
|
2021-11-16 08:38:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
|
|
def start_cluster():
|
|
|
|
try:
|
|
|
|
cluster.start()
|
|
|
|
yield cluster
|
|
|
|
finally:
|
|
|
|
cluster.shutdown()
|
|
|
|
|
|
|
|
|
2022-03-22 16:39:58 +00:00
|
|
|
def check_on_cluster(
|
|
|
|
nodes, expected, *, what, cluster_name="test_auto_cluster", msg=None, retries=5
|
|
|
|
):
|
2021-11-16 08:38:49 +00:00
|
|
|
"""
|
2021-11-29 12:35:28 +00:00
|
|
|
Select data from `system.clusters` on specified nodes and check the result
|
2021-11-16 08:38:49 +00:00
|
|
|
"""
|
2021-11-18 09:45:57 +00:00
|
|
|
assert 1 <= retries <= 6
|
2021-11-16 09:03:15 +00:00
|
|
|
|
2022-08-11 15:42:32 +00:00
|
|
|
node_results = {}
|
2021-11-16 08:38:49 +00:00
|
|
|
for retry in range(1, retries + 1):
|
2022-08-11 15:42:32 +00:00
|
|
|
for node in nodes:
|
|
|
|
if node_results.get(node.name) == expected:
|
|
|
|
# do not retry node after success
|
|
|
|
continue
|
|
|
|
query_text = (
|
|
|
|
f"SELECT {what} FROM system.clusters WHERE cluster = '{cluster_name}'"
|
2022-03-22 16:39:58 +00:00
|
|
|
)
|
2022-08-11 15:42:32 +00:00
|
|
|
node_results[node.name] = int(node.query(query_text))
|
|
|
|
|
|
|
|
if all(actual == expected for actual in node_results.values()):
|
2021-11-16 08:38:49 +00:00
|
|
|
break
|
|
|
|
|
2022-08-11 15:42:32 +00:00
|
|
|
print(f"Retry {retry}/{retries} unsuccessful, result: {node_results}")
|
|
|
|
|
2021-11-16 08:38:49 +00:00
|
|
|
if retry != retries:
|
2022-03-22 16:39:58 +00:00
|
|
|
time.sleep(2**retry)
|
2021-11-16 08:38:49 +00:00
|
|
|
else:
|
2021-11-29 12:35:28 +00:00
|
|
|
msg = msg or f"Wrong '{what}' result"
|
2022-03-22 16:39:58 +00:00
|
|
|
raise Exception(
|
2022-08-11 15:42:32 +00:00
|
|
|
f"{msg}: {node_results}, expected: {expected} (after {retries} retries)"
|
2022-03-22 16:39:58 +00:00
|
|
|
)
|
2021-11-16 08:38:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_cluster_discovery_startup_and_stop(start_cluster):
|
|
|
|
"""
|
|
|
|
Start cluster, check nodes count in system.clusters,
|
|
|
|
then stop/start some nodes and check that it (dis)appeared in cluster.
|
|
|
|
"""
|
|
|
|
|
2022-03-22 16:39:58 +00:00
|
|
|
check_nodes_count = functools.partial(
|
|
|
|
check_on_cluster, what="count()", msg="Wrong nodes count in cluster"
|
|
|
|
)
|
|
|
|
check_shard_num = functools.partial(
|
|
|
|
check_on_cluster,
|
|
|
|
what="count(DISTINCT shard_num)",
|
|
|
|
msg="Wrong shard_num count in cluster",
|
|
|
|
)
|
2021-11-29 12:35:28 +00:00
|
|
|
|
2022-08-11 15:42:32 +00:00
|
|
|
# `- 1` because one node is an observer
|
|
|
|
total_shards = len(set(shard_configs.values())) - 1
|
2022-08-09 17:53:32 +00:00
|
|
|
total_nodes = len(nodes) - 1
|
2021-11-16 08:38:49 +00:00
|
|
|
|
2022-08-11 15:42:32 +00:00
|
|
|
check_nodes_count(
|
2022-08-12 11:05:13 +00:00
|
|
|
[nodes["node0"], nodes["node2"], nodes["node_observer"]], total_nodes
|
2022-08-11 15:42:32 +00:00
|
|
|
)
|
|
|
|
check_shard_num(
|
2022-08-12 11:05:13 +00:00
|
|
|
[nodes["node0"], nodes["node2"], nodes["node_observer"]], total_shards
|
2022-08-11 15:42:32 +00:00
|
|
|
)
|
|
|
|
|
2022-08-12 11:05:13 +00:00
|
|
|
nodes["node1"].stop_clickhouse(kill=True)
|
2022-08-11 15:42:32 +00:00
|
|
|
check_nodes_count(
|
2022-08-12 11:05:13 +00:00
|
|
|
[nodes["node0"], nodes["node2"], nodes["node_observer"]], total_nodes - 1
|
2022-08-11 15:42:32 +00:00
|
|
|
)
|
2022-08-09 17:53:32 +00:00
|
|
|
|
2022-08-12 11:05:13 +00:00
|
|
|
# node1 was the only node in shard '1'
|
2022-08-11 15:42:32 +00:00
|
|
|
check_shard_num(
|
2022-08-12 11:05:13 +00:00
|
|
|
[nodes["node0"], nodes["node2"], nodes["node_observer"]], total_shards - 1
|
2022-08-11 15:42:32 +00:00
|
|
|
)
|
2021-11-16 08:38:49 +00:00
|
|
|
|
2022-08-12 11:05:13 +00:00
|
|
|
nodes["node3"].stop_clickhouse()
|
2022-08-11 15:42:32 +00:00
|
|
|
check_nodes_count(
|
2022-08-12 11:05:13 +00:00
|
|
|
[nodes["node0"], nodes["node2"], nodes["node_observer"]], total_nodes - 2
|
2022-08-11 15:42:32 +00:00
|
|
|
)
|
2021-11-16 08:38:49 +00:00
|
|
|
|
2022-08-12 11:05:13 +00:00
|
|
|
nodes["node1"].start_clickhouse()
|
2022-08-11 15:42:32 +00:00
|
|
|
check_nodes_count(
|
2022-08-12 11:05:13 +00:00
|
|
|
[nodes["node0"], nodes["node2"], nodes["node_observer"]], total_nodes - 1
|
2022-08-11 15:42:32 +00:00
|
|
|
)
|
2021-11-16 08:38:49 +00:00
|
|
|
|
2022-08-12 11:05:13 +00:00
|
|
|
nodes["node3"].start_clickhouse()
|
2022-08-11 15:42:32 +00:00
|
|
|
check_nodes_count(
|
2022-08-12 11:05:13 +00:00
|
|
|
[nodes["node0"], nodes["node2"], nodes["node_observer"]], total_nodes
|
2022-08-11 15:42:32 +00:00
|
|
|
)
|
2021-11-18 09:45:57 +00:00
|
|
|
|
2022-08-09 17:53:32 +00:00
|
|
|
# regular cluster is not affected
|
2022-08-11 15:42:32 +00:00
|
|
|
check_nodes_count(
|
2022-08-12 11:05:13 +00:00
|
|
|
[nodes["node1"], nodes["node2"]], 2, cluster_name="two_shards", retries=1
|
2022-08-11 15:42:32 +00:00
|
|
|
)
|