From a3fcc33daaa0b6a00fba784dbf37719c9b278853 Mon Sep 17 00:00:00 2001 From: Boris Pavlovic Date: Tue, 25 Aug 2015 21:05:37 -0700 Subject: [PATCH] [cli] Introduce "rally plugin" show and list commands This patch does a few things - Introduce rally.common.plugin.info.InfoMixin and adds it to plugin base. It adds method get_info() to all plugins. This method returns information about plugin such like title, description, arguments, plugin module - Introduce rally plugin show and list commands that returns information about all plugins - Moves info related methods from rally.common.utils to rally.common.plugin.info module Related-Bug: #1470895 Change-Id: I8db12e3017d241a2b8bc549a817dad817f922437 --- etc/rally.bash_completion | 2 + .../openstack/context/network/allow_ssh.py | 1 + .../openstack/scenarios/cinder/utils.py | 5 +- .../openstack/scenarios/sahara/utils.py | 4 +- rally/plugins/openstack/wrappers/network.py | 4 +- tests/functional/test_cli_plugin.py | 78 +++++++++++++++++++ 6 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 tests/functional/test_cli_plugin.py diff --git a/etc/rally.bash_completion b/etc/rally.bash_completion index 8656a752..198c4b1a 100644 --- a/etc/rally.bash_completion +++ b/etc/rally.bash_completion @@ -32,6 +32,8 @@ _rally() OPTS["info_ServerProviders"]="" OPTS["info_find"]="--query" OPTS["info_list"]="" + OPTS["plugin_list"]="--name --namespace" + OPTS["plugin_show"]="--name --namespace" OPTS["show_flavors"]="--deployment" OPTS["show_images"]="--deployment" OPTS["show_keypairs"]="--deployment" diff --git a/rally/plugins/openstack/context/network/allow_ssh.py b/rally/plugins/openstack/context/network/allow_ssh.py index ae6cf12a..bc8c27c9 100644 --- a/rally/plugins/openstack/context/network/allow_ssh.py +++ b/rally/plugins/openstack/context/network/allow_ssh.py @@ -87,6 +87,7 @@ def _prepare_open_secgroup(endpoint, secgroup_name): @context.configure(name="allow_ssh", order=320) class AllowSSH(context.Context): + """Sets up security groups for all users to access VM via SSH.""" @utils.log_task_wrapper(LOG.info, _("Enter context: `allow_ssh`")) def setup(self): diff --git a/rally/plugins/openstack/scenarios/cinder/utils.py b/rally/plugins/openstack/scenarios/cinder/utils.py index 46f9ec3b..c3a83c95 100644 --- a/rally/plugins/openstack/scenarios/cinder/utils.py +++ b/rally/plugins/openstack/scenarios/cinder/utils.py @@ -218,9 +218,8 @@ class CinderScenario(scenario.OpenStackScenario): it's attached to an instance :param container_format: container format of image. Acceptable formats: ami, ari, aki, bare, and ovf - :param: disk_format: disk format of image. Acceptable formats: - ami, ari, aki, vhd, vmdk, raw, qcow2, vdi - and iso + :param disk_format: disk format of image. Acceptable formats: + ami, ari, aki, vhd, vmdk, raw, qcow2, vdi and iso :returns: Returns created image object """ resp, img = volume.upload_to_image(force, self._generate_random_name(), diff --git a/rally/plugins/openstack/scenarios/sahara/utils.py b/rally/plugins/openstack/scenarios/sahara/utils.py index 01b5a334..77fa99b7 100644 --- a/rally/plugins/openstack/scenarios/sahara/utils.py +++ b/rally/plugins/openstack/scenarios/sahara/utils.py @@ -411,7 +411,7 @@ class SaharaScenario(scenario.OpenStackScenario): def _create_output_ds(self): """Create an output Data Source based on EDP context - :return: The created Data Source + :returns: The created Data Source """ ds_type = self.context["sahara_output_conf"]["output_type"] url_prefix = self.context["sahara_output_conf"]["output_url_prefix"] @@ -502,7 +502,7 @@ class SaharaScenario(scenario.OpenStackScenario): If Nova Network is used as networking backend, None is returned. - :return: Network id for Neutron or None for Nova Networking. + :returns: Network id for Neutron or None for Nova Networking. """ if consts.Service.NEUTRON not in self.clients("services").values(): diff --git a/rally/plugins/openstack/wrappers/network.py b/rally/plugins/openstack/wrappers/network.py index 64749136..c2e5777c 100644 --- a/rally/plugins/openstack/wrappers/network.py +++ b/rally/plugins/openstack/wrappers/network.py @@ -370,7 +370,7 @@ class NeutronWrapper(NetworkWrapper): """Create Neutron floating IP. :param ext_network: floating network name or dict - :param tenant_id str tenant id + :param tenant_id: str tenant id :param port_id: str port id :param **kwargs: for compatibility, not used here :returns: floating IP dict @@ -415,7 +415,7 @@ class NeutronWrapper(NetworkWrapper): """Check whether a neutron extension is supported :param extension: str, neutron extension - :return: result tuple + :returns: result tuple :rtype: (bool, string) """ extensions = self.client.list_extensions().get("extensions", []) diff --git a/tests/functional/test_cli_plugin.py b/tests/functional/test_cli_plugin.py new file mode 100644 index 00000000..04f72a92 --- /dev/null +++ b/tests/functional/test_cli_plugin.py @@ -0,0 +1,78 @@ +# Copyright 2015: Mirantis Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +from tests.functional import utils + + +class PluginTestCase(unittest.TestCase): + + def setUp(self): + super(PluginTestCase, self).setUp() + self.rally = utils.Rally() + + def test_show_one(self): + result = self.rally("plugin show Dummy.dummy_with_scenario_output") + self.assertIn("NAME", result) + self.assertIn("NAMESPACE", result) + self.assertIn("Dummy.dummy_with_scenario_output", result) + self.assertIn("MODULE", result) + + def test_show_multiple_and_full_match(self): + result = self.rally("plugin show Dummy.dummy") + self.assertIn("NAME", result) + self.assertIn("NAMESPACE", result) + self.assertIn("Dummy.dummy", result) + self.assertIn("MODULE", result) + + def test_show_multiple(self): + result = self.rally("plugin show Dummy") + self.assertIn("Multiple plugins found:", result) + self.assertIn("Dummy.dummy", result) + self.assertIn("Dummy.dummy_exception", result) + self.assertIn("Dummy.dummy_with_scenario_output", result) + self.assertIn("Dummy.dummy_random_fail_in_atomic", result) + + def test_show_not_found(self): + name = "Dummy666666" + result = self.rally("plugin show %s" % name) + self.assertIn("There is no plugin: %s" % name, result) + + def test_show_not_found_in_specific_namespace(self): + name = "Dummy" + namespace = "non_existing" + result = self.rally( + "plugin show --name %(name)s --namespace %(namespace)s" + % {"name": name, "namespace": namespace}) + self.assertIn( + "There is no plugin: %(name)s in %(namespace)s namespace" + % {"name": name, "namespace": namespace}, + result) + + def test_list(self): + result = self.rally("plugin list Dummy") + self.assertIn("Dummy.dummy", result) + self.assertIn("Dummy.dummy_exception", result) + self.assertIn("Dummy.dummy_with_scenario_output", result) + self.assertIn("Dummy.dummy_random_fail_in_atomic", result) + + def test_list_not_found_namespace(self): + result = self.rally("plugin list --namespace some") + self.assertIn("There is no plugin namespace: some", result) + + def test_list_not_found_name(self): + result = self.rally("plugin list Dummy2222") + self.assertIn("There is no plugin: Dummy2222", result)