Merge "Fix several issues with plugin discovery error messages"

This commit is contained in:
Zuul 2020-02-14 16:16:24 +00:00 committed by Gerrit Code Review
commit d69025e23b
17 changed files with 79 additions and 45 deletions

View File

@ -25,6 +25,11 @@ Removed
* Python 2.7, Python 3.4 and Python 3.5 support * Python 2.7, Python 3.4 and Python 3.5 support
Changed
~~~~~~~
* *rally plugin show* command returns not-zero exit code in case of not found
or multiple match errors
[2.1.0] - 2019-11-19 [2.1.0] - 2019-11-19
-------------------- --------------------

View File

@ -675,7 +675,8 @@ def run(argv, categories):
except (IOError, TypeError, ValueError, except (IOError, TypeError, ValueError,
exceptions.RallyException, jsonschema.ValidationError) as e: exceptions.RallyException, jsonschema.ValidationError) as e:
if logging.is_debug(): known_errors = (exceptions.InvalidTaskConfig,)
if logging.is_debug() and not isinstance(e, known_errors):
LOG.exception("Unexpected exception in CLI") LOG.exception("Unexpected exception in CLI")
else: else:
print(e) print(e)

View File

@ -18,6 +18,7 @@ from __future__ import print_function
from rally.cli import cliutils from rally.cli import cliutils
from rally.common.plugin import plugin from rally.common.plugin import plugin
from rally.common import utils from rally.common import utils
from rally import exceptions
from rally import plugins from rally import plugins
@ -58,6 +59,7 @@ class PluginCommands(object):
) )
else: else:
print("Plugin %s not found at any platform" % name) print("Plugin %s not found at any platform" % name)
return exceptions.PluginNotFound.error_code
elif len(found) == 1 or exact_match: elif len(found) == 1 or exact_match:
plugin_ = found[0] if len(found) == 1 else exact_match[0] plugin_ = found[0] if len(found) == 1 else exact_match[0]
@ -79,6 +81,7 @@ class PluginCommands(object):
else: else:
print("Multiple plugins found:") print("Multiple plugins found:")
self._print_plugins_list(found) self._print_plugins_list(found)
return exceptions.MultiplePluginsFound.error_code
@cliutils.args( @cliutils.args(
"--name", dest="name", type=str, "--name", dest="name", type=str,

View File

@ -560,7 +560,7 @@ class Workload(object):
task["subtasks"] = [collections.OrderedDict()] task["subtasks"] = [collections.OrderedDict()]
subtask = task["subtasks"][0] subtask = task["subtasks"][0]
subtask["title"] = workload["name"] subtask["title"] = workload["name"]
subtask["description"] = workload["description"] subtask["description"] = workload.get("description", "")
subtask["scenario"] = {workload["name"]: workload["args"]} subtask["scenario"] = {workload["name"]: workload["args"]}
subtask["contexts"] = workload["contexts"] subtask["contexts"] = workload["contexts"]
subtask["runner"] = {workload["runner_type"]: workload["runner"]} subtask["runner"] = {workload["runner_type"]: workload["runner"]}

View File

@ -156,8 +156,10 @@ class Plugin(meta.MetaMixin, info.InfoMixin):
allow_hidden=allow_hidden) allow_hidden=allow_hidden)
if not results: if not results:
base = cls._get_base()
base = "" if base == Plugin else " %s" % base.__name__
raise exceptions.PluginNotFound( raise exceptions.PluginNotFound(
name=name, platform=platform or "in any") name=name, platform=platform or "any", base=base)
if len(results) == 1: if len(results) == 1:
return results[0] return results[0]

View File

@ -214,9 +214,8 @@ class ValidatablePluginMixin(object):
""" """
try: try:
plugin = cls.get(name, allow_hidden=allow_hidden) plugin = cls.get(name, allow_hidden=allow_hidden)
except exceptions.PluginNotFound: except exceptions.PluginNotFound as e:
return ["There is no %s plugin with name: '%s'" % return [e.format_message()]
(cls.__name__, name)]
if vtype is None: if vtype is None:
semantic = True semantic = True

