diff --git a/rally/benchmark/utils.py b/rally/benchmark/utils.py index bd207943ca..8cb3905f14 100644 --- a/rally/benchmark/utils.py +++ b/rally/benchmark/utils.py @@ -14,7 +14,6 @@ # under the License. import itertools -import logging import time import traceback @@ -22,6 +21,7 @@ from novaclient import exceptions as nova_exc from novaclient.v1_1 import servers from rally import exceptions +from rally import log as logging LOG = logging.getLogger(__name__) diff --git a/rally/benchmark/validation.py b/rally/benchmark/validation.py index 4d5789a6bf..3f2fa6124a 100644 --- a/rally/benchmark/validation.py +++ b/rally/benchmark/validation.py @@ -292,11 +292,14 @@ def tempest_tests_exists(config, clients, task): if not tests: return ValidationResult(False, - "Parameter 'test_name' or 'test_names' should " - "be specified.") + _("Parameter 'test_name' or 'test_names' " + "should be specified.")) verifier = tempest.Tempest(task["deployment_uuid"]) if not verifier.is_installed(): - verifier.install() + try: + verifier.install() + except tempest.TempestSetupFailure as e: + return ValidationResult(False, e) if not verifier.is_configured(): verifier.generate_config_file() diff --git a/rally/cmd/api.py b/rally/cmd/api.py index 2fe0a58766..334f53ab2a 100644 --- a/rally/cmd/api.py +++ b/rally/cmd/api.py @@ -15,7 +15,6 @@ """ The Rally Service API. """ -import logging import os import sys from wsgiref import simple_server @@ -24,17 +23,17 @@ from oslo.config import cfg from rally.aas.rest import app as rally_app from rally.i18n import _ -from rally import log +from rally import log as logging CONF = cfg.CONF -LOG = log.getLogger(__name__) +LOG = logging.getLogger(__name__) def main(): # Initialize configuration and logging. CONF(sys.argv[1:], project='rally') - log.setup('rally') + logging.setup('rally') # Prepare application and bind to the service socket. host = CONF.rest.host port = CONF.rest.port @@ -43,7 +42,7 @@ def main(): # Start application. LOG.info(_('Starting server in PID %s') % os.getpid()) LOG.info(_("Configuration:")) - CONF.log_opt_values(LOG, logging.INFO) + CONF.log_opt_values(LOG, logging.logging.INFO) try: server.serve_forever() except KeyboardInterrupt: diff --git a/rally/verification/verifiers/tempest/tempest.py b/rally/verification/verifiers/tempest/tempest.py index 34c03864cf..2cb0179de9 100644 --- a/rally/verification/verifiers/tempest/tempest.py +++ b/rally/verification/verifiers/tempest/tempest.py @@ -14,16 +14,17 @@ # under the License. -import logging import os import shutil import subprocess import sys +from oslo.config import cfg from oslo.serialization import jsonutils from rally import exceptions from rally.i18n import _ +from rally import log as logging from rally import utils from rally.verification.verifiers.tempest import config from rally.verification.verifiers.tempest import subunit2json @@ -32,13 +33,19 @@ LOG = logging.getLogger(__name__) class TempestSetupFailure(exceptions.RallyException): - msg_fmt = _("Unable to setup tempest: '%(message)s'") + msg_fmt = _("Unable to setup tempest: '%(message)s'.") def check_output(*args, **kwargs): - output = subprocess.check_output(*args, **kwargs) + kwargs["stderr"] = subprocess.STDOUT + try: + output = subprocess.check_output(*args, **kwargs) + except subprocess.CalledProcessError as e: + LOG.debug("failed cmd: '%s'" % e.cmd) + LOG.debug("error output: '%s'" % e.output) + raise - if LOG.getEffectiveLevel() <= logging.DEBUG: + if cfg.CONF.rally_debug: print(output) @@ -83,10 +90,15 @@ class Tempest(object): self.validate_env() print("No virtual environment found...Install the virtualenv.") LOG.debug("Virtual environment directory: %s" % path_to_venv) - check_output("python ./tools/install_venv.py", shell=True, - cwd=self.path()) - check_output("%s python setup.py install" % self.venv_wrapper, - shell=True, cwd=self.path()) + try: + check_output("python ./tools/install_venv.py", shell=True, + cwd=self.path()) + check_output("%s python setup.py install" % self.venv_wrapper, + shell=True, cwd=self.path()) + except subprocess.CalledProcessError: + if os.path.exists(self.path(".venv")): + shutil.rmtree(self.path(".venv")) + raise TempestSetupFailure(_("failed to install virtualenv")) def is_configured(self): return os.path.isfile(self.config_file) @@ -106,11 +118,14 @@ class Tempest(object): def _initialize_testr(self): if not os.path.isdir(self.path(".testrepository")): - msg = _("Test Repository initialization.") - LOG.info(_("Starting: ") + msg) - subprocess.check_call("%s testr init" % self.venv_wrapper, - shell=True, cwd=self.path()) - LOG.info(_("Completed: ") + msg) + print(_("Test Repository initialization.")) + try: + check_output("%s testr init" % self.venv_wrapper, + shell=True, cwd=self.path()) + except subprocess.CalledProcessError: + if os.path.exists(self.path(".testrepository")): + shutil.rmtree(self.path(".testrepository")) + raise TempestSetupFailure(_("failed to initialize testr")) def is_installed(self): return os.path.exists(self.path(".venv")) diff --git a/tests/hacking/checks.py b/tests/hacking/checks.py index 871482b7f5..2c63da6c53 100644 --- a/tests/hacking/checks.py +++ b/tests/hacking/checks.py @@ -82,10 +82,10 @@ def check_assert_methods_from_mock(logical_line, filename): def check_import_of_logging(logical_line, filename): """Check correctness import of logging module N310.""" - excluded_files = ["./rally/log.py"] + excluded_files = ["./rally/log.py", "./tests/unit/test_log.py"] forbidden_imports = ["from rally.openstack.common import log", - "import rally.openstack.common.log" + "import rally.openstack.common.log", "import logging"] if filename not in excluded_files: diff --git a/tests/unit/benchmark/test_validation.py b/tests/unit/benchmark/test_validation.py index 3f68247bf6..80c74e76cd 100644 --- a/tests/unit/benchmark/test_validation.py +++ b/tests/unit/benchmark/test_validation.py @@ -21,6 +21,7 @@ from rally.benchmark import validation from rally import consts from rally import exceptions from rally import objects +from rally.verification.verifiers.tempest import tempest from tests.unit import test @@ -334,6 +335,29 @@ class ValidatorsTestCase(test.TestCase): None, task) self.assertFalse(result.is_valid, result.msg) + @mock.patch("rally.benchmark.validation.tempest.Tempest") + @mock.patch("rally.objects.task.db.task_create") + def test_tempest_tests_exists_tempest_installation_failed( + self, mock_create, mock_tempest): + mock_create.return_value = { + 'status': 'init', + 'deployment_uuid': 'deployment-uuid', + 'verification_log': '', + 'uuid': 'task-uuid', + 'created_at': '', + 'failed': False, + 'tag': '', + 'id': 42} + mock_tempest().is_installed.return_value = False + mock_tempest().install.side_effect = tempest.TempestSetupFailure + + task = objects.Task(deployment_uuid='deployment-uuid') + validator = self._unwrap_validator(validation.tempest_tests_exists) + + result = validator({"args": {"test_name": "a"}}, None, task) + self.assertFalse(result.is_valid, result.msg) + mock_tempest().is_installed.assert_called_once_with() + def test_tempest_set_exists_missing_args(self): validator = self._unwrap_validator(validation.tempest_set_exists) result = validator({}, None, None) diff --git a/tests/unit/verification/verifiers/test_tempest.py b/tests/unit/verification/verifiers/test_tempest.py index eb4e274187..725b655523 100644 --- a/tests/unit/verification/verifiers/test_tempest.py +++ b/tests/unit/verification/verifiers/test_tempest.py @@ -100,10 +100,10 @@ class TempestUtilsTestCase(BaseTestCase): mock_isdir.assert_called_once_with(self.verifier.path(".venv")) mock_sp.assert_has_calls([ mock.call("python ./tools/install_venv.py", shell=True, - cwd=self.verifier.path()), + cwd=self.verifier.path(), stderr=subprocess.STDOUT), mock.call("%s python setup.py install" % self.verifier.venv_wrapper, shell=True, - cwd=self.verifier.path())]) + cwd=self.verifier.path(), stderr=subprocess.STDOUT)]) @mock.patch("os.path.isdir", return_value=False) @testtools.skipIf(sys.version_info >= (2, 7), @@ -124,8 +124,9 @@ class TempestUtilsTestCase(BaseTestCase): self.verifier.path(".testrepository")) self.assertFalse(mock_sp.called) + @testtools.skipIf(sys.version_info < (2, 7), "Incompatible Python Version") @mock.patch("os.path.isdir", return_value=False) - @mock.patch(TEMPEST_PATH + ".tempest.subprocess.check_call") + @mock.patch(TEMPEST_PATH + ".tempest.subprocess.check_output") def test__initialize_testr_when_testr_not_initialized( self, mock_sp, mock_isdir): self.verifier._initialize_testr() @@ -134,7 +135,7 @@ class TempestUtilsTestCase(BaseTestCase): self.verifier.path(".testrepository")) mock_sp.assert_called_once_with( '%s testr init' % self.verifier.venv_wrapper, shell=True, - cwd=self.verifier.path()) + cwd=self.verifier.path(), stderr=subprocess.STDOUT) @mock.patch.object(subunit2json, 'main') @mock.patch('os.path.isfile', return_value=False)