diff --git a/etc/rally.bash_completion b/etc/rally.bash_completion index e9b38d36ac..02e6d14f68 100644 --- a/etc/rally.bash_completion +++ b/etc/rally.bash_completion @@ -54,6 +54,7 @@ _rally() OPTS["verify_install"]="--deployment --source --version --system-wide" OPTS["verify_installplugin"]="--deployment --source --version --system-wide" OPTS["verify_list"]="" + OPTS["verify_listplugins"]="--deployment --system-wide" OPTS["verify_reinstall"]="--deployment --source --version --system-wide" OPTS["verify_results"]="--uuid --html --json --output-file" OPTS["verify_show"]="--uuid --sort-by --detailed" diff --git a/rally/api.py b/rally/api.py index f5f1546731..b22e7cd556 100644 --- a/rally/api.py +++ b/rally/api.py @@ -508,6 +508,21 @@ class Verification(object): verifier.install_plugin() + @classmethod + def list_tempest_plugins(cls, deployment, system_wide=False): + """List all installed Tempest plugins. + + :param deployment: UUID or name of a deployment + :param system_wide: List all plugins installed in the local env or + in Tempest virtual env + """ + deployment_uuid = objects.Deployment.get(deployment)["uuid"] + verifier = tempest.Tempest(deployment_uuid, system_wide=system_wide) + + cls._check_tempest_tree_existence(verifier) + + return verifier.list_plugins() + @classmethod def discover_tests(cls, deployment, pattern=""): """Get a list of discovered tests. diff --git a/rally/cli/commands/verify.py b/rally/cli/commands/verify.py index f534af621c..cdca38d1cf 100644 --- a/rally/cli/commands/verify.py +++ b/rally/cli/commands/verify.py @@ -495,6 +495,22 @@ class VerifyCommands(object): api.Verification.install_tempest_plugin(deployment, source, version, system_wide) + @cliutils.args("--deployment", type=str, dest="deployment", + required=False, help="UUID or name of a deployment") + @cliutils.args("--system-wide", dest="system_wide", + help="List all plugins installed in the local env, " + "not in Tempest virtual env", + required=False, action="store_true") + @envutils.with_default_deployment(cli_arg_name="deployment") + def listplugins(self, deployment=None, system_wide=False): + """List all installed Tempest plugins. + + :param deployment: UUID or name of a deployment + :param system_wide: List all plugins installed in the local env or + in Tempest virtual env + """ + print(api.Verification.list_tempest_plugins(deployment, system_wide)) + @cliutils.args("--deployment", dest="deployment", type=str, required=False, metavar="", help="UUID or name of a deployment") @cliutils.args("--pattern", dest="pattern", type=str, diff --git a/rally/ui/templates/ci/index_verify.html b/rally/ui/templates/ci/index_verify.html index c5ebd03b6a..35bccac0f9 100644 --- a/rally/ui/templates/ci/index_verify.html +++ b/rally/ui/templates/ci/index_verify.html @@ -53,10 +53,6 @@ Tempest installation $ {{ install.cmd }} - [{{ discover.status }}] - Discovering tests - $ {{ discover.cmd }} - [{{ reinstall.status }}] Tempest re-installation $ {{ reinstall.cmd }} @@ -65,6 +61,14 @@ Tempest plugin installation $ {{ installplugin.cmd }} + [{{ listplugins.status }}] + List installed Tempest plugins + $ {{ listplugins.cmd }} + + [{{ discover.status }}] + Discovering tests + $ {{ discover.cmd }} + [{{ genconfig.status }}] Tempest config generation $ {{ genconfig.cmd }} diff --git a/rally/verification/tempest/tempest.py b/rally/verification/tempest/tempest.py index 6d465ac418..a58a8326fa 100644 --- a/rally/verification/tempest/tempest.py +++ b/rally/verification/tempest/tempest.py @@ -40,6 +40,7 @@ class TempestSetupFailure(exceptions.RallyException): def check_output(*args, **kwargs): + print_debug_output = kwargs.pop("print_debug_output", True) kwargs["stderr"] = subprocess.STDOUT try: output = subprocess.check_output(*args, **kwargs) @@ -48,7 +49,8 @@ def check_output(*args, **kwargs): LOG.error("Error output: '%s'" % encodeutils.safe_decode(e.output)) raise - LOG.debug("subprocess output: '%s'" % encodeutils.safe_decode(output)) + if print_debug_output: + LOG.debug("Subprocess output: '%s'" % encodeutils.safe_decode(output)) return output @@ -305,6 +307,13 @@ class Tempest(object): check_output(cmd, cwd=self.path()) LOG.info(_("Tempest plugin has been successfully installed!")) + def list_plugins(self): + """List all installed Tempest plugins for local Tempest repo.""" + cmd = ["tempest", "list-plugins"] + if not self._system_wide: + cmd.insert(0, self.path("tools/with_venv.sh")) + return check_output(cmd, cwd=self.path(), print_debug_output=False) + @logging.log_verification_wrapper(LOG.info, _("Run verification.")) def _prepare_and_run(self, set_name, regex, tests_file, concur, failing): if not self.is_configured(): diff --git a/tests/ci/rally_verify.py b/tests/ci/rally_verify.py index ad5ca54ea2..a581ca0578 100755 --- a/tests/ci/rally_verify.py +++ b/tests/ci/rally_verify.py @@ -255,6 +255,9 @@ def main(): render_vars["installplugin"] = call_rally( "verify installplugin --source %s" % TEMPEST_PLUGIN) + # List installed Tempest plugins + render_vars["listplugins"] = call_rally("verify listplugins") + # Discover tests depending on Tempest suite discover_cmd = "verify discover" if args.mode == "light": diff --git a/tests/unit/cli/commands/test_verify.py b/tests/unit/cli/commands/test_verify.py index 7b099da17a..e7782eff2b 100644 --- a/tests/unit/cli/commands/test_verify.py +++ b/tests/unit/cli/commands/test_verify.py @@ -483,7 +483,7 @@ class VerifyCommandsTestCase(test.TestCase): deployment_uuid, None, version, False) @mock.patch("rally.api.Verification.install_tempest_plugin") - def test_install_plugin_from_url( + def test_installplugin_from_url( self, mock_verification_install_tempest_plugin): deployment_uuid = "83514de2-a770-4e28-82dd-2826b725e733" url = "https://github.com/fake/plugin" @@ -492,7 +492,7 @@ class VerifyCommandsTestCase(test.TestCase): deployment_uuid, url, None, False) @mock.patch("rally.api.Verification.install_tempest_plugin") - def test_install_plugin_from_path( + def test_installplugin_from_path( self, mock_verification_install_tempest_plugin): deployment_uuid = "83514de2-a770-4e28-82dd-2826b725e733" path = "/tmp/fake/plugin" @@ -500,6 +500,13 @@ class VerifyCommandsTestCase(test.TestCase): mock_verification_install_tempest_plugin.assert_called_once_with( deployment_uuid, path, None, False) + @mock.patch("rally.api.Verification.list_tempest_plugins") + def test_listplugins(self, mock_verification_list_tempest_plugins): + deployment_uuid = "83514de2-a770-4e28-82dd-2826b725e733" + self.verify.listplugins(deployment_uuid) + mock_verification_list_tempest_plugins.assert_called_once_with( + deployment_uuid, False) + @mock.patch("rally.api.Verification.discover_tests") def test_discover(self, mock_verification_discover_tests): deployment_uuid = "97725f22-1cd2-46a5-8c62-3cdc36ed6d2a" diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index e73ae5996c..e28da14f79 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -515,6 +515,15 @@ class VerificationAPITestCase(BaseDeploymentTestCase): "/tmp/fake/plugin") self.tempest.install_plugin.assert_called_once_with() + @mock.patch("os.path.exists", return_value=True) + @mock.patch("rally.common.objects.Deployment.get") + @mock.patch("rally.verification.tempest.tempest.Tempest") + def test_list_tempest_plugins( + self, mock_tempest, mock_deployment_get, mock_exists): + mock_tempest.return_value = self.tempest + api.Verification.list_tempest_plugins(self.deployment_uuid) + self.tempest.list_plugins.assert_called_once_with() + @mock.patch("os.path.exists", return_value=True) @mock.patch("rally.common.objects.Deployment.get") @mock.patch("rally.verification.tempest.tempest.Tempest") diff --git a/tests/unit/verification/test_tempest.py b/tests/unit/verification/test_tempest.py index f4decabb37..2cfd9b5127 100644 --- a/tests/unit/verification/test_tempest.py +++ b/tests/unit/verification/test_tempest.py @@ -341,6 +341,14 @@ class TempestInstallPluginsTestCase(BaseTestCase): mock_tempest_check_output.assert_called_with(cmd, cwd=self.verifier.path()) + @mock.patch(TEMPEST_PATH + ".tempest.check_output") + def test_list_plugins(self, mock_tempest_check_output): + self.verifier.list_plugins() + + cmd = [self.verifier.venv_wrapper, "tempest", "list-plugins"] + mock_tempest_check_output.assert_called_with( + cmd, cwd=self.verifier.path(), print_debug_output=False) + class TempestVerifyTestCase(BaseTestCase): def _get_fake_call(self, testr_args,