Пример #1
0
    def validate(self, only_syntax=False):
        """Perform full task configuration validation.

        :param only_syntax: Check only syntax of task configuration
        """
        self.task.update_status(consts.TaskStatus.VALIDATING)
        try:
            self._validate_config_syntax(self.config)
            if only_syntax:
                return
            self._validate_config_platforms(self.config)
            self._validate_config_semantic(self.config)
        except Exception as e:
            exception_info = json.dumps(traceback.format_exc(), indent=2,
                                        separators=(",", ": "))
            self.task.set_failed(type(e).__name__, str(e), exception_info)
            expected_errors = (
                # this error is a wrapper for all error messages from
                # validators.
                exceptions.InvalidTaskConfig,
                # rally.task.task_cfg raises it
                # _validate_config_semantic raises this error in case of
                # failed platform check{s}
                exceptions.ValidationError)
            if logging.is_debug() and not isinstance(e, expected_errors):
                LOG.exception("Unexpected error had happened while validating "
                              "task.")
            raise
Пример #2
0
    def setup(self):
        """Create kuryr or non-kuryr docker network, and prepare image cache"""
        try:
            docker_client = docker.APIClient(base_url="tcp://0.0.0.0:2375")

            if self.config["is_kuryr"]:
                ipam = {
                    "Driver": "kuryr",
                    "Options": {},
                    "Config": [
                        {
                            "Subnet": self.config.get("Subnet"),
                            "IPRange": self.config.get("IPRange"),
                            "Gateway": self.config.get("Gateway")
                        }
                    ]
                }
                res = docker_client.create_network(name="kuryr_network",
                                                   driver="kuryr",
                                                   ipam=ipam)
                self.context["netid"] = res.get("Id")
                self.context["netname"] = "kuryr_network"
            else:
                res = docker_client.create_network(name="docker_network")
                self.context["netid"] = res.get("Id")
                self.context["netname"] = "docker_network"
            LOG.debug("Container network id is '%s'" % self.context["netid"])
        except Exception as e:
            msg = "Can't create docker network: %s" % e.message
            if logging.is_debug():
                LOG.exception(msg)
            else:
                LOG.warning(msg)
Пример #3
0
def import_modules_by_entry_point(_packages=None):
    """Import plugins by entry-point 'rally_plugins'."""
    loaded_packages = _packages or find_packages_by_entry_point()

    for package in loaded_packages:
        if "plugins_path" in package:
            em = pkg_resources.get_entry_map(package["name"])
            ep = em["rally_plugins"]["path"]
            try:
                m = ep.load()
                if hasattr(m, "__path__"):
                    path = pkgutil.extend_path(m.__path__, m.__name__)
                else:
                    path = [m.__file__]
                prefix = m.__name__ + "."
                for loader, name, _is_pkg in pkgutil.walk_packages(
                        path, prefix=prefix):
                    sys.modules[name] = importlib.import_module(name)
            except Exception as e:
                msg = ("\t Failed to load plugins from module '%(module)s' "
                       "(package: '%(package)s')" %
                       {"module": ep.module_name,
                        "package": "%s %s" % (package["name"],
                                              package["version"])})
                if logging.is_debug():
                    LOG.exception(msg)
                else:
                    LOG.warning(msg + (": %s" % six.text_type(e)))
    return loaded_packages
Пример #4
0
    def setup(self):
        """Create list of flavors."""
        from novaclient import exceptions as nova_exceptions

        self.context["flavors"] = {}

        clients = osclients.Clients(self.context["admin"]["credential"])
        for flavor_config in self.config:

            extra_specs = flavor_config.get("extra_specs")

            flavor_config = FlavorConfig(**flavor_config)
            try:
                flavor = clients.nova().flavors.create(**flavor_config)
            except nova_exceptions.Conflict:
                msg = "Using existing flavor %s" % flavor_config["name"]
                if logging.is_debug():
                    LOG.exception(msg)
                else:
                    LOG.warning(msg)
                continue

            if extra_specs:
                flavor.set_keys(extra_specs)

            self.context["flavors"][flavor_config["name"]] = flavor.to_dict()
            LOG.debug("Created flavor with id '%s'" % flavor.id)
Пример #5
0
def _run_scenario_once(cls, method_name, context_obj, scenario_kwargs):
    iteration = context_obj["iteration"]

    # provide arguments isolation between iterations
    scenario_kwargs = copy.deepcopy(scenario_kwargs)

    LOG.info("Task %(task)s | ITER: %(iteration)s START" %
             {"task": context_obj["task"]["uuid"], "iteration": iteration})

    scenario_inst = cls(context_obj)
    error = []
    try:
        with rutils.Timer() as timer:
            getattr(scenario_inst, method_name)(**scenario_kwargs)
    except Exception as e:
        error = utils.format_exc(e)
        if logging.is_debug():
            LOG.exception(e)
    finally:
        status = "Error %s: %s" % tuple(error[0:2]) if error else "OK"
        LOG.info("Task %(task)s | ITER: %(iteration)s END: %(status)s" %
                 {"task": context_obj["task"]["uuid"], "iteration": iteration,
                  "status": status})

        return {"duration": timer.duration() - scenario_inst.idle_duration(),
                "timestamp": timer.timestamp(),
                "idle_duration": scenario_inst.idle_duration(),
                "error": error,
                "output": scenario_inst._output,
                "atomic_actions": scenario_inst.atomic_actions()}
Пример #6
0
    def _delete_single_resource(self, resource):
        """Safe resource deletion with retries and timeouts.

        Send request to delete resource, in case of failures repeat it few
        times. After that pull status of resource until it's deleted.

        Writes in LOG warning with UUID of resource that wasn't deleted

        :param resource: instance of resource manager initiated with resource
                         that should be deleted.
        """

        msg_kw = {
            "uuid": resource.id(),
            "name": resource.name() or "",
            "service": resource._service,
            "resource": resource._resource,
        }

        LOG.debug("Deleting %(service)s %(resource)s object %(name)s (%(uuid)s)" % msg_kw)

        try:
            rutils.retry(resource._max_attempts, resource.delete)
        except Exception as e:
            msg_kw["reason"] = e
            LOG.warning(
                _(
                    "Resource deletion failed, max retries exceeded for "
                    "%(service)s.%(resource)s: %(uuid)s. Reason: %(reason)s"
                )
                % msg_kw
            )
            if logging.is_debug():
                LOG.exception(e)
        else:
            started = time.time()
            failures_count = 0
            while time.time() - started < resource._timeout:
                try:
                    if resource.is_deleted():
                        return
                except Exception as e:
                    LOG.warning(
                        _("Seems like %s.%s.is_deleted(self) method is broken " "It shouldn't raise any exceptions.")
                        % (resource.__module__, type(resource).__name__)
                    )
                    LOG.exception(e)

                    # NOTE(boris-42): Avoid LOG spamming in case of bad
                    #                 is_deleted() method
                    failures_count += 1
                    if failures_count > resource._max_attempts:
                        break

                finally:
                    time.sleep(resource._interval)

            LOG.warning(
                _("Resource deletion failed, timeout occurred for " "%(service)s.%(resource)s: %(uuid)s.") % msg_kw
            )
