Merge "Fix several issues with plugin discovery error messages"
This commit is contained in:
commit
d69025e23b
|
@ -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
|
||||||
--------------------
|
--------------------
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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"]}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 }}'
|
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue