Esempio n. 1
0
    def __init__(self, config, scenario, engine):
        super(HierarchicHTTPRequest, self).__init__(config, scenario, engine)
        self.upload_files = self.config.get("upload-files", [])

        if self.method == "PUT" and len(self.upload_files) > 1:
            self.upload_files = self.upload_files[:1]

        for file_dict in self.upload_files:
            param = file_dict.get("param", None)

            if self.method == "PUT":
                file_dict["param"] = ""
            if self.method == "POST" and not param:
                raise TaurusConfigError(
                    "Items from upload-files must specify parameter name")

            path_exc = TaurusConfigError(
                "Items from upload-files must specify path to file")
            path = str(file_dict.get("path", path_exc))
            if not has_variable_pattern(path):  # exclude variables
                path = self.engine.find_file(path)  # prepare full path for jmx
            else:
                msg = "Path '%s' contains variable and can't be expanded. Don't use relative paths in 'upload-files'!"
                self.log.warning(msg % path)

            file_dict["path"] = path

            mime = mimetypes.guess_type(
                file_dict["path"])[0] or "application/octet-stream"
            file_dict.get("mime-type", mime, force_set=True)
        self.content_encoding = self.config.get('content-encoding', None)
Esempio n. 2
0
    def __load_module(self, alias):
        """
        Load module class by alias
        :param alias: str
        :return: class
        """
        if alias in self.modules:
            return self.modules[alias]

        mod_conf = self.config.get('modules')
        if alias not in mod_conf:
            msg = "Module '%s' not found in list of available aliases %s" % (alias, sorted(mod_conf.keys()))
            raise TaurusConfigError(msg)

        settings = ensure_is_dict(mod_conf, alias, "class")

        acopy = copy.deepcopy(settings)
        BetterDict.traverse(acopy, Configuration.masq_sensitive)
        self.log.debug("Module config: %s %s", alias, acopy)

        err = TaurusConfigError("Class name for alias '%s' is not found in module settings: %s" % (alias, settings))
        clsname = settings.get('class', err)

        self.modules[alias] = load_class(clsname)
        if not issubclass(self.modules[alias], EngineModule):
            # raise TaurusInternalException("Module class does not inherit from EngineModule: %s" % clsname)
            pass

        return self.modules[alias]
Esempio n. 3
0
    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
Esempio n. 4
0
 def get_data_sources(self):
     data_sources = self.get(self.FIELD_DATA_SOURCES, [])
     if not isinstance(data_sources, list):
         raise TaurusConfigError("data-sources '%s' is not a list" % data_sources)
     for index, _ in enumerate(data_sources):
         ensure_is_dict(data_sources, index, "path")
     return self.get(self.FIELD_DATA_SOURCES, [])
Esempio n. 5
0
    def load(self, config_files, callback=None):
        """
        Load and merge JSON/YAML files into current dict

        :type callback: callable
        :type config_files: list[str]
        """
        self.log.debug("Configs: %s", config_files)
        for config_file in config_files:
            try:
                configs = []
                with codecs.open(config_file, 'r', encoding='utf-8') as fds:
                    if self.tab_replacement_spaces:
                        contents = self._replace_tabs(fds.readlines(), config_file)
                    else:
                        contents = fds.read()

                    self._read_yaml_or_json(config_file, configs, contents)

                for config in configs:
                    self.merge(config)

            except KeyboardInterrupt:
                raise
            except InvalidTaurusConfiguration:
                raise
            except BaseException as exc:
                raise TaurusConfigError("Error when reading config file '%s': %s" % (config_file, exc))

            if callback is not None:
                callback(config_file)