Пример #7
0
    def create(cls, config, name):
        """Create a deployment.

        :param config: a dict with deployment configuration
        :param name: a str represents a name of the deployment
        :returns: Deployment object
        """

        try:
            deployment = objects.Deployment(name=name, config=config)
        except exceptions.DeploymentNameExists as e:
            if logging.is_debug():
                LOG.exception(e)
            raise

        deployer = deploy_engine.Engine.get_engine(
            deployment["config"]["type"], deployment)
        try:
            deployer.validate()
        except jsonschema.ValidationError:
            LOG.error(_LE("Deployment %s: Schema validation error.") %
                      deployment["uuid"])
            deployment.update_status(consts.DeployStatus.DEPLOY_FAILED)
            raise

        with deployer:
            credentials = deployer.make_deploy()
            deployment.update_credentials(credentials)
            return deployment
Пример #8
0
    def _validate_config_semantic(self, config):
        LOG.info("Check health of the environment '%s'." % self.env.uuid)
        failed = []
        for p, res in self.env.check_health().items():
            LOG.info("Platform %s (available: %s): %s" %
                     (p, res["available"], res["message"]))
            if not res["available"]:
                failed.append(p)
                if logging.is_debug():
                    LOG.error(res["traceback"])
        if failed:
            raise exceptions.ValidationError(
                "One or several platforms are not available: %s. Check logs "
                "for more details." % ", ".join(failed))
        validation_ctx = self.env.get_validation_context()

        env_data = self.env.data
        env_data["platforms"] = dict(
            (p["platform_name"], p["platform_data"])
            for p in env_data["platforms"].values())

        ctx_obj = {"task": self.task,
                   "config": validation_ctx,
                   "env": env_data}

        with context.ContextManager(ctx_obj):
            for subtask in config.subtasks:
                for workload in subtask["workloads"]:
                    self._validate_workload(
                        workload, vcontext=ctx_obj, vtype="semantic")
Пример #9
0
def load_plugins(dir_or_file):
    if os.path.isdir(dir_or_file):
        directory = dir_or_file
        LOG.info(
            _("Loading plugins from directories %s/*") % directory.rstrip("/"))

        to_load = []
        for root, dirs, files in os.walk(directory, followlinks=True):
            to_load.extend((plugin[:-3], root) for plugin in files
                           if plugin.endswith(".py"))
        for plugin, directory in to_load:
            if directory not in sys.path:
                sys.path.append(directory)

            fullpath = os.path.join(directory, plugin)
            try:
                fp, pathname, descr = imp.find_module(plugin, [directory])
                imp.load_module(plugin, fp, pathname, descr)
                fp.close()
                LOG.info(_("\t Loaded module with plugins: %s.py") % fullpath)
            except Exception as e:
                LOG.warning(
                    "\t Failed to load module with plugins %(path)s.py: %(e)s"
                    % {
                        "path": fullpath,
                        "e": e
                    })
                if logging.is_debug():
                    LOG.exception(e)
    elif os.path.isfile(dir_or_file):
        plugin_file = dir_or_file
        LOG.info(_("Loading plugins from file %s") % plugin_file)
        if plugin_file not in sys.path:
            sys.path.append(plugin_file)
        try:
            plugin_name = os.path.splitext(plugin_file.split("/")[-1])[0]
            imp.load_source(plugin_name, plugin_file)
            LOG.info(_("\t Loaded module with plugins: %s.py") % plugin_name)
        except Exception as e:
            LOG.warning(
                _("\t Failed to load module with plugins %(path)s: %(e)s") % {
                    "path": plugin_file,
                    "e": e
                })
            if logging.is_debug():
                LOG.exception(e)
Пример #10
0
 def cleanup(self):
     """Clean up network"""
     try:
         self.docker_client.remove_network(self.context["netid"])
         LOG.debug("Docker network '%s' deleted" % self.context["netid"])
     except Exception as e:
         msg = "Can't delete docker network: %s" % e.message
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #11
0
 def cleanup(self):
     """This method is called after the task finishes"""
     try:
         nova = osclients.Clients(self.config["admin"]["credential"]).nova()
         nova.flavor.delete(self.context["flavor"]["id"])
         LOG.debug("Flavor '%s' deleted" % self.context["flavor"]["id"])
     except Exception as e:
         msg = "can't delete flavor: %s" % e.message
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #12
0
    def create_client(self, version=None, service_type=None):
        """Return cinder client."""
        from cinderclient import client as cinder

        client = cinder.Client(self.choose_version(version),
                               http_log_debug=logging.is_debug(),
                               timeout=CONF.openstack_client_http_timeout,
                               insecure=self.credential.insecure,
                               **self._get_auth_info(password_key="api_key"))
        kc = self.keystone()
        client.client.management_url = self._get_endpoint(service_type)
        client.client.auth_token = kc.auth_token
        return client
Пример #13
0
 def cleanup(self):
     """This method is called after the task finish."""
     try:
         nova = osclients.Clients(
             self.context["admin"]["credential"]).nova()
         nova.flavors.delete(self.context["flavor"]["id"])
         LOG.debug("Flavor '%s' deleted" % self.context["flavor"]["id"])
     except Exception as e:
         msg = "Can't delete flavor: %s" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #14
