X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=yardstick%2Fcommon%2Futils.py;h=108ee17bc83db621bdb65d8a6b1c5e91ddcfe978;hb=6458b5ec9ea5bdac5b60f2edde8decefae16422f;hp=4952901229859278d5204a45a4d7ba862c2a94b6;hpb=1738c931ab93816007b5434c17d46842e488424a;p=yardstick.git diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py index 495290122..108ee17bc 100644 --- a/yardstick/common/utils.py +++ b/yardstick/common/utils.py @@ -23,16 +23,21 @@ import logging import os import random import re +import signal import socket import subprocess import sys +import time import six from flask import jsonify from six.moves import configparser from oslo_serialization import jsonutils +from oslo_utils import encodeutils import yardstick +from yardstick.common import exceptions + logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) @@ -65,7 +70,7 @@ def itersubclasses(cls, _seen=None): yield sub -def import_modules_from_package(package): +def import_modules_from_package(package, raise_exception=False): """Import modules given a package name :param: package - Full package name. For example: rally.deploy.engines @@ -86,10 +91,27 @@ def import_modules_from_package(package): for module_name in missing_modules: try: importlib.import_module(module_name) - except (ImportError, SyntaxError): + except (ImportError, SyntaxError) as exc: + if raise_exception: + raise exc logger.exception('Unable to import module %s', module_name) +NON_NONE_DEFAULT = object() + + +def get_key_with_default(data, key, default=NON_NONE_DEFAULT): + value = data.get(key, default) + if value is NON_NONE_DEFAULT: + raise KeyError(key) + return value + + +def make_dict_from_map(data, key_map): + return {dest_key: get_key_with_default(data, src_key, default) + for dest_key, (src_key, default) in key_map.items()} + + def makedirs(d): try: os.makedirs(d) @@ -106,19 +128,23 @@ def remove_file(path): raise -def execute_command(cmd): +def execute_command(cmd, **kwargs): exec_msg = "Executing command: '%s'" % cmd logger.debug(exec_msg) - output = subprocess.check_output(cmd.split()).split(os.linesep) - - return output + output = subprocess.check_output(cmd.split(), **kwargs) + return encodeutils.safe_decode(output, incoming='utf-8').split(os.linesep) def source_env(env_file): p = subprocess.Popen(". %s; env" % env_file, stdout=subprocess.PIPE, shell=True) output = p.communicate()[0] + + # sometimes output type would be binary_type, and it don't have splitlines + # method, so we need to decode + if isinstance(output, six.binary_type): + output = encodeutils.safe_decode(output) env = dict(line.split('=', 1) for line in output.splitlines() if '=' in line) os.environ.update(env) return env @@ -383,15 +409,24 @@ class ErrorClass(object): class Timer(object): - def __init__(self): + def __init__(self, timeout=None): super(Timer, self).__init__() self.start = self.delta = None + self._timeout = int(timeout) if timeout else None + + def _timeout_handler(self, *args): + raise exceptions.TimerTimeout(timeout=self._timeout) def __enter__(self): self.start = datetime.datetime.now() + if self._timeout: + signal.signal(signal.SIGALRM, self._timeout_handler) + signal.alarm(self._timeout) return self def __exit__(self, *_): + if self._timeout: + signal.alarm(0) self.delta = datetime.datetime.now() - self.start def __getattr__(self, item): @@ -410,3 +445,50 @@ def read_meminfo(ssh_client): output[match[0]] = match[1] return output + + +def find_relative_file(path, task_path): + """ + Find file in one of places: in abs of path or relative to a directory path, + in this order. + + :param path: + :param task_path: + :return str: full path to file + """ + # fixme: create schema to validate all fields have been provided + for lookup in [os.path.abspath(path), os.path.join(task_path, path)]: + try: + with open(lookup): + return lookup + except IOError: + pass + raise IOError(errno.ENOENT, 'Unable to find {} file'.format(path)) + + +def open_relative_file(path, task_path): + try: + return open(path) + except IOError as e: + if e.errno == errno.ENOENT: + return open(os.path.join(task_path, path)) + raise + + +def wait_until_true(predicate, timeout=60, sleep=1, exception=None): + """Wait until callable predicate is evaluated as True + + :param predicate: (func) callable deciding whether waiting should continue + :param timeout: (int) timeout in seconds how long should function wait + :param sleep: (int) polling interval for results in seconds + :param exception: exception instance to raise on timeout. If None is passed + (default) then WaitTimeout exception is raised. + """ + try: + with Timer(timeout=timeout): + while not predicate(): + time.sleep(sleep) + except exceptions.TimerTimeout: + if exception and issubclass(exception, Exception): + raise exception # pylint: disable=raising-bad-type + raise exceptions.WaitTimeout