diff options
Diffstat (limited to 'dovetail/container.py')
-rw-r--r-- | dovetail/container.py | 191 |
1 files changed, 148 insertions, 43 deletions
diff --git a/dovetail/container.py b/dovetail/container.py index ae7c8e2e..14045165 100644 --- a/dovetail/container.py +++ b/dovetail/container.py @@ -8,6 +8,7 @@ # import os +import yaml import utils.dovetail_logger as dt_logger import utils.dovetail_utils as dt_utils @@ -17,7 +18,8 @@ from utils.dovetail_config import DovetailConfig as dt_cfg class Container(object): container_list = {} - has_pull_latest_image = {'yardstick': False, 'functest': False} + has_pull_latest_image = {'yardstick': False, 'functest': False, + 'bottlenecks': False} logger = None @@ -41,20 +43,23 @@ class Container(object): return '%s:%s' % (dt_cfg.dovetail_config[type]['image_name'], dt_cfg.dovetail_config[type]['docker_tag']) except KeyError as e: - cls.logger.error('There is no %s in %s config file.', e, type) + cls.logger.exception( + 'There is no key {} in {} config file.'.format(e, type)) return None # get the openrc_volume for creating the container @classmethod def openrc_volume(cls, type): dovetail_config = dt_cfg.dovetail_config - dovetail_config['openrc'] = os.path.abspath(dovetail_config['openrc']) + dovetail_config['openrc'] = os.path.join(dovetail_config['config_dir'], + dovetail_config['env_file']) if os.path.isfile(dovetail_config['openrc']): openrc = ' -v %s:%s ' % (dovetail_config['openrc'], dovetail_config[type]['openrc']) return openrc else: - cls.logger.error("File %s is not exist", dovetail_config['openrc']) + cls.logger.error( + "File {} doesn't exist.".format(dovetail_config['openrc'])) return None # set functest envs and TEST_DB_URL for creating functest container @@ -72,8 +77,7 @@ class Container(object): if 'sdnvpn' in testcase_name: ins_type = "-e INSTALLER_TYPE=netvirt" scenario = " -e DEPLOY_SCENARIO=bgpvpn" - node = " -e NODE_NAME=master" - envs = "%s %s %s" % (ins_type, scenario, node) + envs = "%s %s" % (ins_type, scenario) dovetail_config = dt_cfg.dovetail_config if dovetail_config['report_dest'].startswith("http"): @@ -99,18 +103,40 @@ class Container(object): cls.logger.error("Can't find any external network.") return None - if dovetail_config['report_dest'].startswith("http"): - cls.logger.info("Yardstick can't push results to DB.") - cls.logger.info("Results will be stored with files.") - log_vol = '-v %s:%s ' % (dovetail_config['result_dir'], dovetail_config["yardstick"]['result']['log']) - key_path = os.path.join(dovetail_config['userconfig_dir'], 'id_rsa') - key_con_path = dovetail_config["yardstick"]['result']['key_path'] - key_vol = '-v %s:%s ' % (key_path, key_con_path) + + # for yardstick, support pod.yaml configuration + pod_file = os.path.join(dovetail_config['config_dir'], + dovetail_config['pod_file']) + if not os.path.isfile(pod_file): + cls.logger.error("File {} doesn't exist.".format(pod_file)) + return None + key_file = os.path.join(dovetail_config['config_dir'], + dovetail_config['pri_key']) + key_container_path = dovetail_config["yardstick"]['result']['key_path'] + if not os.path.isfile(key_file): + cls.logger.debug("Key file {} is not found, must use password in " + "{} to do HA test.".format(key_file, pod_file)) + key_vol = '' + else: + key_vol = '-v %s:%s ' % (key_file, key_container_path) return "%s %s %s" % (envs, log_vol, key_vol) @classmethod + def set_bottlenecks_config(cls, testcase_name): + dovetail_config = dt_cfg.dovetail_config + yard_tag = dovetail_config['yardstick']['docker_tag'] + docker_vol = '-v /var/run/docker.sock:/var/run/docker.sock' + env = ('-e Yardstick_TAG={} -e OUTPUT_FILE={}.out' + .format(yard_tag, testcase_name)) + report = "" + if dovetail_config['report_dest'].startswith("http"): + report = ("-e BOTTLENECKS_DB_TARGET={}" + .format(dovetail_config['report_dest'])) + return "{} {} {}".format(docker_vol, env, report) + + @classmethod def create(cls, type, testcase_name): dovetail_config = dt_cfg.dovetail_config docker_image = cls.get_docker_image(type) @@ -123,42 +149,91 @@ class Container(object): # CI_DEBUG is used for showing the debug logs of the upstream projects # BUILD_TAG is the unique id for this test - envs = ' -e CI_DEBUG=true' + envs = ' -e CI_DEBUG=true -e NODE_NAME=master' envs = envs + ' -e BUILD_TAG=%s-%s' % (dovetail_config['build_tag'], testcase_name) + hosts_config = "" + hosts_config_file = os.path.join(dovetail_config['config_dir'], + 'hosts.yaml') + try: + with open(hosts_config_file) as f: + hosts_info = yaml.safe_load(f) + if hosts_info['hosts_info']: + for host in hosts_info['hosts_info']: + dt_utils.add_hosts_info(host) + hosts_config += " --add-host " + hosts_config += str(host) + cls.logger.debug('Get hosts info {}.'.format(host)) + except Exception: + cls.logger.warn('Failed to get hosts info in {}, ' + 'maybe some issues with domain name resolution.' + .format(hosts_config_file)) + config = "" if type.lower() == "functest": config = cls.set_functest_config(testcase_name) if type.lower() == "yardstick": config = cls.set_yardstick_config() + if type.lower() == "bottlenecks": + config = cls.set_bottlenecks_config(testcase_name) if not config: return None # for refstack, support user self_defined configuration - # for yardstick, support pod.yaml configuration - pod_file = os.path.join(dovetail_config['userconfig_dir'], 'pod.yaml') - if type.lower() == "yardstick" and not os.path.exists(pod_file): - cls.logger.error("File %s doesn't exist.", pod_file) - return None - key_file = os.path.join(dovetail_config['userconfig_dir'], 'id_rsa') - if type.lower() == "yardstick" and not os.path.exists(key_file): - cls.logger.debug("File %s doesn't exist.", key_file) - cls.logger.debug("Can just use password in %s.", pod_file) config_volume = \ - ' -v %s:%s ' % (dovetail_config['userconfig_dir'], - dovetail_config["functest"]['config']['dir']) + ' -v %s:%s ' % (os.getenv("DOVETAIL_HOME"), + dovetail_config[type]['config']['dir']) + + cacert_volume = "" + https_enabled = dt_utils.check_https_enabled(cls.logger) + cacert = os.getenv('OS_CACERT',) + if https_enabled: + cls.logger.info("https enabled...") + if cacert is not None: + if not os.path.isfile(cacert): + cls.logger.error("Env variable 'OS_CACERT' is set to {} " + "but the file does not exist." + .format(cacert)) + return None + elif not dovetail_config['config_dir'] in cacert: + cls.logger.error("Credential file has to be put in {}, " + "which can be mount into container." + .format(dovetail_config['config_dir'])) + return None + cacert_volume = ' -v %s:%s ' % (cacert, cacert) + else: + cls.logger.warn("https enabled, OS_CACERT not set, insecure " + "connection used or OS_CACERT missed") result_volume = ' -v %s:%s ' % (dovetail_config['result_dir'], dovetail_config[type]['result']['dir']) - cmd = 'sudo docker run %s %s %s %s %s %s %s /bin/bash' % \ - (opts, envs, config, openrc, config_volume, - result_volume, docker_image) + cmd = 'sudo docker run %s %s %s %s %s %s %s %s %s /bin/bash' % \ + (opts, envs, config, hosts_config, openrc, cacert_volume, + config_volume, result_volume, docker_image) dt_utils.exec_cmd(cmd, cls.logger) ret, container_id = \ dt_utils.exec_cmd("sudo docker ps | grep " + docker_image + " | awk '{print $1}' | head -1", cls.logger) cls.container_list[type] = container_id + + if 'sdnvpn' in str(testcase_name): + prefix_path = dt_cfg.dovetail_config[type]['config']['dir'] + file_name = dt_cfg.dovetail_config['sdnvpn_image'] + src_path = os.path.join(prefix_path, 'pre_config', file_name) + dest_path = '/home/opnfv/functest/images' + Container.pre_copy(container_id, src_path, dest_path) + + if type.lower() == 'functest': + prefix_path = dt_cfg.dovetail_config[type]['config']['dir'] + file_name = dt_cfg.dovetail_config['cirros_image'] + src_path = os.path.join(prefix_path, 'pre_config', file_name) + dest_path = '/home/opnfv/functest/images' + Container.pre_copy(container_id, src_path, dest_path) + + if type.lower() == 'yardstick': + cls.set_yardstick_conf_file(container_id) + return container_id @classmethod @@ -177,15 +252,15 @@ class Container(object): cmd = "sudo docker ps -aq -f 'ancestor=%s'" % (image_id) ret, msg = dt_utils.exec_cmd(cmd, cls.logger) if msg and ret == 0: - cls.logger.debug('image %s has containers, skip.', image_id) + cls.logger.debug('Image {} has containers, skip.'.format(image_id)) return True cmd = 'sudo docker rmi %s' % (image_id) - cls.logger.debug('remove image %s', image_id) + cls.logger.debug('Remove image {}.'.format(image_id)) ret, msg = dt_utils.exec_cmd(cmd, cls.logger) if ret == 0: - cls.logger.debug('remove image %s successfully', image_id) + cls.logger.debug('Remove image {} successfully.'.format(image_id)) return True - cls.logger.error('fail to remove image %s.', image_id) + cls.logger.error('Failed to remove image {}.'.format(image_id)) return False @classmethod @@ -193,9 +268,10 @@ class Container(object): cmd = 'sudo docker pull %s' % (image_name) ret, msg = dt_utils.exec_cmd(cmd, cls.logger) if ret != 0: - cls.logger.error('fail to pull docker image %s!', image_name) + cls.logger.error( + 'Failed to pull docker image {}!'.format(image_name)) return False - cls.logger.debug('success to pull docker image %s!', image_name) + cls.logger.debug('Success to pull docker image {}!'.format(image_name)) return True @classmethod @@ -204,7 +280,8 @@ class Container(object): if not docker_image: return None if cls.has_pull_latest_image[validate_type] is True: - cls.logger.debug('%s is already the newest version.', docker_image) + cls.logger.debug( + '{} is already the newest version.'.format(docker_image)) return docker_image old_image_id = cls.get_image_id(docker_image) if not cls.pull_image_only(docker_image): @@ -212,13 +289,14 @@ class Container(object): cls.has_pull_latest_image[validate_type] = True new_image_id = cls.get_image_id(docker_image) if not new_image_id: - cls.logger.error("fail to get the new image's id %s", docker_image) + cls.logger.error( + "Failed to get the id of image {}.".format(docker_image)) return None if not old_image_id: return docker_image if new_image_id == old_image_id: - cls.logger.debug('image %s has no changes, no need to remove.', - docker_image) + cls.logger.debug('Image {} has no changes, no need to remove.' + .format(docker_image)) else: cls.remove_image(old_image_id) return docker_image @@ -230,11 +308,23 @@ class Container(object): return image_id @classmethod - def clean(cls, container_id): - cmd1 = 'sudo docker stop %s' % (container_id) - dt_utils.exec_cmd(cmd1, cls.logger) - cmd2 = 'sudo docker rm %s' % (container_id) - dt_utils.exec_cmd(cmd2, cls.logger) + def check_container_exist(cls, container_name): + cmd = ('sudo docker ps -aq -f name={}'.format(container_name)) + ret, msg = dt_utils.exec_cmd(cmd, cls.logger) + if ret == 0 and msg: + return True + return False + + @classmethod + def clean(cls, container_id, valid_type): + cmd = ('sudo docker rm -f {}'.format(container_id)) + dt_utils.exec_cmd(cmd, cls.logger) + if valid_type.lower() == 'bottlenecks': + containers = dt_cfg.dovetail_config[valid_type]['extra_container'] + for container in containers: + if cls.check_container_exist(container): + cmd = ('sudo docker rm -f {}'.format(container)) + dt_utils.exec_cmd(cmd, cls.logger) @classmethod def exec_cmd(cls, container_id, sub_cmd, exit_on_error=False): @@ -250,3 +340,18 @@ class Container(object): return (1, 'src_path or dest_path is empty') cmd = 'cp %s %s' % (src_path, dest_path) return cls.exec_cmd(container_id, cmd, exit_on_error) + + @classmethod + def set_yardstick_conf_file(cls, container_id): + valid_type = 'yardstick' + src = dt_cfg.dovetail_config[valid_type]['yard_conf']['src_file'] + dest = dt_cfg.dovetail_config[valid_type]['yard_conf']['dest_file'] + cls.pre_copy(container_id, src, dest) + url = dt_cfg.dovetail_config['report_dest'] + if url.startswith("http"): + cmd = ("sed -i '16s#http://127.0.0.1:8000/results#{}#g' {}" + .format(url, dest)) + cls.exec_cmd(container_id, cmd) + if url.lower() == 'file': + cmd = ("sed -i '12s/http/file/g' {}".format(dest)) + cls.exec_cmd(container_id, cmd) |