View File

@ -140,7 +140,8 @@ class NotFoundException(RallyException):
class PluginNotFound(NotFoundException): class PluginNotFound(NotFoundException):
error_code = 211 error_code = 211
msg_fmt = "There is no plugin `%(name)s` in %(platform)s platform." msg_fmt = "There is no%(base)s plugin `%(name)s` in %(platform)s " \
"platform."
class PluginWithSuchNameExists(RallyException): class PluginWithSuchNameExists(RallyException):

View File

@ -256,7 +256,15 @@ class TaskEngine(object):
:param vcontext: a validation context :param vcontext: a validation context
:param vtype: a type of validation (platform, syntax or semantic) :param vtype: a type of validation (platform, syntax or semantic)
""" """
scenario_cls = scenario.Scenario.get(workload["name"]) try:
scenario_cls = scenario.Scenario.get(workload["name"])
except exceptions.PluginNotFound as e:
raise exceptions.InvalidTaskConfig(
name=workload["name"],
pos=workload["position"],
config=json.dumps(objects.Workload.to_task(workload)),
reason=e.format_message()) from None
scenario_context = copy.deepcopy(scenario_cls.get_default_context()) scenario_context = copy.deepcopy(scenario_cls.get_default_context())
results = [] results = []
@ -318,14 +326,11 @@ class TaskEngine(object):
vtype=vtype)) vtype=vtype))
if results: if results:
msg = "\n ".join(results) raise exceptions.InvalidTaskConfig(
kw = {"name": workload["name"], name=workload["name"],
"pos": workload["position"], pos=workload["position"],
"config": json.dumps( config=json.dumps(objects.Workload.to_task(workload)),
objects.Workload.to_task(workload)), reason="\n ".join(results))
"reason": msg}
raise exceptions.InvalidTaskConfig(**kw)
@logging.log_task_wrapper(LOG.info, "Task validation of syntax.") @logging.log_task_wrapper(LOG.info, "Task validation of syntax.")
def _validate_config_syntax(self, config): def _validate_config_syntax(self, config):

View File

