TEMPEST: refactor error handling while installation
Tempest installation doesn't contain enough information for debugging errors, which can be occured during installation. This patch adds: - logging failed command and its output to: `rally.verification.verifiers.tempest.tempest.check_output`; - handling TempestSetupFailure in validation tempest scenarios; - fix in hacking check for logging module. Change-Id: Ida723c6898cb6845459169f387ca36bf280fb644
This commit is contained in:
parent
8d0cde9c7f
commit
e5af73a4d2
@ -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__)
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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"))
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user