Beispiel #1
0
class ScenarioExecutor(EngineModule):
    """
    :type provisioning: engine.Provisioning
    :type execution: BetterDict
    """

    RAMP_UP = "ramp-up"
    HOLD_FOR = "hold-for"
    CONCURR = "concurrency"
    THRPT = "throughput"
    EXEC = "execution"
    STEPS = "steps"
    LOAD_FMT = namedtuple("LoadSpec", "concurrency throughput ramp_up hold iterations duration steps")

    def __init__(self):
        super(ScenarioExecutor, self).__init__()
        self.provisioning = None
        self.execution = BetterDict()  # FIXME: why have this field if we have `parameters` from base class?
        self.__scenario = None
        self.label = None
        self.widget = None
        self.reader = None
        self.delay = None
        self.start_time = None
        self.env = None
        self.preprocess_args = lambda x: None

    def has_results(self):
        if self.reader and self.reader.buffer:
            return True
        else:
            return False

    def get_script_path(self, required=False, scenario=None):
        """
        :type required: bool
        :type scenario: Scenario
        """
        if scenario is None:
            scenario = self.get_scenario()

        if required:
            exc = TaurusConfigError("You must provide script for %s" % self)
            script = scenario.get(Scenario.SCRIPT, exc)
        else:
            script = scenario.get(Scenario.SCRIPT)

        if script:
            script = self.engine.find_file(script)
            scenario[Scenario.SCRIPT] = script

        return script

    def get_scenario(self, name=None, cache_scenario=True):
        """
        Returns scenario dict, extract if scenario is inlined

        :return: DictOfDicts
        """
        if name is None and self.__scenario is not None:
            return self.__scenario

        scenarios = self.engine.config.get("scenarios", force_set=True)

        if name is None:  # get current scenario
            exc = TaurusConfigError("Scenario is not found in execution: %s" % self.execution)
            label = self.execution.get('scenario', exc)

            is_script = isinstance(label, string_types) and label not in scenarios and \
                        os.path.exists(self.engine.find_file(label))
            if isinstance(label, list):
                msg = "Invalid content of scenario, list type instead of dict or string: %s"
                raise TaurusConfigError(msg % label)
            if isinstance(label, dict) or is_script:
                self.log.debug("Extract %s into scenarios" % label)
                if isinstance(label, string_types):
                    scenario = BetterDict.from_dict({Scenario.SCRIPT: label})
                else:
                    scenario = label

                path = self.get_script_path(scenario=Scenario(self.engine, scenario))
                if path:
                    label = os.path.basename(path)
                if not path or label in scenarios:
                    hash_str = str(hashlib.md5(to_json(scenario).encode()).hexdigest())
                    label = 'autogenerated_' + hash_str[-10:]

                scenarios[label] = scenario
                self.execution['scenario'] = label

            self.label = label
        else:  # get scenario by name
            label = name

        exc = TaurusConfigError("Scenario '%s' not found in scenarios: %s" % (label, scenarios.keys()))
        scenario = scenarios.get(label, exc)
        scenario_obj = Scenario(self.engine, scenario)

        if name is None and cache_scenario:
            self.__scenario = scenario_obj

        return scenario_obj

    def get_load(self):
        """
        Helper method to read load specification
        """

        def eval_int(value):
            try:
                return int(value)
            except (ValueError, TypeError):
                return value

        def eval_float(value):
            try:
                return int(value)
            except (ValueError, TypeError):
                return value

        prov_type = self.engine.config.get(Provisioning.PROV)

        ensure_is_dict(self.execution, ScenarioExecutor.THRPT, prov_type)
        throughput = eval_float(self.execution[ScenarioExecutor.THRPT].get(prov_type, 0))

        ensure_is_dict(self.execution, ScenarioExecutor.CONCURR, prov_type)
        concurrency = eval_int(self.execution[ScenarioExecutor.CONCURR].get(prov_type, 0))

        iterations = eval_int(self.execution.get("iterations", None))

        ramp_up = self.execution.get(ScenarioExecutor.RAMP_UP, None)
        steps = eval_int(self.execution.get(ScenarioExecutor.STEPS, None))
        hold = dehumanize_time(self.execution.get(ScenarioExecutor.HOLD_FOR, 0))
        if ramp_up is None:
            duration = hold
        else:
            ramp_up = dehumanize_time(ramp_up)
            duration = hold + ramp_up

        if duration and not iterations:
            iterations = 0  # which means infinite

        msg = ''
        if not isinstance(concurrency, numeric_types + (type(None),)):
            msg += "Invalid concurrency value[%s]: %s " % (type(concurrency).__name__, concurrency)
        if not isinstance(throughput, numeric_types + (type(None),)):
            msg += "Invalid throughput value[%s]: %s " % (type(throughput).__name__, throughput)
        if not isinstance(steps, numeric_types + (type(None),)):
            msg += "Invalid throughput value[%s]: %s " % (type(steps).__name__, steps)
        if not isinstance(iterations, numeric_types + (type(None),)):
            msg += "Invalid throughput value[%s]: %s " % (type(iterations).__name__, iterations)

        if msg:
            raise TaurusConfigError(msg)

        return self.LOAD_FMT(concurrency=concurrency, ramp_up=ramp_up, throughput=throughput, hold=hold,
                             iterations=iterations, duration=duration, steps=steps)

    def get_resource_files(self):
        files_list = []
        if isinstance(self, FileLister):
            files_list.extend(self.resource_files())
        files_list.extend(self.execution.get("files", []))
        return files_list

    def __repr__(self):
        return "%s/%s" % (self.execution.get("executor", None), self.label if self.label else id(self))

    def execute(self, args, cwd=None, stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=False):
        self.preprocess_args(args)

        return self.engine.start_subprocess(args=args, cwd=cwd, stdout=stdout,
                                            stderr=stderr, stdin=stdin, shell=shell, env=self.env)
Beispiel #2
0
class EngineModule(object):
    """
    Base class for any BZT engine module

    :type engine: Engine
    :type settings: BetterDict
    """

    def __init__(self):
        self.log = logging.getLogger('')
        self.engine = None
        self.settings = BetterDict()
        self.parameters = BetterDict()

    def prepare(self):
        """
        Preparation stage, at which configuration is being read, configs
        and tools being prepared. All long preparations and checks should be
        made here, to make `startup` stage as fast as possible.
        """
        pass

    def startup(self):
        """
        Startup should be as fast as possible. Launch background processes,
        do some API calls for initiation of actual work. Consider making all
        checks and preparations on `prepare` stage.
        """
        pass

    def check(self):
        """
        Check if work should be finished

        :rtype: bool
        :return: True if should be finished
        """
        return False

    def shutdown(self):
        """
        Stop all processes that were started in `startup` stage.
        Should also be as fast as possible, deferring all long operations to
        `post_process` stage.
        """
        pass

    def post_process(self):
        """
        Do all possibly long analysis and processing on run results
        """
        pass

    def _should_run(self):
        """
        Returns True if provisioning matches run-at
        """
        prov = self.engine.config.get(Provisioning.PROV)
        runat = self.parameters.get("run-at", None)
        if runat is not None and prov != runat:
            self.log.debug("Should not run because of non-matching prov: %s != %s", prov, runat)
            return False
        return True