0
    def create_client(self, version=None, service_type=None):
        """Return cinder client."""
        from cinderclient import client as cinder

        client = cinder.Client(self.choose_version(version),
                               http_log_debug=logging.is_debug(),
                               timeout=CONF.openstack_client_http_timeout,
                               insecure=self.credential.insecure,
                               **self._get_auth_info(password_key="api_key"))
        kc = self.keystone()
        client.client.management_url = self._get_endpoint(service_type)
        client.client.auth_token = kc.auth_token
        return client
Пример #15
0
    def list_plugins(self, api, namespace=None):
        """List all plugins for verifiers management."""
        if namespace:
            namespace = namespace.lower()
        verifier_plugins = api.verifier.list_plugins(namespace)

        fields = ["Plugin name", "Namespace", "Description"]
        if logging.is_debug():
            fields.append("Location")

        cliutils.print_list(verifier_plugins, fields,
                            formatters={"Plugin name": lambda p: p["name"]},
                            normalize_field_names=True)
Пример #16
0
 def _create_member(self, body):
     try:
         members = {}
         members = self.clients("neutron").create_member(
             body)["member"]["id"]
         LOG.debug("Lbmember '%s' has create." % members)
     except Exception as e:
         msg = "Can't create Lbmember: %s" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
     return members
Пример #17
0
 def _create_l7_rule(self, body):
     try:
         l7rule = {}
         l7rule = self.clients("neutron").create_l7rule(
             body)["l7rule"]["id"]
         LOG.debug("L7rule '%s' has been created." % l7rule)
     except Exception as e:
         msg = "Can't create l7rule: '%s'" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
     return l7rule
Пример #18
0
 def _create_l7_policy(self, body):
     try:
         l7policies = {}
         l7policies = self.clients("neutron").create_l7policy(
             body)["l7policy"]["id"]
         LOG.debug("L7policy '%s' has been created." % l7policies)
     except Exception as e:
         msg = "Can't create l7policy: '%s'" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
     return l7policies
Пример #19
0
    def verify_connection(self):
        from keystoneclient import exceptions as keystone_exceptions

        try:
            if self.permission == consts.EndpointPermission.ADMIN:
                self.clients().verified_keystone()
            else:
                self.clients().keystone()
        except keystone_exceptions.ConnectionRefused as e:
            if logging.is_debug():
                LOG.exception(e)
            raise exceptions.RallyException("Unable to connect %s." %
                                            self.auth_url)
Пример #20
0
    def export(self, api, uuid, connection_string):
        """Export task results to the custom task's exporting system.

        :param uuid: UUID of the task
        :param connection_string: string used to connect to the system
        """

        parsed_obj = urlparse.urlparse(connection_string)
        try:
            client = exporter.Exporter.get(
                parsed_obj.scheme)(connection_string)
        except exceptions.InvalidConnectionString as e:
            if logging.is_debug():
                LOG.exception(e)
            print(e)
            return 1
        except exceptions.PluginNotFound as e:
            if logging.is_debug():
                LOG.exception(e)
            msg = ("\nPlease check your connection string. The format of "
                   "`connection` should be plugin-name://"
                   "<user>:<pwd>@<full_address>:<port>/<path>.<type>")
            print(str(e) + msg)
            return 1

        try:
            client.export(uuid)
        except (IOError, exceptions.RallyException) as e:
            if logging.is_debug():
                LOG.exception(e)
            print(e)
            return 1
        print(
            _("Task %(uuid)s results was successfully exported to %("
              "connection)s using %(name)s plugin.") % {
                  "uuid": uuid,
                  "connection": connection_string,
                  "name": parsed_obj.scheme
              })
 def cleanup(self):
     try:
         if self.net_wrapper.SERVICE_IMPL == consts.Service.NEUTRON:
             for user, tenant_id in rutils.iterate_per_tenants(
                     self.context["users"]):
                 network = self.context["tenants"][tenant_id]["network"]
                 self.net_wrapper.delete_network(network)
     except Exception as e:
         msg = "Can't cleanup ec2 client: %s" % e.message
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #22
0
    def list_verifier_exts(self, api, verifier_id=None):
        """List all verifier extensions."""

        verifier_exts = api.verifier.list_extensions(verifier_id=verifier_id)
        if verifier_exts:
            fields = ["Name", "Entry point"]
            if logging.is_debug():
                fields.append("Location")
            cliutils.print_list(verifier_exts, fields,
                                normalize_field_names=True)
        else:
            print("There are no verifier extensions. You can add verifier "
                  "extension, using command `rally verify add-verifier-ext`.")
Пример #23
0
    def export(self, uuid, connection_string):
        """Export task results to the custom task's exporting system.

        :param uuid: UUID of the task
        :param connection_string: string used to connect to the system
        """

        parsed_obj = urlparse.urlparse(connection_string)
        try:
            client = exporter.TaskExporter.get(parsed_obj.scheme)(
                connection_string)
        except exceptions.InvalidConnectionString as e:
            if logging.is_debug():
                LOG.exception(e)
            print (e)
            return 1
        except exceptions.PluginNotFound as e:
            if logging.is_debug():
                LOG.exception(e)
            msg = ("\nPlease check your connection string. The format of "
                   "`connection` should be plugin-name://"
                   "<user>:<pwd>@<full_address>:<port>/<path>.<type>")
            print (str(e) + msg)
            return 1

        try:
            client.export(uuid)
        except (IOError, exceptions.RallyException) as e:
            if logging.is_debug():
                LOG.exception(e)
            print (e)
            return 1
        print(_("Task %(uuid)s results was successfully exported to %("
                "connection)s using %(name)s plugin.") % {
                    "uuid": uuid,
                    "connection": connection_string,
                    "name": parsed_obj.scheme
        })
Пример #24
0
 def cleanup(self):
     """This method is called after the task finish."""
     try:
         trove = osclients.Clients(
             self.context["admin"]["credential"]).trove()
         trove.instances.delete(self.context["instance"]["id"])
         LOG.debug("Instance %s deleted request is sent"
                   % self.context["instance"]["name"])
     except Exception as e:
         msg = "Can't delete context instance: %s" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #25
0
    def list_plugins(self, api, platform=None):
        """List all plugins for verifiers management."""

        if platform:
            platform = platform.lower()
        verifier_plugins = api.verifier.list_plugins(platform=platform)

        fields = ["Plugin name", "Platform", "Description"]
        if logging.is_debug():
            fields.append("Location")

        cliutils.print_list(verifier_plugins, fields,
                            formatters={"Plugin name": lambda p: p["name"]},
                            normalize_field_names=True)