Esempio n. 6
0
    def prepare(self):
        """
        Preparation in provisioning begins with reading executions list
        and instantiating ScenarioExecutor classes for them
        """
        super(Provisioning, self).prepare()
        esettings = self.engine.config.get(SETTINGS)
        default_executor = esettings.get("default-executor", None)

        exc = TaurusConfigError("No 'execution' is configured. Did you forget to pass config files?")

        if ScenarioExecutor.EXEC not in self.engine.config and self.disallow_empty_execution:
            # raise exc
            pass

        executions = self.engine.config.get(ScenarioExecutor.EXEC, [])
        if not executions and self.disallow_empty_execution:
            # raise exc
            pass

        if isinstance(executions, dict):
            executions = [executions]

        for execution in executions:
            executor = execution.get("executor", default_executor)
            if not executor:
                msg = "Cannot determine executor type and no default executor in %s"
                # raise TaurusConfigError(msg % execution)
                pass
                
            instance = self.engine.instantiate_module(executor)
            instance.provisioning = self
            instance.execution = execution
            # assert isinstance(instance, ScenarioExecutor)
            self.executors.append(instance)
Esempio n. 7
0
 def visit_includescenarioblock(self, block):
     scenario_name = block.scenario_name
     if scenario_name in self.path:
         msg = "Mutual recursion detected in include-scenario blocks (scenario %s)"
         raise TaurusConfigError(msg % scenario_name)
     self.record_path(scenario_name)
     scenario = self.executor.get_scenario(name=block.scenario_name)
     return self.executor.res_files_from_scenario(scenario)
Esempio n. 8
0
 def __prepare_provisioning(self):
     """
     Instantiate provisioning class
     """
     err = TaurusConfigError("Please check global config availability or configure provisioning settings")
     cls = self.config.get(Provisioning.PROV, err)
     self.provisioning = self.instantiate_module(cls)
     self.prepared.append(self.provisioning)
     self.provisioning.prepare()
Esempio n. 9
0
    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)
Esempio n. 10
0
 def __parse_requests(self, raw_requests, require_url=True):
     requests = []
     for key in range(len(raw_requests)):  # pylint: disable=consider-using-enumerate
         req = ensure_is_dict(raw_requests, key, "url")
         if not require_url and "url" not in req:
             req["url"] = None
         try:
             requests.append(self.__parse_request(req))
         except BaseException as exc:
             logging.debug("%s\n%s" % (exc, traceback.format_exc()))
             raise TaurusConfigError("Wrong request:\n %s" % req)
     return requests
Esempio n. 11
0
    def prepare(self):
        """
        Read aggregation options
        """
        super(ConsolidatingAggregator, self).prepare()

        # make unique & sort
        self.track_percentiles = self.settings.get("percentiles",
                                                   self.track_percentiles)
        self.track_percentiles = list(set(self.track_percentiles))
        self.track_percentiles.sort()
        self.settings["percentiles"] = self.track_percentiles

        self.ignored_labels = self.settings.get("ignore-labels",
                                                self.ignored_labels)
        self.generalize_labels = self.settings.get("generalize-labels",
                                                   self.generalize_labels)

        self.min_buffer_len = dehumanize_time(
            self.settings.get("min-buffer-len", self.min_buffer_len))

        max_buffer_len = self.settings.get("max-buffer-len",
                                           self.max_buffer_len)
        try:
            self.max_buffer_len = dehumanize_time(max_buffer_len)
        except TaurusInternalException as exc:
            self.log.debug("Exception in dehumanize_time(%s): %s",
                           max_buffer_len, exc)
            raise TaurusConfigError("Wrong 'max-buffer-len' value: %s" %
                                    max_buffer_len)

        self.buffer_multiplier = self.settings.get("buffer-multiplier",
                                                   self.buffer_multiplier)

        count = len(self.track_percentiles)
        if count == 1:
            self.buffer_scale_idx = str(float(self.track_percentiles[0]))
        if count > 1:
            percentile = self.settings.get("buffer-scale-choice", 0.5)
            percentiles = [i / (count - 1.0) for i in range(count)]
            distances = [
                abs(percentile - percentiles[i]) for i in range(count)
            ]
            index_position = distances.index(min(distances))
            self.buffer_scale_idx = str(
                float(self.track_percentiles[index_position]))

        debug_str = 'Buffer scaling setup: percentile %s from %s selected'
        self.log.debug(debug_str, self.buffer_scale_idx,
                       self.track_percentiles)
        self.rtimes_len = self.settings.get("rtimes-len", self.rtimes_len)
        self.max_error_count = self.settings.get("max-error-variety",
                                                 self.max_error_count)
