[Verify] Adding 'add-options' arg to `rally verify genconfig` cmd

Tempest supports a mechanism that allows us to plug in various tests as
a Tempest plugin. Each plugin needs to be configured in the proper way.
Rally cannot configure all plugins on the planet. We should add some
option that will allow us to add extra configuration for plugins to
Tempest config file.

For example, if we want to run Ceilometer tests, the workflow will be
as follows:

$ rally verify install
$ rally verify installplugin --source https://github.com/openstack/ceilometer.git
$ rally verify genconfig --add-options /path/to/config/file/for/ceilometer/tests
$ rally verify start --regex ceilometer

where config file for Ceilometer tests is something like this:

...
[service_available]

ceilometer = True
event_enabled = True
...

Change-Id: Ida02a36e2757a742ca91919cc756846f137a23d3
This commit is contained in:
Yaroslav Lobankov 2016-08-06 13:48:36 +03:00
parent e4f9a75f8a
commit 2d9ceb5a34
8 changed files with 74 additions and 24 deletions

View File

@ -49,7 +49,7 @@ _rally()
OPTS["verify_compare"]="--uuid-1 --uuid-2 --csv --html --json --output-file --threshold"
OPTS["verify_detailed"]="--uuid --sort-by"
OPTS["verify_discover"]="--deployment --pattern --system-wide"
OPTS["verify_genconfig"]="--deployment --tempest-config --override"
OPTS["verify_genconfig"]="--deployment --tempest-config --add-options --override"
OPTS["verify_import"]="--deployment --set --file --no-use"
OPTS["verify_install"]="--deployment --source --version --system-wide"
OPTS["verify_installplugin"]="--deployment --source --version --system-wide"

View File

@ -560,11 +560,13 @@ class Verification(object):
@classmethod
def configure_tempest(cls, deployment, tempest_config=None,
override=False):
"""Generate configuration file of Tempest.
extra_conf=None, override=False):
"""Generate Tempest configuration file.
:param deployment: UUID or name of a deployment
:param tempest_config: User specified Tempest config file location
:param extra_conf: A ConfigParser() object with options to
extend/update Tempest config file
:param override: Whether or not to override existing Tempest
config file
"""
@ -574,11 +576,11 @@ class Verification(object):
cls._check_tempest_tree_existence(verifier)
verifier.generate_config_file(override)
verifier.generate_config_file(extra_conf, override)
@classmethod
def show_config_info(cls, deployment):
"""Get information about configuration file of Tempest.
"""Get information about Tempest configuration file.
:param deployment: UUID or name of a deployment
"""

View File

