#!/usr/bin/env python3 #-*- coding: utf-8 -*- import subprocess import os import getpass import argparse import logging import signal import subprocess import sys CUR_FILE_DIR = os.path.dirname(os.path.realpath(__file__)) DEFAULT_CLICKHOUSE_ROOT = os.path.abspath(os.path.join(CUR_FILE_DIR, "../../")) CURRENT_WORK_DIR = os.getcwd() CONTAINER_NAME = "clickhouse_testflows_tests" DIND_TESTFLOWS_TESTS_IMAGE_NAME = "yandex/clickhouse-testflows-runner" def check_args_and_update_paths(args): if not os.path.isabs(args.binary): args.binary = os.path.abspath(os.path.join(CURRENT_WORK_DIR, args.binary)) if not args.bridge_binary: args.bridge_binary = os.path.join(os.path.dirname(args.binary), 'clickhouse-odbc-bridge') elif not os.path.isabs(args.bridge_binary): args.bridge_binary = os.path.abspath(os.path.join(CURRENT_WORK_DIR, args.bridge_binary)) if not os.path.isabs(args.configs_dir): args.configs_dir = os.path.abspath(os.path.join(CURRENT_WORK_DIR, args.configs_dir)) if not os.path.isabs(args.clickhouse_root): args.clickhouse_root = os.path.abspath(os.path.join(CURRENT_WORK_DIR, args.clickhouse_root)) for path in [args.binary, args.configs_dir, args.clickhouse_root]: if not os.path.exists(path): raise Exception("Path {} doesn't exists".format(path)) def docker_kill_handler_handler(signum, frame): subprocess.check_call('docker kill $(docker ps -a -q --filter name={name} --format="{{{{.ID}}}}")'.format(name=CONTAINER_NAME), shell=True) raise KeyboardInterrupt("Killed by Ctrl+C") signal.signal(signal.SIGINT, docker_kill_handler_handler) if __name__ == "__main__": logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') parser = argparse.ArgumentParser(description="ClickHouse testflows runner") parser.add_argument( "--binary", default=os.environ.get("CLICKHOUSE_TESTS_SERVER_BIN_PATH", os.environ.get("CLICKHOUSE_TESTS_CLIENT_BIN_PATH", "/usr/bin/clickhouse")), help="Path to clickhouse binary") parser.add_argument( "--bridge-binary", default=os.environ.get("CLICKHOUSE_TESTS_ODBC_BRIDGE_BIN_PATH", ""), help="Path to clickhouse-odbc-bridge binary. Defaults to clickhouse-odbc-bridge in the same dir as clickhouse.") parser.add_argument( "--configs-dir", default=os.environ.get("CLICKHOUSE_TESTS_BASE_CONFIG_DIR", os.path.join(DEFAULT_CLICKHOUSE_ROOT, "programs/server")), help="Path to clickhouse configs directory") parser.add_argument( "--clickhouse-root", default=DEFAULT_CLICKHOUSE_ROOT, help="Path to repository root folder") parser.add_argument( "--command", default='', help="Set it to run some other command in container (for example bash)") parser.add_argument( "--disable-net-host", action='store_true', default=False, help="Don't use net host in parent docker container") parser.add_argument( "--docker-image-version", default="latest", help="Version of docker image which runner will use to run tests") parser.add_argument('testflows_args', nargs='*', help="args for testflows command") args = parser.parse_args() check_args_and_update_paths(args) net = "" if not args.disable_net_host: net = "--net=host" # create named volume which will be used inside to store images and other docker related files, # to avoid redownloading it every time # # should be removed manually when not needed subprocess.check_call('docker volume create {name}_volume'.format(name=CONTAINER_NAME), shell=True) # enable tty mode & interactive for docker if we have real tty tty = "" if sys.stdout.isatty() and sys.stdin.isatty(): tty = "-it" cmd = "docker run {net} {tty} --rm --name {name} --privileged --volume={bridge_bin}:/clickhouse-odbc-bridge --volume={bin}:/clickhouse \ --volume={cfg}:/clickhouse-config --volume={pth}:/ClickHouse --volume={name}_volume:/var/lib/docker -e TESTFLOWS_OPTS='{opts}' {img} {command}".format( net=net, tty=tty, bin=args.binary, bridge_bin=args.bridge_binary, cfg=args.configs_dir, pth=args.clickhouse_root, opts=' '.join(args.testflows_args), img=DIND_TESTFLOWS_TESTS_IMAGE_NAME + ":" + args.docker_image_version, name=CONTAINER_NAME, command=args.command ) print(("Running testflows container as: '" + cmd + "'.")) # testflows return non zero error code on failed tests subprocess.call(cmd, shell=True) result_path = os.environ.get("CLICKHOUSE_TESTS_RESULT_PATH", None) if result_path is not None: move_from = os.path.join(args.clickhouse_root, 'tests/testflows') status = os.path.join(move_from, 'check_status.tsv') results = os.path.join(move_from, 'test_results.tsv') subprocess.call("mv {} {}".format(status, result_path), shell=True) subprocess.call("mv {} {}".format(results, result_path), shell=True)