Esempio n. 12
0
    def __init__(self, config, scenario, engine):
        self.engine = engine
        self.log = self.engine.log.getChild(self.__class__.__name__)
        super(HTTPRequest, self).__init__(config, scenario)
        msg = "Option 'url' is mandatory for request but not found in %s" % config
        self.url = self.config.get("url", TaurusConfigError(msg))
        self.label = self.config.get("label", self.url)
        self.method = self.config.get("method", "GET")
        if not has_variable_pattern(self.method):
            self.method = self.method.upper()

        # TODO: add method to join dicts/lists from scenario/request level?
        self.headers = self.config.get("headers", {})

        self.keepalive = self.config.get('keepalive', None)
        self.timeout = self.config.get('timeout', None)
        self.think_time = self.config.get('think-time', None)
        self.follow_redirects = self.config.get('follow-redirects', None)
        self.body = self.__get_body()
Esempio n. 13
0
    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
Esempio n. 14
0
    def __configure(self, configs):
        self.log.info("Starting with configs: %s", configs)

        if self.options.no_system_configs is None:
            self.options.no_system_configs = False

        bzt_rc = os.path.expanduser(os.path.join('~', ".bzt-rc"))
        if os.path.exists(bzt_rc):
            self.log.debug("Using personal config: %s" % bzt_rc)
        else:
            self.log.debug("Adding personal config: %s", bzt_rc)
            self.log.info("No personal config found, creating one at %s",
                          bzt_rc)
            shutil.copy(
                os.path.join(get_full_path(__file__, step_up=1), 'resources',
                             'base-bzt-rc.yml'), bzt_rc)

        merged_config = self.engine.configure(
            [bzt_rc] + configs, not self.options.no_system_configs)

        # apply aliases
        for alias in self.options.aliases:
            cli_aliases = self.engine.config.get('cli-aliases')
            keys = sorted(cli_aliases.keys())
            err = TaurusConfigError(
                "'%s' not found in aliases. Available aliases are: %s" %
                (alias, ", ".join(keys)))
            self.engine.config.merge(cli_aliases.get(alias, err))

        if self.options.option:
            overrider = ConfigOverrider(self.log)
            overrider.apply_overrides(self.options.option, self.engine.config)

        if self.__is_verbose():
            CLI.console_handler.setLevel(logging.DEBUG)
        self.engine.create_artifacts_dir(configs, merged_config)
        self.engine.default_cwd = os.getcwd()
        self.engine.eval_env(
        )  # yacky, I don't like having it here, but how to apply it after aliases and artif dir?
Esempio n. 15
0
    def __lint_config(self):
        settings = self.engine.config.get(CLI.CLI_SETTINGS).get("linter")
        self.log.debug("Linting config")
        self.warn_on_unfamiliar_fields = settings.get(
            "warn-on-unfamiliar-fields", True)
        config_copy = copy.deepcopy(self.engine.config)
        ignored_warnings = settings.get("ignored-warnings", [])
        self.linter = ConfigurationLinter(config_copy, ignored_warnings,
                                          self.log)
        self.linter.register_checkers()
        self.linter.lint()
        warnings = self.linter.get_warnings()
        for warning in warnings:
            self.log.warning(str(warning))

        if settings.get("lint-and-exit", False):
            if warnings:
                raise TaurusConfigError(
                    "Errors were found in the configuration")
            else:
                raise NormalShutdown(
                    "Linting has finished, no errors were found")