Пример #26
0
def _run_scenario_once(args):
    iteration, cls, method_name, context_obj, kwargs = args

    LOG.info("Task %(task)s | ITER: %(iteration)s START" %
             {"task": context_obj["task"]["uuid"], "iteration": iteration})

    context_obj["iteration"] = iteration
    scenario_inst = cls(context_obj)

    error = []
    output = {"additive": [], "complete": []}
    try:
        with rutils.Timer() as timer:
            # NOTE(amaretskiy): Output as return value is deprecated
            #     but supported for backward compatibility
            deprecated_output = getattr(scenario_inst, method_name)(**kwargs)
            warning = ""
            if deprecated_output:
                warning = ("Returning output data by scenario is deprecated "
                           "in favor of calling add_output().")
            if scenario_inst._output != {"complete": [], "additive": []}:
                output = scenario_inst._output
                if deprecated_output:
                    warning += (" Output data both returned and passed to "
                                "add_output() so returned one is ignored!")
            elif deprecated_output:
                output["additive"].append({
                    "title": "Scenario output",
                    "description": "",
                    "chart_plugin": "StackedArea",
                    "data": [list(item)
                             for item in deprecated_output["data"].items()]})
            if warning:
                LOG.warning(warning)
    except Exception as e:
        error = utils.format_exc(e)
        if logging.is_debug():
            LOG.exception(e)
    finally:
        status = "Error %s: %s" % tuple(error[0:2]) if error else "OK"
        LOG.info("Task %(task)s | ITER: %(iteration)s END: %(status)s" %
                 {"task": context_obj["task"]["uuid"], "iteration": iteration,
                  "status": status})

        return {"duration": timer.duration() - scenario_inst.idle_duration(),
                "timestamp": timer.timestamp(),
                "idle_duration": scenario_inst.idle_duration(),
                "error": error,
                "output": output,
                "atomic_actions": scenario_inst.atomic_actions()}
Пример #27
0
 def create_client(self, version=None, service_type=None):
     """Return manila client."""
     from manilaclient import client as manila
     manila_client = manila.Client(
         self.choose_version(version),
         region_name=self.credential.region_name,
         http_log_debug=logging.is_debug(),
         timeout=CONF.openstack_client_http_timeout,
         insecure=self.credential.insecure,
         **self._get_auth_info(password_key="api_key",
                               project_name_key="project_name"))
     manila_client.client.management_url = self._get_endpoint(service_type)
     manila_client.client.auth_token = self.keystone.auth_ref.auth_token
     return manila_client
Пример #28
0
        def _admin_cleanup():
            try:
                neutron = osclients.Clients(
                    self.context["admin"]["credential"]).neutron()

                neutron.delete_subnet(self.context["admin_subnet"])
                LOG.debug("Admin Subnet '%s' deleted" %
                          self.context["admin_subnet"])
            except Exception as e:
                msg = "Can't delete subnet: %s" % e
                if logging.is_debug():
                    LOG.exception(msg)
                else:
                    LOG.warning(msg)
Пример #29
0
def _publisher(publish, queue):
    """Calls a publish method that fills queue with jobs.

    :param publish: method that fills the queue
    :param queue: deque object to be filled by the publish() method
    """
    try:
        publish(queue)
    except Exception as e:
        msg = "Failed to publish a task to the queue"
        if logging.is_debug():
            LOG.exception(msg)
        else:
            LOG.warning("%s: %s" % (msg, e))
Пример #30
0
def import_modules_by_entry_point():
    """Import plugins by entry-point 'rally_plugins'."""
    loaded_packages = []

    for package in pkg_resources.working_set:
        entry_map = package.get_entry_map("rally_plugins")
        if not entry_map:
            # this package doesn't have rally_plugins entry-point
            continue

        package_info = {}

        if "path" in entry_map:
            ep = entry_map["path"]
            try:
                m = ep.load()
                if hasattr(m, "__path__"):
                    path = pkgutil.extend_path(m.__path__, m.__name__)
                else:
                    path = [m.__file__]
                prefix = m.__name__ + "."
                for loader, name, _is_pkg in pkgutil.walk_packages(
                        path, prefix=prefix):
                    sys.modules[name] = importlib.import_module(name)
            except Exception as e:
                msg = ("\t Failed to load plugins from module '%(module)s' "
                       "(package: '%(package)s')" %
                       {"module": ep.module_name,
                        "package": "%s %s" % (package.project_name,
                                              package.version)})
                if logging.is_debug():
                    LOG.exception(msg)
                else:
                    LOG.warning(msg + (": %s" % six.text_type(e)))
            else:
                package_info["plugins_path"] = ep.module_name
        if "options" in entry_map:
            ep = entry_map["options"]
            package_info["options"] = "%s:%s" % (
                ep.module_name,
                ep.attrs[0] if ep.attrs else "list_opts",
            )

        if package_info:
            package_info.update(
                name=package.project_name,
                version=package.version)
            loaded_packages.append(package_info)
    return loaded_packages
Пример #31
0
 def _admin_setup():
     try:
         neutron = osclients.Clients(
             self.context["admin"]["credential"]).neutron()
         body = {"network": dict(name=self.config.get("name"))}
         self.context["admin_network"] = neutron.create_network(
             body=body)["network"]["id"]
         LOG.debug("Admin Network with id '%s'" %
                   self.context["admin_network"])
     except Exception as e:
         msg = "Can't create network: %s" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #32
0
 def create_client(self, version=None, service_type=None):
     """Return manila client."""
     from manilaclient import client as manila
     manila_client = manila.Client(
         self.choose_version(version),
         region_name=self.credential.region_name,
         http_log_debug=logging.is_debug(),
         timeout=CONF.openstack_client_http_timeout,
         insecure=self.credential.insecure,
         **self._get_auth_info(password_key="api_key",
                               project_name_key="project_name"))
     kc = self.keystone()
     manila_client.client.management_url = self._get_endpoint(service_type)
     manila_client.client.auth_token = kc.auth_token
     return manila_client
