Enhance rally info
* Add "rally info BenchmarkScenario", "rally info DeployEgnine" etc. * Simplify the default "rally info" output * Add SLA support Change-Id: I85259e7cf61b2b435b416b9618064f8ec22fe778
This commit is contained in:
parent
b439b4d127
commit
91acc1c039
@ -73,8 +73,6 @@ class Scenario(object):
|
||||
@staticmethod
|
||||
def get_by_name(name):
|
||||
"""Returns Scenario class by name."""
|
||||
# TODO(msdubov): support approximate string matching
|
||||
# (here and in other base classes).
|
||||
for scenario in utils.itersubclasses(Scenario):
|
||||
if name == scenario.__name__:
|
||||
return scenario
|
||||
|
@ -25,6 +25,7 @@ import jsonschema
|
||||
import six
|
||||
|
||||
from rally.benchmark.processing import utils as putils
|
||||
from rally import exceptions
|
||||
from rally.i18n import _
|
||||
from rally import utils
|
||||
|
||||
@ -81,6 +82,14 @@ class SLA(object):
|
||||
'detail': check_result.msg})
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
def get_by_name(name):
|
||||
"""Returns SLA by name."""
|
||||
for sla in utils.itersubclasses(SLA):
|
||||
if name == sla.__name__:
|
||||
return sla
|
||||
raise exceptions.NoSuchSLA(name=name)
|
||||
|
||||
|
||||
class FailureRate(SLA):
|
||||
"""Failure rate in percents."""
|
||||
|
@ -104,19 +104,6 @@ def args(*args, **kwargs):
|
||||
return _decorator
|
||||
|
||||
|
||||
def _get_doc(cls):
|
||||
"""Get the dynamic docstring of a class.
|
||||
|
||||
Return the usual docstring stored in __doc__ if no dynamic one exists.
|
||||
|
||||
:returns: docstring
|
||||
"""
|
||||
if hasattr(cls, "__get__doc__"):
|
||||
return cls().__get__doc__()
|
||||
else:
|
||||
return cls.__doc__
|
||||
|
||||
|
||||
def _methods_of(cls):
|
||||
"""Get all callable methods of a class that don't start with underscore.
|
||||
|
||||
@ -132,7 +119,7 @@ def _compose_category_description(category):
|
||||
descr_pairs = _methods_of(category)
|
||||
|
||||
description = ""
|
||||
doc = _get_doc(category)
|
||||
doc = category.__doc__
|
||||
if doc:
|
||||
description = doc.strip()
|
||||
if descr_pairs:
|
||||
|
@ -50,6 +50,7 @@ Samples:
|
||||
from __future__ import print_function
|
||||
|
||||
from rally.benchmark.scenarios import base as scenario_base
|
||||
from rally.benchmark.sla import base as sla_base
|
||||
from rally.cmd import cliutils
|
||||
from rally import deploy
|
||||
from rally.deploy import serverprovider
|
||||
@ -60,14 +61,18 @@ from rally import utils
|
||||
class InfoCommands(object):
|
||||
"""This command allows you to get quick doc of some rally entities.
|
||||
|
||||
Available for scenario groups, scenarios, deployment engines and
|
||||
Available for scenario groups, scenarios, SLA, deploy engines and
|
||||
server providers.
|
||||
"""
|
||||
|
||||
def __get__doc__(self):
|
||||
doc = "Usage:\n\n $ rally info find <query>\n\n"
|
||||
doc += "Possible queries:\n\n" + self._list()
|
||||
return doc
|
||||
Usage:
|
||||
$ rally info find <query>
|
||||
|
||||
To see lists of entities you can query docs for, type one of the following:
|
||||
$ rally info BenchmarkScenarios
|
||||
$ rally info SLA
|
||||
$ rally info DeployEngines
|
||||
$ rally info ServerProviders
|
||||
"""
|
||||
|
||||
@cliutils.args("--query", dest="query", type=str, help="Search query.")
|
||||
def find(self, query):
|
||||
@ -81,8 +86,8 @@ class InfoCommands(object):
|
||||
if info:
|
||||
print(info)
|
||||
else:
|
||||
print("Failed to find any docs for query: '%s'" % query)
|
||||
substitutions = self._find_substitution(query)
|
||||
print("Failed to find any docs for query: '%s'" % query)
|
||||
if substitutions:
|
||||
print("Did you mean one of these?\n\t%s" %
|
||||
"\n\t".join(substitutions))
|
||||
@ -93,36 +98,51 @@ class InfoCommands(object):
|
||||
|
||||
Lists benchmark scenario groups, deploy engines and server providers.
|
||||
"""
|
||||
print(self._list())
|
||||
self.BenchmarkScenarios()
|
||||
self.SLA()
|
||||
self.DeployEngines()
|
||||
self.ServerProviders()
|
||||
|
||||
def _list(self):
|
||||
base_classes = {"scenario_groups": scenario_base.Scenario,
|
||||
"deploy_engines": deploy.EngineFactory,
|
||||
"server_providers": serverprovider.ProviderFactory}
|
||||
descriptions = {"scenario_groups": [],
|
||||
"deploy_engines": [],
|
||||
"server_providers": []}
|
||||
for entity_type in base_classes:
|
||||
for entity in utils.itersubclasses(base_classes[entity_type]):
|
||||
name = entity.__name__
|
||||
doc = utils.parse_docstring(entity.__doc__)
|
||||
description = doc["short_description"] or ""
|
||||
descriptions[entity_type].append((name, description))
|
||||
|
||||
info = self._compose_table("Benchmark scenario groups",
|
||||
descriptions["scenario_groups"])
|
||||
def BenchmarkScenarios(self):
|
||||
"""List benchmark scenarios available in Rally."""
|
||||
scenarios = self._get_descriptions(scenario_base.Scenario)
|
||||
info = self._compose_table("Benchmark scenario groups", scenarios)
|
||||
info += (" To get information about benchmark scenarios inside "
|
||||
"each scenario group, run:\n"
|
||||
" $ rally info find <ScenarioGroupName>\n\n")
|
||||
info += self._compose_table("Deploy engines",
|
||||
descriptions["deploy_engines"])
|
||||
info += self._compose_table("Server providers",
|
||||
descriptions["server_providers"])
|
||||
return info
|
||||
print(info)
|
||||
|
||||
def SLA(self):
|
||||
"""List server providers available in Rally."""
|
||||
sla = self._get_descriptions(sla_base.SLA)
|
||||
info = self._compose_table("SLA", sla)
|
||||
print(info)
|
||||
|
||||
def DeployEngines(self):
|
||||
"""List deploy engines available in Rally."""
|
||||
engines = self._get_descriptions(deploy.EngineFactory)
|
||||
info = self._compose_table("Deploy engines", engines)
|
||||
print(info)
|
||||
|
||||
def ServerProviders(self):
|
||||
"""List server providers available in Rally."""
|
||||
providers = self._get_descriptions(serverprovider.ProviderFactory)
|
||||
info = self._compose_table("Server providers", providers)
|
||||
print(info)
|
||||
|
||||
def _get_descriptions(self, base_cls):
|
||||
descriptions = []
|
||||
for entity in utils.itersubclasses(base_cls):
|
||||
name = entity.__name__
|
||||
doc = utils.parse_docstring(entity.__doc__)
|
||||
description = doc["short_description"] or ""
|
||||
descriptions.append((name, description))
|
||||
return descriptions
|
||||
|
||||
def _find_info(self, query):
|
||||
return (self._get_scenario_group_info(query) or
|
||||
self._get_scenario_info(query) or
|
||||
self._get_sla_info(query) or
|
||||
self._get_deploy_engine_info(query) or
|
||||
self._get_server_provider_info(query))
|
||||
|
||||
@ -200,6 +220,15 @@ class InfoCommands(object):
|
||||
except exceptions.NoSuchScenario:
|
||||
return None
|
||||
|
||||
def _get_sla_info(self, query):
|
||||
try:
|
||||
sla = sla_base.SLA.get_by_name(query)
|
||||
info = "%s (SLA).\n\n" % sla.__name__
|
||||
info += utils.format_docstring(sla.__doc__)
|
||||
return info
|
||||
except exceptions.NoSuchSLA:
|
||||
return None
|
||||
|
||||
def _get_deploy_engine_info(self, query):
|
||||
try:
|
||||
deploy_engine = deploy.EngineFactory.get_by_name(query)
|
||||
|
@ -136,6 +136,10 @@ class NoSuchContext(NotFoundException):
|
||||
msg_fmt = _("There is no benchmark context with name `%(name)s`.")
|
||||
|
||||
|
||||
class NoSuchSLA(NotFoundException):
|
||||
msg_fmt = _("There is no SLA with name `%(name)s`.")
|
||||
|
||||
|
||||
class NoSuchConfigField(NotFoundException):
|
||||
msg_fmt = _("There is no field in the task config with name `%(name)s`.")
|
||||
|
||||
|
@ -38,6 +38,9 @@ class InfoTestCase(unittest.TestCase):
|
||||
def test_find_scenario(self):
|
||||
self.assertIn("(benchmark scenario)", self.rally("info find dummy"))
|
||||
|
||||
def test_find_sla(self):
|
||||
self.assertIn("(SLA)", self.rally("info find FailureRate"))
|
||||
|
||||
def test_find_deployment_engine(self):
|
||||
marker_string = "ExistingCloud (deploy engine)."
|
||||
self.assertIn(marker_string, self.rally("info find ExistingCloud"))
|
||||
@ -68,18 +71,29 @@ class InfoTestCase(unittest.TestCase):
|
||||
output = self.rally("info list")
|
||||
self.assertIn("Benchmark scenario groups:", output)
|
||||
self.assertIn("NovaServers", output)
|
||||
self.assertIn("SLA:", output)
|
||||
self.assertIn("FailureRate", output)
|
||||
self.assertIn("Deploy engines:", output)
|
||||
self.assertIn("ExistingCloud", output)
|
||||
self.assertIn("Server providers:", output)
|
||||
self.assertIn("ExistingServers", output)
|
||||
|
||||
def test_list_shorthand(self):
|
||||
try:
|
||||
self.rally("info")
|
||||
except utils.RallyCmdError as e:
|
||||
self.assertIn("Benchmark scenario groups:", e.output)
|
||||
self.assertIn("NovaServers", e.output)
|
||||
self.assertIn("Deploy engines:", e.output)
|
||||
self.assertIn("ExistingCloud", e.output)
|
||||
self.assertIn("Server providers:", e.output)
|
||||
self.assertIn("ExistingServers", e.output)
|
||||
def test_BenchmarkScenarios(self):
|
||||
output = self.rally("info BenchmarkScenarios")
|
||||
self.assertIn("Benchmark scenario groups:", output)
|
||||
self.assertIn("NovaServers", output)
|
||||
|
||||
def test_SLA(self):
|
||||
output = self.rally("info SLA")
|
||||
self.assertIn("SLA:", output)
|
||||
self.assertIn("FailureRate", output)
|
||||
|
||||
def test_DeployEngines(self):
|
||||
output = self.rally("info DeployEngines")
|
||||
self.assertIn("Deploy engines:", output)
|
||||
self.assertIn("ExistingCloud", output)
|
||||
|
||||
def test_ServerProviders(self):
|
||||
output = self.rally("info ServerProviders")
|
||||
self.assertIn("Server providers:", output)
|
||||
self.assertIn("ExistingServers", output)
|
||||
|
@ -17,6 +17,7 @@ import mock
|
||||
|
||||
from rally.benchmark.scenarios import base as scenario_base
|
||||
from rally.benchmark.scenarios.dummy import dummy
|
||||
from rally.benchmark.sla import base as sla_base
|
||||
from rally.cmd.commands import info
|
||||
from rally import deploy
|
||||
from rally.deploy.engines import existing as existing_cloud
|
||||
@ -27,6 +28,7 @@ from tests.unit import test
|
||||
|
||||
|
||||
SCENARIO = "rally.cmd.commands.info.scenario_base.Scenario"
|
||||
SLA = "rally.cmd.commands.info.sla_base.SLA"
|
||||
ENGINE = "rally.cmd.commands.info.deploy.EngineFactory"
|
||||
PROVIDER = "rally.cmd.commands.info.serverprovider.ProviderFactory"
|
||||
UTILS = "rally.cmd.commands.info.utils"
|
||||
@ -61,6 +63,13 @@ class InfoCommandsTestCase(test.TestCase):
|
||||
mock_get_scenario_by_name.assert_called_once_with(query)
|
||||
self.assertEqual(1, status)
|
||||
|
||||
@mock.patch(SLA + ".get_by_name", return_value=sla_base.FailureRate)
|
||||
def test_find_failure_rate_sla(self, mock_get_by_name):
|
||||
query = "FailureRate"
|
||||
status = self.info.find(query)
|
||||
mock_get_by_name.assert_called_once_with(query)
|
||||
self.assertEqual(None, status)
|
||||
|
||||
@mock.patch(ENGINE + ".get_by_name",
|
||||
return_value=existing_cloud.ExistingCloud)
|
||||
def test_find_existing_cloud(self, mock_get_by_name):
|
||||
@ -82,6 +91,32 @@ class InfoCommandsTestCase(test.TestCase):
|
||||
status = self.info.list()
|
||||
mock_itersubclasses.assert_has_calls([
|
||||
mock.call(scenario_base.Scenario),
|
||||
mock.call(sla_base.SLA),
|
||||
mock.call(deploy.EngineFactory),
|
||||
mock.call(serverprovider.ProviderFactory)])
|
||||
self.assertEqual(None, status)
|
||||
|
||||
@mock.patch(UTILS + ".itersubclasses", return_value=[dummy.Dummy])
|
||||
def test_BenchmarkScenarios(self, mock_itersubclasses):
|
||||
status = self.info.BenchmarkScenarios()
|
||||
mock_itersubclasses.assert_called_once_with(scenario_base.Scenario)
|
||||
self.assertEqual(None, status)
|
||||
|
||||
@mock.patch(UTILS + ".itersubclasses", return_value=[dummy.Dummy])
|
||||
def test_SLA(self, mock_itersubclasses):
|
||||
status = self.info.SLA()
|
||||
mock_itersubclasses.assert_called_once_with(sla_base.SLA)
|
||||
self.assertEqual(None, status)
|
||||
|
||||
@mock.patch(UTILS + ".itersubclasses", return_value=[dummy.Dummy])
|
||||
def test_DeployEngines(self, mock_itersubclasses):
|
||||
status = self.info.DeployEngines()
|
||||
mock_itersubclasses.assert_called_once_with(deploy.EngineFactory)
|
||||
self.assertEqual(None, status)
|
||||
|
||||
@mock.patch(UTILS + ".itersubclasses", return_value=[dummy.Dummy])
|
||||
def test_ServerProviders(self, mock_itersubclasses):
|
||||
status = self.info.ServerProviders()
|
||||
mock_itersubclasses.assert_called_once_with(
|
||||
serverprovider.ProviderFactory)
|
||||
self.assertEqual(None, status)
|
||||
|
@ -6,6 +6,10 @@ _rally()
|
||||
declare -A SUBCOMMANDS
|
||||
declare -A OPTS
|
||||
|
||||
OPTS["info_BenchmarkScenarios"]=""
|
||||
OPTS["info_DeployEngines"]=""
|
||||
OPTS["info_SLA"]=""
|
||||
OPTS["info_ServerProviders"]=""
|
||||
OPTS["info_find"]="--query"
|
||||
OPTS["info_list"]=""
|
||||
OPTS["use_deployment"]="--uuid --name"
|
||||
|
Loading…
Reference in New Issue
Block a user