@ -51,3 +51,9 @@
shell: shell:
cmd: | cmd: |
sudo pip3 install bindep sudo pip3 install bindep
- name: Prepare rally plugins stored at home dir
shell:
cmd: |
mkdir --parents ~/.rally/plugins
cp --recursive {{ zuul.project.src_dir }}/rally-jobs/plugins/* ~/.rally/plugins

View File

@ -13,15 +13,23 @@
become: yes become: yes
when: bindep_output.stdout_lines when: bindep_output.stdout_lines
- name: Install Rally and check - name: Install Rally system wide
shell:
executable: /bin/sh
chdir: '{{ zuul.project.src_dir }}'
cmd: "sudo pip3 install --constraint ./upper-constraints.txt ./"
- name: Check Rally base commands
shell: shell:
cmd: | cmd: |
# install system wide
sudo pip3 install --constraint ./upper-constraints.txt ./
rally --version rally --version
rally db create rally db create
rally env list rally env list
# should be loaded from ~/.rally/plugins
rally plugin show --name FakePlugin.testplugin
# builtin plugin
rally plugin show --name HttpRequests.check_request
executable: /bin/sh executable: /bin/sh
chdir: '{{ zuul.project.src_dir }}'

View File

@ -12,12 +12,12 @@
import os import os
import unittest import testtools
from tests.functional import utils from tests.functional import utils
class DeploymentTestCase(unittest.TestCase): class DeploymentTestCase(testtools.TestCase):
def test_create_deployment_from_env(self): def test_create_deployment_from_env(self):
os.environ.update( os.environ.update(

View File

@ -17,12 +17,12 @@ import json
import os import os
import tempfile import tempfile
import unittest import testtools
from tests.functional import utils from tests.functional import utils
class EnvTestCase(unittest.TestCase): class EnvTestCase(testtools.TestCase):
def test_create_no_spec(self): def test_create_no_spec(self):
rally = utils.Rally() rally = utils.Rally()

View File

@ -14,14 +14,14 @@
# under the License. # under the License.
import subprocess import subprocess
import unittest
import six import six
import testtools
from rally.utils import encodeutils from rally.utils import encodeutils
class CLITestCase(unittest.TestCase): class CLITestCase(testtools.TestCase):
def test_rally_cli(self): def test_rally_cli(self):
try: try:

View File

@ -13,12 +13,12 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import unittest import testtools
from tests.functional import utils from tests.functional import utils
class PluginTestCase(unittest.TestCase): class PluginTestCase(testtools.TestCase):
def test_show_one(self): def test_show_one(self):
rally = utils.Rally() rally = utils.Rally()
@ -30,29 +30,32 @@ class PluginTestCase(unittest.TestCase):
def test_show_multiple(self): def test_show_multiple(self):
rally = utils.Rally() rally = utils.Rally()
result = rally("plugin show Dummy") result = self.assertRaises(utils.RallyCliError,
self.assertIn("Multiple plugins found:", result) rally, "plugin show Dummy")
self.assertIn("Dummy.dummy", result) self.assertIn("Multiple plugins found:", result.output)
self.assertIn("Dummy.dummy_exception", result) self.assertIn("Dummy.dummy", result.output)
self.assertIn("Dummy.dummy_random_fail_in_atomic", result) self.assertIn("Dummy.dummy_exception", result.output)
self.assertIn("Dummy.dummy_random_fail_in_atomic", result.output)
def test_show_not_found(self): def test_show_not_found(self):
rally = utils.Rally() rally = utils.Rally()
name = "Dummy666666" name = "Dummy666666"
result = rally("plugin show %s" % name) result = self.assertRaises(utils.RallyCliError,
self.assertIn("Plugin %s not found" % name, result) rally, "plugin show %s" % name)
self.assertIn("Plugin %s not found" % name, result.output)
def test_show_not_found_in_specific_platform(self): def test_show_not_found_in_specific_platform(self):
rally = utils.Rally() rally = utils.Rally()
name = "Dummy" name = "Dummy"
platform = "non_existing" platform = "non_existing"
result = rally( result = self.assertRaises(
"plugin show --name %(name)s --platform %(platform)s" utils.RallyCliError,
% {"name": name, "platform": platform}) rally, "plugin show --name %(name)s --platform %(platform)s"
% {"name": name, "platform": platform})
self.assertIn( self.assertIn(
"Plugin %(name)s@%(platform)s not found" "Plugin %(name)s@%(platform)s not found"
% {"name": name, "platform": platform}, % {"name": name, "platform": platform},
result) result.output)
def test_list(self): def test_list(self):
rally = utils.Rally() rally = utils.Rally()

View File

@ -15,12 +15,13 @@
import os import os
import subprocess import subprocess
import unittest
import testtools
from tests.functional import utils from tests.functional import utils
class LibAPITestCase(unittest.TestCase): class LibAPITestCase(testtools.TestCase):
def test_rally_lib(self): def test_rally_lib(self):
rally = utils.Rally(force_new_db=True) rally = utils.Rally(force_new_db=True)

View File

@ -203,7 +203,7 @@ class Rally(object):
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
output = encodeutils.safe_decode(e.output) output = encodeutils.safe_decode(e.output)
raise RallyCliError(cmd, e.returncode, output) raise RallyCliError(cmd, e.returncode, output) from None
finally: finally:
if write_report: if write_report:
if not report_path: if not report_path:

View File

@ -98,8 +98,8 @@ class ValidatorTestCase(test.TestCase):
result = DummyPluginBase.validate("dummy_plugin", None, None, None) result = DummyPluginBase.validate("dummy_plugin", None, None, None)
self.assertEqual(1, len(result)) self.assertEqual(1, len(result))
self.assertIn("There is no DummyPluginBase plugin " self.assertIn("There is no DummyPluginBase plugin `dummy_plugin`",
"with name: 'dummy_plugin'", result[0]) result[0])
def test_failure_includes_detailed_info(self): def test_failure_includes_detailed_info(self):