Пример #33
0
 def create_client(self, version=None, service_type=None):
     """Return nova client."""
     from novaclient import client as nova
     kc = self.keystone()
     compute_api_url = kc.service_catalog.url_for(
         service_type=self.choose_service_type(service_type),
         endpoint_type=self.credential.endpoint_type,
         region_name=self.credential.region_name)
     client = nova.Client(self.choose_version(version),
                          auth_token=kc.auth_token,
                          http_log_debug=logging.is_debug(),
                          timeout=CONF.openstack_client_http_timeout,
                          insecure=self.credential.insecure,
                          **self._get_auth_info(password_key="api_key"))
     client.set_management_url(compute_api_url)
     return client
Пример #34
0
 def cleanup(self):
     try:
         manager = osclients.Clients(self.context['users'][0]['credential']).nova().servers
         server = manager.get(self.context['server']['id'])
         server.force_delete()
         try:
             utils.wait_for_delete(server, manager.get)
         except BaseException:
             pass
         LOG.debug("Server '%s' deleted" % self.context["server"]["id"])
     except Exception as e:
         msg = "Can't delete server: %s" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #35
0
 def create_client(self, version=None, service_type=None):
     """Return nova client."""
     from novaclient import client as nova
     kc = self.keystone()
     compute_api_url = kc.service_catalog.url_for(
         service_type=self.choose_service_type(service_type),
         endpoint_type=self.credential.endpoint_type,
         region_name=self.credential.region_name)
     client = nova.Client(self.choose_version(version),
                          auth_token=kc.auth_token,
                          http_log_debug=logging.is_debug(),
                          timeout=CONF.openstack_client_http_timeout,
                          insecure=self.credential.insecure,
                          **self._get_auth_info(password_key="api_key"))
     client.set_management_url(compute_api_url)
     return client
Пример #36
0
 def setup(self):
     try:
         neutron = osclients.Clients(self.context['users'][0]['credential']).neutron()
         body = {
             "floatingip": {
                 "floating_network_id": self.config['external_net']
             }
         }
         floating_ip = neutron.create_floatingip(body)['floatingip']
         self.context['floatingip'] = floating_ip
         LOG.debug("FloatingIP with id '%s'" % floating_ip['id'])
     except Exception as e:
         msg = "Can't create server: %s" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #37
0
 def create_client(self, version=None, service_type=None):
     """Return cinder client."""
     from cinderclient import client as cinder
     client = cinder.Client(self.choose_version(version),
                            http_log_debug=logging.is_debug(),
                            timeout=CONF.openstack_client_http_timeout,
                            insecure=self.credential.insecure,
                            cacert=self.credential.cacert,
                            **self._get_auth_info(password_key="api_key"))
     kc = self.keystone()
     volume_api_url = kc.service_catalog.url_for(
         service_type=self.choose_service_type(service_type),
         endpoint_type=self.credential.endpoint_type,
         region_name=self.credential.region_name)
     client.client.management_url = volume_api_url
     client.client.auth_token = kc.auth_token
     return client
Пример #38
0
    def _fetch_osprofiler_data(cls, connection_str, trace_id):
        from osprofiler.drivers import base
        from osprofiler import opts as osprofiler_opts

        opts.register_opts(osprofiler_opts.list_opts())

        try:
            engine = base.get_driver(connection_str)
        except Exception:
            msg = "Error while fetching OSProfiler results."
            if logging.is_debug():
                LOG.exception(msg)
            else:
                LOG.error(msg)
            return None

        return engine.get_report(trace_id)
Пример #39
0
 def create_client(self, version=None, service_type=None):
     """Return cinder client."""
     from cinderclient import client as cinder
     client = cinder.Client(self.choose_version(version),
                            http_log_debug=logging.is_debug(),
                            timeout=CONF.openstack_client_http_timeout,
                            insecure=self.credential.insecure,
                            cacert=self.credential.cacert,
                            **self._get_auth_info(password_key="api_key"))
     kc = self.keystone()
     volume_api_url = kc.service_catalog.url_for(
         service_type=self.choose_service_type(service_type),
         endpoint_type=self.credential.endpoint_type,
         region_name=self.credential.region_name)
     client.client.management_url = volume_api_url
     client.client.auth_token = kc.auth_token
     return client
Пример #40
0
    def get_osprofiler_data(cls, data):

        from osprofiler import cmd
        from osprofiler.drivers import base
        from osprofiler import opts as osprofiler_opts

        opts.register_opts(osprofiler_opts.list_opts())

        try:
            engine = base.get_driver(data["data"]["conn_str"])
        except Exception:
            msg = "Error while fetching OSProfiler results."
            if logging.is_debug():
                LOG.exception(msg)
            else:
                LOG.error(msg)
            return None

        data["widget"] = "EmbedChart"
        data["title"] = "{0} : {1}".format(data["title"],
                                           data["data"]["trace_id"][0])

        path = "%s/template.html" % os.path.dirname(cmd.__file__)
        with open(path) as f:
            html_obj = f.read()

        osp_data = engine.get_report(data["data"]["trace_id"][0])
        osp_data = json.dumps(osp_data,
                              indent=4,
                              separators=(",", ": "),
                              default=_datetime_json_serialize)
        data["data"] = html_obj.replace("$DATA", osp_data)
        data["data"] = data["data"].replace("$LOCAL", "false")

        # NOTE(chenxu): self._data will be passed to
        # ["complete_output"]["data"] as a whole string and
        # tag </script> will be parsed incorrectly in javascript string
        # so we turn it to <\/script> and turn it back in javascript.
        data["data"] = data["data"].replace("/script>", "\/script>")

        return {
            "title": data["title"],
            "widget": data["widget"],
            "data": data["data"]
        }
Пример #41
0
 def _create_pool(self, body):
     try:
         #body = {
         #    "pool": {
         #        "name": "rally_pool"
         #        "subnet_id": self.context.["user_subnet"]
         #    }
         #}
         pools = {}
         pools = self.clients("neutron").create_pool(body)["pool"]["id"]
         LOG.debug("LbPool '%s' has create." % pools)
     except Exception as e:
         msg = "Can't create pool: %s" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
     return pools
Пример #42
0
 def setup(self):
     client = client_heketi.HeketiClient(
         host=self.config.get("server"),
         user=self.config.get("username"),
         key=self.config.get("secret"),
     )
     try:
         if client.hello():
             self.context["heketi_client"] = client
             LOG.debug("Successfully connected to the Heketi server.")
             return
         msg = "Failed to connect to the Heketi server."
     except Exception as e:
         msg = "Can't connect to the Heketi server: %s" % e.message
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
     raise exceptions.ContextSetupFailure(ctx_name=CONTEXT_NAME, msg=msg)