@ -20,6 +20,7 @@ import json
import os
import six
from six.moves import configparser
import yaml
from rally import api
@ -405,20 +406,36 @@ class VerifyCommands(object):
@cliutils.args("--tempest-config", dest="tempest_config", type=str,
required=False, metavar="<path>",
help="User-specified Tempest config file location")
@cliutils.args("--add-options", dest="extra_conf_path", type=str,
required=False, metavar="<path>",
help="Path to a file with additional options "
"to extend/update Tempest config file")
@cliutils.args("--override", dest="override",
help="Override existing Tempest config file",
required=False, action="store_true")
@envutils.with_default_deployment(cli_arg_name="deployment")
def genconfig(self, deployment=None, tempest_config=None, override=False):
def genconfig(self, deployment=None, tempest_config=None,
extra_conf_path=None, override=False):
"""Generate Tempest configuration file.
:param deployment: UUID or name of a deployment
:param tempest_config: User-specified Tempest config file location
:param extra_conf_path: Path to a file with additional options
to extend/update Tempest config file
:param override: Whether or not to override existing Tempest
config file
"""
extra_conf = None
if extra_conf_path:
if os.path.exists(extra_conf_path):
extra_conf = configparser.ConfigParser()
extra_conf.read(os.path.abspath(extra_conf_path))
else:
print(_("File '%s' not found.") % extra_conf_path)
return 1
api.Verification.configure_tempest(deployment, tempest_config,
override)
extra_conf, override)
@cliutils.args("--deployment", dest="deployment", type=str,
metavar="<uuid>", required=False,

View File

@ -306,13 +306,19 @@ class TempestConfig(utils.RandomNameGeneratorMixin):
self.conf.set(section_name, "stack_user_role",
CONF.tempest.heat_stack_user_role)
def generate(self, conf_path=None):
def generate(self, conf_path, extra_conf=None):
for name, method in inspect.getmembers(self, inspect.ismethod):
if name.startswith("_configure_"):
method()
if conf_path:
_write_config(conf_path, self.conf)
if extra_conf:
for section in extra_conf.sections():
if section not in self.conf.sections():
self.conf.add_section(section)
for option, value in extra_conf.items(section):
self.conf.set(section, option, value)
_write_config(conf_path, self.conf)
class TempestResourcesContext(utils.RandomNameGeneratorMixin):

View File

@ -204,9 +204,11 @@ class Tempest(object):
def is_configured(self):
return os.path.isfile(self.config_file)
def generate_config_file(self, override=False):
"""Generate configuration file of Tempest for current deployment.
def generate_config_file(self, extra_conf=None, override=False):
"""Generate Tempest configuration file for the current deployment.
:param extra_conf: A ConfigParser() object with options to
extend/update Tempest config file
:param override: Whether or not to override existing Tempest
config file
"""
@ -217,7 +219,8 @@ class Tempest(object):
LOG.info(_("Creating Tempest configuration "
"file for deployment: %s") % self.deployment)
config.TempestConfig(self.deployment).generate(self.config_file)
conf = config.TempestConfig(self.deployment)
conf.generate(self.config_file, extra_conf)
LOG.info(_("Tempest configuration file "
"has been successfully created!"))
else:

View File

@ -443,7 +443,7 @@ class VerifyCommandsTestCase(test.TestCase):
deployment_id = "14377d10-ca77-4104-aba8-36edebcfc120"
self.verify.genconfig(deployment_id)
mock_verification_configure_tempest.assert_called_once_with(
deployment_id, None, False)
deployment_id, None, None, False)
@mock.patch("rally.api.Verification.configure_tempest")
def test_genconfig_with_config_specified(
@ -452,7 +452,19 @@ class VerifyCommandsTestCase(test.TestCase):
tempest_conf = "/tmp/tempest.conf"
self.verify.genconfig(deployment_id, tempest_config=tempest_conf)
mock_verification_configure_tempest.assert_called_once_with(
deployment_id, tempest_conf, False)
deployment_id, tempest_conf, None, False)
@mock.patch("rally.api.Verification.configure_tempest")
@mock.patch("six.moves.configparser.ConfigParser")
@mock.patch("os.path.exists", return_value=True)
def test_genconfig_with_extra_conf_path_specified(
self, mock_exists, mock_config_parser,
mock_verification_configure_tempest):
deployment_id = "68b501af-a553-431c-83ac-30f93a112231"
extra_conf_path = "/tmp/extra.conf"
self.verify.genconfig(deployment_id, extra_conf_path=extra_conf_path)
mock_verification_configure_tempest.assert_called_once_with(
deployment_id, None, mock_config_parser(), False)
@mock.patch("rally.api.Verification.configure_tempest")
def test_genconfig_override_config(
@ -460,17 +472,21 @@ class VerifyCommandsTestCase(test.TestCase):
deployment_id = "cd5b64ad-c12f-4781-a89e-95535b145a11"
self.verify.genconfig(deployment_id, override=True)
mock_verification_configure_tempest.assert_called_once_with(
deployment_id, None, True)
deployment_id, None, None, True)
@mock.patch("rally.api.Verification.configure_tempest")
def test_genconfig_with_config_specified_and_override_config(
self, mock_verification_configure_tempest):
@mock.patch("six.moves.configparser.ConfigParser")
@mock.patch("os.path.exists", return_value=True)
def test_genconfig_with_all_args_specified(
self, mock_exists, mock_config_parser,
mock_verification_configure_tempest):
deployment_id = "89982aba-efef-48cb-8d94-ca893b4e78a6"
tempest_conf = "/tmp/tempest.conf"
self.verify.genconfig(deployment_id,
tempest_config=tempest_conf, override=True)
tempest_conf_path = "/tmp/tempest.conf"
extra_conf_path = "/tmp/extra-tempest.conf"
self.verify.genconfig(deployment_id, tempest_config=tempest_conf_path,
extra_conf_path=extra_conf_path, override=True)
mock_verification_configure_tempest.assert_called_once_with(
deployment_id, tempest_conf, True)
deployment_id, tempest_conf_path, mock_config_parser(), True)
@mock.patch("rally.api.Verification.install_tempest")
def test_install(self, mock_verification_install_tempest):

View File

@ -550,7 +550,7 @@ class VerificationAPITestCase(BaseDeploymentTestCase):
self, mock_tempest, mock_deployment_get, mock_exists):
mock_tempest.return_value = self.tempest
api.Verification.configure_tempest(self.deployment_uuid)
self.tempest.generate_config_file.assert_called_once_with(False)
self.tempest.generate_config_file.assert_called_once_with(None, False)
@mock.patch("os.path.exists", return_value=False)
@mock.patch("rally.common.objects.Deployment.get")

View File

@ -264,8 +264,14 @@ class TempestConfigTestCase(test.TestCase):
mock_inspect_getmembers.return_value = [("_configure_something",
configure_something_method)]
self.tempest_conf.generate("/path/to/fake/conf")
fake_extra_conf = mock.MagicMock()
fake_extra_conf.sections.return_value = ["section"]
fake_extra_conf.items.return_value = [("option", "value")]
self.tempest_conf.generate("/path/to/fake/conf", fake_extra_conf)
self.assertEqual(configure_something_method.call_count, 1)
self.assertIn(("option", "value"),
self.tempest_conf.conf.items("section"))
self.assertEqual(mock__write_config.call_count, 1)
@mock.patch("six.moves.builtins.open", side_effect=mock.mock_open())