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