Пример #43
0
 def auth_ref(self):
     try:
         if "keystone_auth_ref" not in self.cache:
             sess, plugin = self.get_session()
             self.cache["keystone_auth_ref"] = plugin.get_access(sess)
     except Exception as e:
         if logging.is_debug():
             LOG.exception("Unable to authenticate for user"
                           " %(username)s in project"
                           " %(tenant_name)s" %
                           {"username": self.credential.username,
                            "tenant_name": self.credential.tenant_name})
         raise exceptions.AuthenticationFailed(
             username=self.credential.username,
             project=self.credential.tenant_name,
             url=self.credential.auth_url,
             etype=e.__class__.__name__,
             error=str(e))
     return self.cache["keystone_auth_ref"]
Пример #44
0
def _run_scenario_once(cls, method_name, context_obj, scenario_kwargs,
                       event_queue):
    iteration = context_obj["iteration"]
    event_queue.put({
        "type": "iteration",
        "value": iteration,
    })

    # provide arguments isolation between iterations
    scenario_kwargs = copy.deepcopy(scenario_kwargs)

    LOG.info("Task %(task)s | ITER: %(iteration)s START" % {
        "task": context_obj["task"]["uuid"],
        "iteration": iteration
    })

    scenario_inst = cls(context_obj)
    error = []
    try:
        with rutils.Timer() as timer:
            getattr(scenario_inst, method_name)(**scenario_kwargs)
    except Exception as e:
        error = utils.format_exc(e)
        if logging.is_debug():
            LOG.exception("Iteration %s raised Exception" % iteration)
    finally:
        status = "Error %s: %s" % tuple(error[0:2]) if error else "OK"
        LOG.info(
            "Task %(task)s | ITER: %(iteration)s END: %(status)s" % {
                "task": context_obj["task"]["uuid"],
                "iteration": iteration,
                "status": status
            })

        return {
            "duration": timer.duration() - scenario_inst.idle_duration(),
            "timestamp": timer.timestamp(),
            "idle_duration": scenario_inst.idle_duration(),
            "error": error,
            "output": scenario_inst._output,
            "atomic_actions": scenario_inst.atomic_actions()
        }
Пример #45
0
 def setup(self):
     """This method is called before the task start."""
     try:
         # use rally.osclients to get necessary client instance
         nova = osclients.Clients(
             self.context["admin"]["credential"]).nova()
         # and then do what you need with this client
         self.context["flavor"] = nova.flavors.create(
             # context settings are stored in self.config
             name=self.config.get("flavor_name", "rally_test_flavor"),
             ram=self.config.get("ram", 1),
             vcpus=self.config.get("vcpus", 1),
             disk=self.config.get("disk", 1)).to_dict()
         LOG.debug("Flavor with id '%s'" % self.context["flavor"]["id"])
     except Exception as e:
         msg = "Can't create flavor: %s" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #46
0
 def setup(self):
     """This method is called before the task start."""
     try:
         # use rally.osclients to get necessary client instance
         nova = osclients.Clients(
             self.context["admin"]["credential"]).nova()
         # and then do what you need with this client
         self.context["flavor"] = nova.flavors.create(
             # context settings are stored in self.config
             name=self.config.get("flavor_name", "rally_test_flavor"),
             ram=self.config.get("ram", 1),
             vcpus=self.config.get("vcpus", 1),
             disk=self.config.get("disk", 1)).to_dict()
         LOG.debug("Flavor with id '%s'", self.context["flavor"]["id"])
     except Exception as e:
         msg = "Can't create flavor: %s" % e
         if logging.is_debug():
             LOG.exception(msg)
         else:
             LOG.warning(msg)
Пример #47
0
    def validate(self, only_syntax=False):
        """Perform full task configuration validation.

        :param only_syntax: Check only syntax of task configuration
        """
        self.task.update_status(consts.TaskStatus.VALIDATING)
        try:
            self._validate_config_syntax(self.config)
            if only_syntax:
                return
            self._validate_config_platforms(self.config)
            self._validate_config_semantic(self.config)
        except Exception as e:
            exception_info = json.dumps(traceback.format_exc(), indent=2,
                                        separators=(",", ": "))
            self.task.set_failed(type(e).__name__, str(e), exception_info)
            if (logging.is_debug() and
                    not isinstance(e, exceptions.InvalidTaskConfig)):
                LOG.exception("Invalid Task")
            raise exceptions.InvalidTaskException(str(e))
Пример #48
0
        def _print_task_info(task):
            print()
            print("-" * 80)
            print(_("Task %(task_id)s: %(status)s")
                  % {"task_id": task_id, "status": task["status"]})

            if task["status"] == consts.TaskStatus.FAILED:
                print("-" * 80)
                verification = yaml.safe_load(task["verification_log"])

                if not logging.is_debug():
                    print(verification[0])
                    print(verification[1])
                    print()
                    print(_("For more details run:\n"
                            "rally -vd task detailed %s")
                          % task["uuid"])
                else:
                    print(yaml.safe_load(verification[2]))
                return False
            return True
Пример #49
0
    def _clone(self):
        """Clone a repo and switch to a certain version."""
        source = self.verifier.source or self._meta_get("default_repo")
        if not source or (
                not URL_RE.match(source) and not os.path.exists(source)):
            raise exceptions.RallyException("Source path '%s' is not valid."
                                            % source)

        if logging.is_debug():
            LOG.debug("Cloning verifier repo from %s into %s."
                      % (source, self.repo_dir))
        else:
            LOG.info("Cloning verifier repo from %s." % source)

        cmd = ["git", "clone", source, self.repo_dir]

        default_version = self._meta_get("default_version")
        if default_version and default_version != "master":
            cmd.extend(["-b", default_version])

        utils.check_output(cmd)

        version = self.verifier.version
        if version:
            LOG.info("Switching verifier repo to the '%s' version." % version)
            utils.check_output(["git", "checkout", version], cwd=self.repo_dir)
        else:
            output = utils.check_output(["git", "describe", "--all"],
                                        cwd=self.repo_dir).strip()
            if output.startswith("heads/"):  # it is a branch
                version = output[6:]
            else:
                head = utils.check_output(["git", "rev-parse", "HEAD"],
                                          cwd=self.repo_dir).strip()
                if output.endswith(head[:7]):  # it is a commit ID
                    version = head
                else:  # it is a tag
                    version = output

            self.verifier.update_properties(version=version)