Esempio n. 16
0
    def __prepare_reporters(self):
        """
        Instantiate reporters, then prepare them in case they would like to interact
        """
        reporting = self.config.get(Reporter.REP, [])
        for index, reporter in enumerate(reporting):
            reporter = ensure_is_dict(reporting, index, "module")
            msg = "reporter 'module' field isn't recognized: %s"
            cls = reporter.get('module', TaurusConfigError(msg % reporter))
            instance = self.instantiate_module(cls)
            instance.parameters = reporter
            if self.__singletone_exists(instance, self.reporters):
                continue
            # assert isinstance(instance, Reporter)
            self.reporters.append(instance)

        for reporter in self.reporters[:]:
            if not reporter.should_run():
                self.reporters.remove(reporter)

        # prepare reporters
        for module in self.reporters:
            self.prepared.append(module)
            module.prepare()
Esempio n. 17
0
    def __parse_request(self, req):
        if 'if' in req:
            condition = req.get("if")

            # TODO: apply some checks to `condition`?
            then_clause = req.get(
                "then",
                TaurusConfigError(
                    "'then' clause is mandatory for 'if' blocks"))
            then_requests = self.__parse_requests(then_clause)
            else_clause = req.get("else", [])
            else_requests = self.__parse_requests(else_clause)
            return IfBlock(condition, then_requests, else_requests, req)
        elif 'once' in req:
            do_block = req.get(
                "once",
                TaurusConfigError(
                    "operation list is mandatory for 'once' blocks"))
            do_requests = self.__parse_requests(do_block)
            return OnceBlock(do_requests, req)
        elif 'loop' in req:
            loops = req.get("loop")
            do_block = req.get(
                "do",
                TaurusConfigError(
                    "'do' option is mandatory for 'loop' blocks"))
            do_requests = self.__parse_requests(do_block)
            return LoopBlock(loops, do_requests, req)
        elif 'while' in req:
            condition = req.get("while")
            do_block = req.get(
                "do",
                TaurusConfigError(
                    "'do' option is mandatory for 'while' blocks"))
            do_requests = self.__parse_requests(do_block)
            return WhileBlock(condition, do_requests, req)
        elif 'foreach' in req:
            iteration_str = req.get("foreach")
            match = re.match(r'(.+) in (.+)', iteration_str)
            if not match:
                msg = "'foreach' value should be in format '<elementName> in <collection>' but '%s' found"
                raise TaurusConfigError(msg % iteration_str)
            loop_var, input_var = match.groups()
            do_block = req.get(
                "do",
                TaurusConfigError(
                    "'do' field is mandatory for 'foreach' blocks"))
            do_requests = self.__parse_requests(do_block)
            return ForEachBlock(input_var, loop_var, do_requests, req)
        elif 'transaction' in req:
            name = req.get('transaction')
            do_block = req.get(
                'do',
                TaurusConfigError(
                    "'do' field is mandatory for transaction blocks"))
            do_requests = self.__parse_requests(do_block)
            include_timers = req.get('include-timers')
            return TransactionBlock(name, do_requests, include_timers, req,
                                    self.scenario)
        elif 'include-scenario' in req:
            name = req.get('include-scenario')
            return IncludeScenarioBlock(name, req)
        elif 'action' in req:
            action = req.get('action')
            if action not in ('pause', 'stop', 'stop-now', 'continue'):
                raise TaurusConfigError(
                    "Action should be either 'pause', 'stop', 'stop-now' or 'continue'"
                )
            target = req.get('target', 'current-thread')
            if target not in ('current-thread', 'all-threads'):
                msg = "Target for action should be either 'current-thread' or 'all-threads' but '%s' found"
                raise TaurusConfigError(msg % target)
            duration = req.get('pause-duration', None)
            if duration is not None:
                duration = dehumanize_time(duration)
            return ActionBlock(action, target, duration, req)
        elif 'set-variables' in req:
            mapping = req.get('set-variables')
            return SetVariables(mapping, req)
        else:
            return HierarchicHTTPRequest(req, self.scenario, self.engine)