def test_zookeeper_rescale(self): """ test scenario for ZK CH 1 -> 2 wait complete + ZK 1 -> 3 nowait CH 2 -> 1 wait complete + ZK 3 -> 1 nowait CH 1 -> 2 wait complete + ZK 1 -> 3 nowait """ def insert_replicated_data(chi, create_tables, insert_tables): with When(f'create if not exists replicated tables {create_tables}'): for table in create_tables: clickhouse.create_table_on_cluster( chi, 'all-sharded', f'default.{table}', f'(id UInt64) ENGINE=ReplicatedMergeTree(\'/clickhouse/tables/default.{table}/{{shard}}\',\'{{replica}}\') ORDER BY (id)', if_not_exists=True, ) with When(f'insert tables data {insert_tables}'): for table in insert_tables: clickhouse.query( chi['metadata']['name'], f'INSERT INTO default.{table} SELECT rand()+number FROM numbers(1000)', pod="chi-test-cluster-for-zk-default-0-1-0") def check_zk_root_znode(chi, pod_count, zk_retry=5): for pod_num in range(pod_count): out = "" for i in range(zk_retry): out = kubectl.launch( f"exec zookeeper-{pod_num} -- bash -ce './bin/zkCli.sh ls /'", ns=settings.test_namespace, ok_to_fail=True) if "[clickhouse, zookeeper]" in out: break else: with Then( f"Zookeeper ROOT NODE not ready, wait { (i+1)*3} sec" ): time.sleep((i + 1) * 3) assert "[clickhouse, zookeeper]" in out, "Unexpected `zkCli.sh ls /` output" out = clickhouse.query( chi["metadata"]["name"], "SELECT count() FROM system.zookeeper WHERE path='/'") assert "2" == out.strip( " \t\r\n" ), f"Unexpected `SELECT count() FROM system.zookeeper WHERE path='/'` output {out}" def rescale_zk_and_clickhouse(ch_node_count, zk_node_count, first_install=False): zk_manifest = 'zookeeper-1-node-1GB-for-tests-only.yaml' if zk_node_count == 1 else 'zookeeper-3-nodes-1GB-for-tests-only.yaml' _, chi = util.install_clickhouse_and_zookeeper( chi_file= f'manifests/chi/test-cluster-for-zookeeper-{ch_node_count}.yaml', chi_template_file='manifests/chit/tpl-clickhouse-latest.yaml', chi_name='test-cluster-for-zk', zk_manifest=zk_manifest, clean_ns=first_install, force_zk_install=True, zk_install_first=first_install, make_object_count=False, ) return chi with When("Clean exists ClickHouse and Zookeeper"): kubectl.delete_all_zookeeper(settings.test_namespace) kubectl.delete_all_chi(settings.test_namespace) with When("Install CH 1 node ZK 1 node"): chi = rescale_zk_and_clickhouse(ch_node_count=1, zk_node_count=1, first_install=True) util.wait_clickhouse_cluster_ready(chi) wait_zookeeper_ready(pod_count=1) check_zk_root_znode(chi, pod_count=1) util.wait_clickhouse_cluster_ready(chi) wait_clickhouse_no_readonly_replicas(chi) insert_replicated_data(chi, create_tables=['test_repl1'], insert_tables=['test_repl1']) total_iterations = 5 for iteration in range(total_iterations): with When(f"ITERATION {iteration}"): with Then("CH 1 -> 2 wait complete + ZK 1 -> 3 nowait"): chi = rescale_zk_and_clickhouse(ch_node_count=2, zk_node_count=3) wait_zookeeper_ready(pod_count=3) check_zk_root_znode(chi, pod_count=3) util.wait_clickhouse_cluster_ready(chi) insert_replicated_data( chi, create_tables=['test_repl2'], insert_tables=['test_repl1', 'test_repl2']) with Then("CH 2 -> 1 wait complete + ZK 3 -> 1 nowait"): chi = rescale_zk_and_clickhouse(ch_node_count=1, zk_node_count=1) wait_zookeeper_ready(pod_count=1) check_zk_root_znode(chi, pod_count=1) util.wait_clickhouse_cluster_ready(chi) insert_replicated_data( chi, create_tables=['test_repl3'], insert_tables=['test_repl1', 'test_repl2', 'test_repl3']) with When("CH 1 -> 2 wait complete + ZK 1 -> 3 nowait"): chi = rescale_zk_and_clickhouse(ch_node_count=2, zk_node_count=3) check_zk_root_znode(chi, pod_count=3) with Then('check data in tables'): for table, exptected_rows in { "test_repl1": str(1000 + 2000 * total_iterations), "test_repl2": str(2000 * total_iterations), "test_repl3": str(1000 * total_iterations) }.items(): actual_rows = clickhouse.query( chi['metadata']['name'], f'SELECT count() FROM default.{table}', pod="chi-test-cluster-for-zk-default-0-1-0") assert actual_rows == exptected_rows, f"Invalid rows counter after inserts {table} expected={exptected_rows} actual={actual_rows}" with Then('drop all created tables'): for i in range(3): clickhouse.drop_table_on_cluster(chi, 'all-sharded', f'default.test_repl{i+1}')
def clean_namespace(delete_chi=False): with Given(f"Clean namespace {settings.test_namespace}"): if delete_chi: kubectl.delete_all_chi(settings.test_namespace) kubectl.delete_ns(settings.test_namespace, ok_to_fail=True) kubectl.create_ns(settings.test_namespace)
def test_keeper_outline( self, keeper_type="zookeeper", pod_for_insert_data="chi-test-cluster-for-zk-default-0-1-0", keeper_manifest_1_node='zookeeper-1-node-1GB-for-tests-only.yaml', keeper_manifest_3_node='zookeeper-3-nodes-1GB-for-tests-only.yaml', ): """ test scenario for Zoo/Clickhouse Keeper CH 1 -> 2 wait complete + Keeper 1 -> 3 nowait CH 2 -> 1 wait complete + Keeper 3 -> 1 nowait CH 1 -> 2 wait complete + Keeper 1 -> 3 nowait """ def insert_replicated_data(chi, create_tables, insert_tables): with When(f'create if not exists replicated tables {create_tables}'): for table in create_tables: clickhouse.create_table_on_cluster( chi, 'all-sharded', f'default.{table}', f'(id UInt64) ENGINE=ReplicatedMergeTree(\'/clickhouse/tables/default.{table}/{{shard}}\',\'{{replica}}\') ORDER BY (id)', if_not_exists=True, ) with When(f'insert tables data {insert_tables}'): for table in insert_tables: clickhouse.query( chi['metadata']['name'], f'INSERT INTO default.{table} SELECT rand()+number FROM numbers(1000)', pod=pod_for_insert_data) def check_zk_root_znode(chi, pod_count, retry_count=5): for pod_num in range(pod_count): out = "" expected_out = "" for i in range(retry_count): if keeper_type == "zookeeper-operator": expected_out = "[clickhouse, zookeeper, zookeeper-operator]" keeper_cmd = './bin/zkCli.sh ls /' pod_prefix = "zookeeper" elif keeper_type == "zookeeper": expected_out = "[clickhouse, zookeeper]" keeper_cmd = './bin/zkCli.sh ls /' pod_prefix = "zookeeper" else: expected_out = "clickhouse" keeper_cmd = "if [[ ! $(command -v zookeepercli) ]]; then " keeper_cmd += "wget -q -O /tmp/zookeepercli.deb https://github.com/outbrain/zookeepercli/releases/download/v1.0.12/zookeepercli_1.0.12_amd64.deb; " keeper_cmd += "dpkg -i /tmp/zookeepercli.deb; " keeper_cmd += "fi; " keeper_cmd += "zookeepercli -servers 127.0.0.1:2181 -c ls /" pod_prefix = "clickhouse-keeper" out = kubectl.launch( f"exec {pod_prefix}-{pod_num} -- bash -ce '{keeper_cmd}'", ns=settings.test_namespace, ok_to_fail=True) if expected_out in out: break else: with Then( f"{keeper_type} ROOT NODE not ready, wait {(i + 1) * 3} sec" ): time.sleep((i + 1) * 3) assert expected_out in out, f"Unexpected {keeper_type} `ls /` output" out = clickhouse.query( chi["metadata"]["name"], "SELECT count() FROM system.zookeeper WHERE path='/'") expected_out = { "zookeeper": "2", "zookeeper-operator": "3", "clickhouse-keeper": "1", } assert expected_out[keeper_type] == out.strip( " \t\r\n" ), f"Unexpected `SELECT count() FROM system.zookeeper WHERE path='/'` output {out}" def rescale_zk_and_clickhouse(ch_node_count, keeper_node_count, first_install=False): keeper_manifest = keeper_manifest_1_node if keeper_node_count == 1 else keeper_manifest_3_node _, chi = util.install_clickhouse_and_keeper( chi_file= f'manifests/chi/test-cluster-for-{keeper_type}-{ch_node_count}.yaml', chi_template_file='manifests/chit/tpl-clickhouse-latest.yaml', chi_name='test-cluster-for-zk', keeper_manifest=keeper_manifest, keeper_type=keeper_type, clean_ns=first_install, force_keeper_install=True, keeper_install_first=first_install, make_object_count=False, ) return chi with When("Clean exists ClickHouse Keeper and ZooKeeper"): kubectl.delete_all_chi(settings.test_namespace) kubectl.delete_all_keeper(settings.test_namespace) with When("Install CH 1 node ZK 1 node"): chi = rescale_zk_and_clickhouse(ch_node_count=1, keeper_node_count=1, first_install=True) util.wait_clickhouse_cluster_ready(chi) wait_keeper_ready(keeper_type=keeper_type, pod_count=1) check_zk_root_znode(chi, pod_count=1) util.wait_clickhouse_cluster_ready(chi) wait_clickhouse_no_readonly_replicas(chi) insert_replicated_data(chi, create_tables=['test_repl1'], insert_tables=['test_repl1']) total_iterations = 3 for iteration in range(total_iterations): with When(f"ITERATION {iteration}"): with Then("CH 1 -> 2 wait complete + ZK 1 -> 3 nowait"): chi = rescale_zk_and_clickhouse(ch_node_count=2, keeper_node_count=3) wait_keeper_ready(keeper_type=keeper_type, pod_count=3) check_zk_root_znode(chi, pod_count=3) util.wait_clickhouse_cluster_ready(chi) wait_clickhouse_no_readonly_replicas(chi) insert_replicated_data( chi, create_tables=['test_repl2'], insert_tables=['test_repl1', 'test_repl2']) with Then("CH 2 -> 1 wait complete + ZK 3 -> 1 nowait"): chi = rescale_zk_and_clickhouse(ch_node_count=1, keeper_node_count=1) wait_keeper_ready(keeper_type=keeper_type, pod_count=1) check_zk_root_znode(chi, pod_count=1) util.wait_clickhouse_cluster_ready(chi) wait_clickhouse_no_readonly_replicas(chi) insert_replicated_data( chi, create_tables=['test_repl3'], insert_tables=['test_repl1', 'test_repl2', 'test_repl3']) with When("CH 1 -> 2 wait complete + ZK 1 -> 3 nowait"): chi = rescale_zk_and_clickhouse(ch_node_count=2, keeper_node_count=3) check_zk_root_znode(chi, pod_count=3) with Then('check data in tables'): for table_name, exptected_rows in { "test_repl1": str(1000 + 2000 * total_iterations), "test_repl2": str(2000 * total_iterations), "test_repl3": str(1000 * total_iterations) }.items(): actual_rows = clickhouse.query( chi['metadata']['name'], f'SELECT count() FROM default.{table_name}', pod="chi-test-cluster-for-zk-default-0-1-0") assert actual_rows == exptected_rows, f"Invalid rows counter after inserts {table_name} expected={exptected_rows} actual={actual_rows}" with Then('drop all created tables'): for i in range(3): clickhouse.drop_table_on_cluster(chi, 'all-sharded', f'default.test_repl{i + 1}')