Пример #50
0
    def get_osprofiler_data(cls, data):

        from osprofiler import cmd
        from osprofiler.drivers import base

        try:
            engine = base.get_driver(data["data"]["conn_str"])
        except Exception:
            if logging.is_debug():
                LOG.exception("Error while fetching OSProfiler results.")
            return None

        data["widget"] = "EmbedChart"
        data["title"] = "{0} : {1}".format(data["title"],
                                           data["data"]["trace_id"][0])

        path = "%s/template.html" % os.path.dirname(cmd.__file__)
        with open(path) as f:
            html_obj = f.read()

        osp_data = engine.get_report(data["data"]["trace_id"][0])
        osp_data = json.dumps(osp_data,
                              indent=4,
                              separators=(",", ": "),
                              default=_datetime_json_serialize)
        data["data"] = html_obj.replace("$DATA", osp_data)
        data["data"] = data["data"].replace("$LOCAL", "false")

        # NOTE(chenxu): self._data will be passed to
        # ["complete_output"]["data"] as a whole string and
        # tag </script> will be parsed incorrectly in javascript string
        # so we turn it to <\/script> and turn it back in javascript.
        data["data"] = data["data"].replace("/script>", "\/script>")

        return {"title": data["title"],
                "widget": data["widget"],
                "data": data["data"]}
Пример #51
0
def import_modules_by_entry_point():
    """Import plugins by entry-point 'rally_plugins'."""
    for ep in pkg_resources.iter_entry_points("rally_plugins"):
        if ep.name == "path":
            try:
                m = ep.load()
                if hasattr(m, "__path__"):
                    path = pkgutil.extend_path(m.__path__, m.__name__)
                else:
                    path = [m.__file__]
                prefix = m.__name__ + "."
                for loader, name, _is_pkg in pkgutil.walk_packages(
                        path, prefix=prefix):
                    sys.modules[name] = importlib.import_module(name)
            except Exception as e:
                msg = ("\t Failed to load plugins from module '%(module)s' "
                       "(package: '%(package)s')" %
                       {"module": ep.module_name,
                        "package": "%s %s" % (ep.dist.project_name,
                                              ep.dist.version)})
                if logging.is_debug():
                    LOG.exception(msg)
                else:
                    LOG.warning(msg + (": %s" % six.text_type(e)))
Пример #52
0
def _consumer(consume, queue):
    """Infinity worker that consumes tasks from queue.

    :param consume: method that consumes an object removed from the queue
    :param queue: deque object to popleft() objects from
    """
    cache = {}
    while True:
        if not queue:
            break
        else:
            try:
                args = queue.popleft()
            except IndexError:
                # consumed by other thread
                continue
        try:
            consume(cache, args)
        except Exception as e:
            msg = "Failed to consume a task from the queue"
            if logging.is_debug():
                LOG.exception(msg)
            else:
                LOG.warning("%s: %s" % (msg, e))
Пример #53
0
def run(argv, categories):
    parser = lambda subparsers: _add_command_parsers(categories, subparsers)
    category_opt = cfg.SubCommandOpt("category",
                                     title="Command categories",
                                     help="Available categories",
                                     handler=parser)

    CONF.register_cli_opt(category_opt)
    help_msg = ("Additional custom plugin locations. Multiple files or "
                "directories may be specified. All plugins in the specified"
                " directories and subdirectories will be imported. Plugins in"
                " /opt/rally/plugins and ~/.rally/plugins will always be "
                "imported.")

    CONF.register_cli_opt(cfg.ListOpt("plugin-paths",
                                      default=os.environ.get(
                                          "RALLY_PLUGIN_PATHS"),
                                      help=help_msg))

    try:
        CONF(argv[1:], project="rally", version=version.version_string(),
             default_config_files=find_config_files(CONFIG_SEARCH_PATHS))
        logging.setup("rally")
        if not CONF.get("log_config_append"):
            # The below two lines are to disable noise from request module. The
            # standard way should be we make such lots of settings on the root
            # rally. However current oslo codes doesn't support such interface.
            # So I choose to use a 'hacking' way to avoid INFO logs from
            # request module where user didn't give specific log configuration.
            # And we could remove this hacking after oslo.log has such
            # interface.
            LOG.debug("INFO logs from urllib3 and requests module are hide.")
            requests_log = logging.getLogger("requests").logger
            requests_log.setLevel(logging.WARNING)
            urllib3_log = logging.getLogger("urllib3").logger
            urllib3_log.setLevel(logging.WARNING)

            # NOTE(wtakase): This is for suppressing boto error logging.
            LOG.debug("ERROR log from boto module is hide.")
            boto_log = logging.getLogger("boto").logger
            boto_log.setLevel(logging.CRITICAL)

    except cfg.ConfigFilesNotFoundError:
        cfgfile = CONF.config_file[-1] if CONF.config_file else None
        if cfgfile and not os.access(cfgfile, os.R_OK):
            st = os.stat(cfgfile)
            print(_("Could not read %s. Re-running with sudo") % cfgfile)
            try:
                os.execvp("sudo", ["sudo", "-u", "#%s" % st.st_uid] + sys.argv)
            except Exception:
                print(_("sudo failed, continuing as if nothing happened"))

        print(_("Please re-run %s as root.") % argv[0])
        return(2)

    if CONF.category.name == "version":
        print(version.version_string())
        return(0)

    if CONF.category.name == "bash-completion":
        print(_generate_bash_completion_script())
        return(0)

    fn = CONF.category.action_fn
    fn_args = [encodeutils.safe_decode(arg)
               for arg in CONF.category.action_args]
    fn_kwargs = {}
    for k in CONF.category.action_kwargs:
        v = getattr(CONF.category, "action_kwarg_" + k)
        if v is None:
            continue
        if isinstance(v, six.string_types):
            v = encodeutils.safe_decode(v)
        fn_kwargs[k] = v

    # call the action with the remaining arguments
    # check arguments
    try:
        validate_args(fn, *fn_args, **fn_kwargs)
    except MissingArgs as e:
        # NOTE(mikal): this isn't the most helpful error message ever. It is
        # long, and tells you a lot of things you probably don't want to know
        # if you just got a single arg wrong.
        print(fn.__doc__)
        CONF.print_help()
        print("Missing arguments:")
        for missing in e.missing:
            for arg in fn.args:
                if arg[1].get("dest", "").endswith(missing):
                    print(" " + arg[0][0])
                    break
        return(1)

    try:
        for path in CONF.plugin_paths or []:
            discover.load_plugins(path)

        validate_deprecated_args(argv, fn)

        if getattr(fn, "_suppress_warnings", False):
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")
                ret = fn(*fn_args, **fn_kwargs)
        else:
            ret = fn(*fn_args, **fn_kwargs)
        return(ret)

    except (IOError, TypeError, ValueError, exceptions.DeploymentNotFound,
            exceptions.TaskNotFound, jsonschema.ValidationError) as e:
        if logging.is_debug():
            LOG.exception(e)
        print(e)
        return 1
    except sqlalchemy.exc.OperationalError as e:
        if logging.is_debug():
            LOG.exception(e)
        print(e)
        print("Looks like Rally can't connect to its DB.")
        print("Make a sure that connection string in rally.conf is proper:")
        print(CONF.database.connection)
        return 1
    except Exception:
        print(_("Command failed, please check log for more info"))
        raise
Пример #54
0
    def detailed(self, task_id=None, iterations_data=False):
        """Print detailed information about given task.

        :param task_id: str, task uuid
        :param iterations_data: bool, include results for each iteration
        """
        task = api.Task.get_detailed(task_id, extended_results=True)

        if not task:
            print("The task %s can not be found" % task_id)
            return 1

        print()
        print("-" * 80)
        print(_("Task %(task_id)s: %(status)s")
              % {"task_id": task_id, "status": task["status"]})

        if task["status"] == consts.TaskStatus.FAILED:
            print("-" * 80)
            verification = yaml.safe_load(task["verification_log"])
            if logging.is_debug():
                print(yaml.safe_load(verification[2]))
            else:
                print(verification[0])
                print(verification[1])
                print(_("\nFor more details run:\nrally -vd task detailed %s")
                      % task["uuid"])
            return 0
        elif task["status"] not in [consts.TaskStatus.FINISHED,
                                    consts.TaskStatus.ABORTED]:
            print("-" * 80)
            print(_("\nThe task %s marked as '%s'. Results "
                    "available when it is '%s'.") % (
                task_id, task["status"], consts.TaskStatus.FINISHED))
            return 0
        for result in task["results"]:
            key = result["key"]
            print("-" * 80)
            print()
            print("test scenario %s" % key["name"])
            print("args position %s" % key["pos"])
            print("args values:")
            print(json.dumps(key["kw"], indent=2))
            print()

            iterations = []
            iterations_headers = ["iteration", "full duration"]
            iterations_actions = []
            output = []
            task_errors = []
            if iterations_data:
                for i, atomic_name in enumerate(result["info"]["atomic"], 1):
                    action = "%i. %s" % (i, atomic_name)
                    iterations_headers.append(action)
                    iterations_actions.append((atomic_name, action))

            for idx, itr in enumerate(result["iterations"], 1):

                if iterations_data:
                    row = {"iteration": idx,
                           "full duration": itr["duration"]}
                    for name, action in iterations_actions:
                        row[action] = itr["atomic_actions"].get(name, 0)
                    iterations.append(row)

                if "output" in itr:
                    iteration_output = itr["output"]
                else:
                    iteration_output = {"additive": [], "complete": []}

                    # NOTE(amaretskiy): "scenario_output" is supported
                    #   for backward compatibility
                    if ("scenario_output" in itr
                            and itr["scenario_output"]["data"]):
                        iteration_output["additive"].append(
                            {"data": itr["scenario_output"]["data"].items(),
                             "title": "Scenario output",
                             "description": "",
                             "chart_plugin": "StackedArea"})

                for idx, additive in enumerate(iteration_output["additive"]):
                    if len(output) <= idx + 1:
                        output_table = plot.charts.OutputStatsTable(
                            result["info"], title=additive["title"])
                        output.append(output_table)
                    output[idx].add_iteration(additive["data"])

                if itr.get("error"):
                    task_errors.append(TaskCommands._format_task_error(itr))

            self._print_task_errors(task_id, task_errors)

            cols = plot.charts.MainStatsTable.columns
            float_cols = result["info"]["stat"]["cols"][1:7]
            formatters = dict(zip(float_cols,
                                  [cliutils.pretty_float_formatter(col, 3)
                                   for col in float_cols]))
            rows = [dict(zip(cols, r)) for r in result["info"]["stat"]["rows"]]
            cliutils.print_list(rows,
                                fields=cols,
                                formatters=formatters,
                                table_label="Response Times (sec)",
                                sortby_index=None)
            print()

            if iterations_data:
                formatters = dict(zip(iterations_headers[1:],
                                      [cliutils.pretty_float_formatter(col, 3)
                                       for col in iterations_headers[1:]]))
                cliutils.print_list(iterations,
                                    fields=iterations_headers,
                                    table_label="Atomics per iteration",
                                    formatters=formatters)
                print()

            if output:
                cols = plot.charts.OutputStatsTable.columns
                float_cols = cols[1:7]
                formatters = dict(zip(float_cols,
                                  [cliutils.pretty_float_formatter(col, 3)
                                   for col in float_cols]))

                for out in output:
                    data = out.render()
                    rows = [dict(zip(cols, r)) for r in data["data"]["rows"]]
                    if rows:
                        # NOTE(amaretskiy): print title explicitly because
                        #     prettytable fails if title length is too long
                        print(data["title"])
                        cliutils.print_list(rows, fields=cols,
                                            formatters=formatters)
                        print()

            print(_("Load duration: %s") %
                  result["info"]["load_duration"])
            print(_("Full duration: %s") %
                  result["info"]["full_duration"])

            print("\nHINTS:")
            print(_("* To plot HTML graphics with this data, run:"))
            print("\trally task report %s --out output.html\n" % task["uuid"])
            print(_("* To generate a JUnit report, run:"))
            print("\trally task report %s --junit --out output.xml\n" %
                  task["uuid"])
            print(_("* To get raw JSON output of task results, run:"))
            print("\trally task results %s\n" % task["uuid"])