Merge "Refactor exceptions"

This commit is contained in:
Jenkins 2017-05-20 22:19:16 +00:00 committed by Gerrit Code Review
commit 0959b59b2f
26 changed files with 173 additions and 110 deletions

View File

@ -49,10 +49,12 @@ LOG = logging.getLogger(__name__)
class FailedToLoadTask(exceptions.RallyException):
error_code = 472
msg_fmt = _("Invalid %(source)s passed:\n\n\t %(msg)s")
class FailedToLoadResults(exceptions.RallyException):
error_code = 529
msg_fmt = _("ERROR: Invalid task result format in %(source)s\n\n\t%(msg)s")

View File

@ -32,7 +32,7 @@ import uuid
from six import moves
from rally.common.i18n import _LE
from rally.common.i18n import _, _LE
from rally.common import logging
from rally import exceptions
@ -47,7 +47,7 @@ class ImmutableMixin(object):
def __setattr__(self, key, value):
if self._inited:
raise exceptions.ImmutableException()
raise AttributeError(_("This object is immutable."))
super(ImmutableMixin, self).__setattr__(key, value)

View File

@ -16,6 +16,10 @@
import six
from rally.common.i18n import _
from rally.common.plugin import discover
_exception_map = None
class RallyException(Exception):
@ -27,6 +31,7 @@ class RallyException(Exception):
"""
msg_fmt = _("%(message)s")
error_code = 500
def __init__(self, message=None, **kwargs):
self.kwargs = kwargs
@ -40,32 +45,44 @@ class RallyException(Exception):
return six.text_type(self)
class ImmutableException(RallyException):
msg_fmt = _("This object is immutable.")
def find_exception(response):
"""Discover a proper exception class based on response object."""
global _exception_map
if _exception_map is None:
_exception_map = dict(
(e.error_code, e) for e in discover.itersubclasses(RallyException))
exc_class = _exception_map.get(response.status_code, RallyException)
error_data = response.json()["error"]
if error_data["args"]:
return exc_class(error_data["args"])
return exc_class(error_data["msg"])
def make_exception(exc):
"""Check a class of exception and convert it to rally-like if needed."""
if isinstance(exc, RallyException):
return exc
return RallyException(str(exc))
class InvalidArgumentsException(RallyException):
error_code = 455
msg_fmt = _("Invalid arguments: '%(message)s'")
class InvalidConfigException(RallyException):
error_code = 456
msg_fmt = _("This config has invalid schema: `%(message)s`")
class InvalidRunnerResult(RallyException):
msg_fmt = _("Type of result of `%(name)s` runner should be"
" `base.ScenarioRunnerResult`. Got: `%(results_type)s`")
class InvalidTaskException(InvalidConfigException):
error_code = 457
msg_fmt = _("Task config is invalid: `%(message)s`")
class NotFoundScenarios(InvalidTaskException):
msg_fmt = _("There are no benchmark scenarios with names: `%(names)s`.")
class InvalidTaskConfig(InvalidTaskException):
error_code = 458
msg_fmt = _("Input task is invalid!\n\n"
"Subtask %(name)s[%(pos)s] has wrong configuration"
"\nSubtask configuration:\n%(config)s\n"
@ -73,51 +90,52 @@ class InvalidTaskConfig(InvalidTaskException):
class NotFoundException(RallyException):
error_code = 404
msg_fmt = _("The resource can not be found: %(message)s")
class ThreadTimeoutException(RallyException):
error_code = 515
msg_fmt = _("Iteration interrupted due to timeout.")
class PluginNotFound(NotFoundException):
error_code = 459
msg_fmt = _("There is no plugin with name: `%(name)s` in "
"%(namespace)s namespace.")
class PluginWithSuchNameExists(RallyException):
error_code = 516
msg_fmt = _("Plugin with such name: %(name)s already exists in "
"%(namespace)s namespace. It's module allocates at "
"%(existing_path)s. You are trying to add plugin whose module "
"allocates at %(new_path)s.")
class NoSuchConfigField(NotFoundException):
msg_fmt = _("There is no field in the task config with name `%(name)s`.")
class NoSuchRole(NotFoundException):
msg_fmt = _("There is no role with name `%(role)s`.")
class TaskNotFound(NotFoundException):
error_code = 460
msg_fmt = _("Task with uuid=%(uuid)s not found.")
class DeploymentNotFound(NotFoundException):
error_code = 461
msg_fmt = _("Deployment %(deployment)s not found.")
class DeploymentNameExists(RallyException):
error_code = 462
msg_fmt = _("Deployment name '%(deployment)s' already registered.")
class DeploymentNotFinishedStatus(RallyException):
error_code = 463
msg_fmt = _("Deployment '%(name)s' (UUID=%(uuid)s) is in"
" '%(status)s' status.")
class DeploymentIsBusy(RallyException):
error_code = 464
msg_fmt = _("There are allocated resources for the deployment with "
"uuid=%(uuid)s.")
@ -127,24 +145,29 @@ class RallyAssertionError(RallyException):
class ResourceNotFound(NotFoundException):
error_code = 465
msg_fmt = _("Resource with id=%(id)s not found.")
class TimeoutException(RallyException):
error_code = 517
msg_fmt = _("Rally tired waiting for %(resource_type)s %(resource_name)s:"
"%(resource_id)s to become %(desired_status)s current "
"status %(resource_status)s")
class GetResourceFailure(RallyException):
error_code = 518
msg_fmt = _("Failed to get the resource %(resource)s: %(err)s")
class GetResourceNotFound(GetResourceFailure):
error_code = 519
msg_fmt = _("Resource %(resource)s is not found.")
class GetResourceErrorStatus(GetResourceFailure):
error_code = 520
msg_fmt = _("Resource %(resource)s has %(status)s status.\n"
"Fault: %(fault)s")
@ -154,94 +177,54 @@ class ScriptError(RallyException):
class TaskInvalidStatus(RallyException):
error_code = 466
msg_fmt = _("Task `%(uuid)s` in `%(actual)s` status but `%(require)s` is "
"required.")
class ChecksumMismatch(RallyException):
msg_fmt = _("Checksum mismatch for image: %(url)s")
class InvalidAdminException(InvalidArgumentsException):
error_code = 521
msg_fmt = _("user '%(username)s' doesn't have 'admin' role")
class InvalidEndpointsException(InvalidArgumentsException):
error_code = 522
msg_fmt = _("wrong keystone credentials specified in your endpoint"
" properties. (HTTP 401)")
class HostUnreachableException(InvalidArgumentsException):
error_code = 523
msg_fmt = _("unable to establish connection to the remote host: %(url)s")
class InvalidScenarioArgument(RallyException):
error_code = 467
msg_fmt = _("Invalid scenario argument: '%(message)s'")
class BenchmarkSetupFailure(RallyException):
msg_fmt = _("Unable to setup benchmark: '%(message)s'")
class ContextSetupFailure(RallyException):
error_code = 524
msg_fmt = _("Unable to setup context '%(ctx_name)s': '%(msg)s'")
class ValidationError(RallyException):
error_code = 468
msg_fmt = _("Validation error: %(message)s")
class NoNodesFound(RallyException):
msg_fmt = _("There is no nodes matching filters: %(filters)r")
class UnknownRelease(RallyException):
msg_fmt = _("Unknown release '%(release)s'")
class CleanUpException(RallyException):
msg_fmt = _("Cleanup failed.")
class ImageCleanUpException(CleanUpException):
msg_fmt = _("Image Deletion Failed")
class EncryptionTypeDeleteException(CleanUpException):
msg_fmt = _("EncryptionType Deletion Failed")
class IncompatiblePythonVersion(RallyException):
msg_fmt = _("Incompatible python version found '%(version)s', "
"required '%(required_version)s'")
class WorkerNotFound(NotFoundException):
error_code = 469
msg_fmt = _("Worker %(worker)s could not be found")
class WorkerAlreadyRegistered(RallyException):
error_code = 525
msg_fmt = _("Worker %(worker)s already registered")
class SaharaClusterFailure(RallyException):
msg_fmt = _("Sahara cluster %(name)s has failed to %(action)s. "
"Reason: '%(reason)s'")
class LiveMigrateException(RallyException):
msg_fmt = _("Live Migration failed: %(message)s")
class MigrateException(RallyException):
msg_fmt = _("Migration failed: %(message)s")
class InvalidHostException(RallyException):
msg_fmt = _("Live Migration failed: %(message)s")
class MultipleMatchesFound(RallyException):
error_code = 470
msg_fmt = _("Found multiple %(needle)s: %(haystack)s")
def __init__(self, **kwargs):
@ -251,17 +234,21 @@ class MultipleMatchesFound(RallyException):
class SSHTimeout(RallyException):
error_code = 526
pass
class SSHError(RallyException):
error_code = 527
pass
class InvalidConnectionString(RallyException):
error_code = 471
msg_fmt = _("The connection string is not valid: %(message)s. Please "
"check your connection string.")
class DowngradeNotSupported(RallyException):
error_code = 528
msg_fmt = _("Database schema downgrade is not supported.")

View File

@ -24,6 +24,7 @@ from rally.task import scenario
class DummyScenarioException(exceptions.RallyException):
error_code = 530
msg_fmt = _("Dummy scenario expected exception: '%(message)s'")

View File

@ -244,9 +244,10 @@ class OpenStackAPIVersions(context.Context):
% conf["service_type"])
elif "service_name" in conf:
if not self.context.get("admin", {}).get("credential"):
raise exceptions.BenchmarkSetupFailure(_(
"Setting 'service_name' is allowed only for 'admin' "
"user."))
raise exceptions.ContextSetupFailure(
ctx_name=self.get_name(),
msg=_("Setting 'service_name' is allowed"
" only for 'admin' user."))
if not services_from_admin:
services_from_admin = dict(
[(s.name, s.type)

View File

@ -61,7 +61,8 @@ class RoleGenerator(context.Context):
if str(def_role.name) == context_role:
return def_role
else:
raise exceptions.NoSuchRole(role=context_role)
raise exceptions.NotFoundException(_(
"There is no role with name `%s`") % context_role)
def _get_consumer(self, func_name):
def consume(cache, args):

View File

@ -170,9 +170,13 @@ class SaharaCluster(context.Context):
for cluster, client in dct.items():
cluster_status = cluster.status.lower()
if cluster_status == "error":
raise exceptions.SaharaClusterFailure(
name=cluster.name, action="start",
reason=cluster.status_description)
msg = _("Sahara cluster %(name)s has failed to"
" %(action)s. Reason: '%(reason)s'") % {
"name": cluster.name, "action": "start",
"reason": cluster.status_description}
raise exceptions.ContextSetupFailure(
ctx_name=self.get_name(),
msg=msg)
elif cluster_status != "active":
return False
return True

View File

@ -104,8 +104,11 @@ class SaharaImage(context.Context):
visibility = image["visibility"]
if visibility != "public":
raise exceptions.BenchmarkSetupFailure(
"Image provided in the Sahara context should be public.")
raise exceptions.ContextSetupFailure(
ctx_name=self.get_name(),
msg=_("Image provided in the Sahara context"
" should be public.")
)
image_id = image_uuid
for user, tenant_id in rutils.iterate_per_tenants(

View File

@ -17,6 +17,7 @@ import random
from oslo_config import cfg
from rally.common.i18n import _
from rally import exceptions
from rally.plugins.openstack import scenario
from rally.plugins.openstack.services.storage import block
@ -496,4 +497,5 @@ class CinderScenario(scenario.OpenStackScenario):
resp = self.admin_clients("cinder").volume_encryption_types.delete(
volume_type)
if (resp[0].status_code != 202):
raise exceptions.EncryptionTypeDeleteException()
raise exceptions.RallyException(
_("EncryptionType Deletion Failed"))

View File

@ -17,6 +17,7 @@ import random
from oslo_config import cfg
from rally.common.i18n import _
from rally.common import logging
from rally import exceptions
from rally.plugins.openstack import scenario
@ -727,9 +728,9 @@ class NovaScenario(scenario.OpenStackScenario):
server_admin = self.admin_clients("nova").servers.get(server.id)
if (host_pre_migrate == getattr(server_admin, "OS-EXT-SRV-ATTR:host")
and not skip_host_check):
raise exceptions.LiveMigrateException(
"Migration complete but instance did not change host: %s" %
host_pre_migrate)
raise exceptions.RallyException(_(
"Live Migration failed: Migration complete "
"but instance did not change host: %s") % host_pre_migrate)
@atomic.action_timer("nova.find_host_to_migrate")
def _find_host_to_migrate(self, server):
@ -752,8 +753,8 @@ class NovaScenario(scenario.OpenStackScenario):
value.get("nova-compute", {}).get("available", False)])
return new_host
except IndexError:
raise exceptions.InvalidHostException(
"No valid host found to migrate")
raise exceptions.RallyException(
_("Live Migration failed: No valid host found to migrate"))
@atomic.action_timer("nova.migrate")
def _migrate(self, server, skip_host_check=False):
@ -778,9 +779,9 @@ class NovaScenario(scenario.OpenStackScenario):
server_admin = self.admin_clients("nova").servers.get(server.id)
host_after_migrate = getattr(server_admin, "OS-EXT-SRV-ATTR:host")
if host_pre_migrate == host_after_migrate:
raise exceptions.MigrateException(
"Migration complete but instance did not change host: %s" %
host_pre_migrate)
raise exceptions.RallyException(
_("Migration failed: Migration complete but instance"
" did not change host: %s") % host_pre_migrate)
@atomic.optional_action_timer("nova.add_server_secgroups")
def _add_server_secgroups(self, server, security_group,

View File

@ -125,9 +125,10 @@ class SaharaScenario(scenario.OpenStackScenario):
if net["name"] == name_or_id:
return net["id"]
# If the name is not found in the list. Exit with error.
raise exceptions.BenchmarkSetupFailure(
"Could not resolve Floating IP Pool name %s to id" %
name_or_id)
raise exceptions.ContextSetupFailure(
ctx_name=self.get_name(),
msg=_("Could not resolve Floating IP Pool"
" name %s to id") % name_or_id)
else:
# Pool is not provided. Using the one set as GW for current router.

View File

@ -127,8 +127,9 @@ class UnifiedGlanceV1Service(glance_common.UnifiedGlanceMixin, image.Image):
def _check_v1_visibility(visibility):
visibility_values = ["public", "private"]
if visibility and visibility not in visibility_values:
raise image.VisibilityException("Improper visibility value: %s "
"in glance_v1" % visibility)
raise image.VisibilityException(
message="Improper visibility value: %s in glance_v1"
% visibility)
def create_image(self, image_name=None, container_format=None,
image_location=None, disk_format=None,

View File

@ -146,8 +146,9 @@ class UnifiedGlanceV2Service(glance_common.UnifiedGlanceMixin, image.Image):
def _check_v2_visibility(visibility):
visibility_values = ["public", "private", "shared", "community"]
if visibility and visibility not in visibility_values:
raise image.VisibilityException("Improper visibility value: %s "
"in glance_v2" % visibility)
raise image.VisibilityException(
message="Improper visibility value: %s in glance_v2"
% visibility)
def create_image(self, image_name=None, container_format=None,
image_location=None, disk_format=None,

View File

@ -13,6 +13,7 @@
import collections
from rally import exceptions
from rally.task import service
from oslo_config import cfg
@ -23,16 +24,18 @@ UnifiedImage = collections.namedtuple("Image", ["id", "name", "visibility",
"status"])
class VisibilityException(Exception):
class VisibilityException(exceptions.RallyException):
"""Wrong visibility value exception.
"""
error_code = 531
class RemovePropsException(Exception):
class RemovePropsException(exceptions.RallyException):
"""Remove Props it not supported exception.
"""
error_code = 560
class Image(service.UnifiedService):

View File

@ -14,6 +14,7 @@
import random
from rally.common.i18n import _
from rally import exceptions
from rally.plugins.openstack.services.image import image
from rally.plugins.openstack.services.storage import block
@ -411,7 +412,8 @@ class CinderMixin(object):
resp = self._get_client().volume_encryption_types.delete(
volume_type)
if (resp[0].status_code != 202):
raise exceptions.EncryptionTypeDeleteException()
raise exceptions.RallyException(
_("EncryptionType Deletion Failed"))
def update_encryption_type(self, volume_type, specs):
"""Update the encryption type information for the specified volume type.

View File

@ -49,6 +49,7 @@ def generate_cidr(start_cidr="10.2.0.0/24"):
class NetworkWrapperException(exceptions.RallyException):
error_code = 532
msg_fmt = _("%(message)s")

View File

@ -43,6 +43,7 @@ URL_RE = re.compile(
class VerifierSetupFailure(exceptions.RallyException):
error_code = 533
msg_fmt = "Failed to set up verifier '%(verifier)s': %(message)s"

View File

@ -33,7 +33,7 @@ class ImmutableMixinTestCase(test.TestCase):
def test_without_base_values(self):
im = utils.ImmutableMixin()
self.assertRaises(exceptions.ImmutableException,
self.assertRaises(AttributeError,
im.__setattr__, "test", "test")
def test_with_base_values(self):
@ -44,7 +44,7 @@ class ImmutableMixinTestCase(test.TestCase):
super(A, self).__init__()
a = A("test")
self.assertRaises(exceptions.ImmutableException,
self.assertRaises(AttributeError,
a.__setattr__, "abc", "test")
self.assertEqual(a.test, "test")

View File

@ -71,10 +71,11 @@ class RoleGeneratorTestCase(test.TestCase):
{"id": "u2", "tenant_id": "t2"}]
ctx.config = ["unknown_role"]
ctx.credential = mock.MagicMock()
ex = self.assertRaises(exceptions.NoSuchRole, ctx._get_role_object,
"unknown_role")
ex = self.assertRaises(exceptions.NotFoundException,
ctx._get_role_object, "unknown_role")
expected = "There is no role with name `unknown_role`."
expected = ("The resource can not be found: There is no role "
"with name `unknown_role`")
self.assertEqual(expected, str(ex))
@mock.patch("%s.osclients" % CTX)

View File

@ -146,4 +146,4 @@ class SaharaClusterTestCase(test.ScenarioTestCase):
mock.MagicMock(status="error")
]
self.assertRaises(exceptions.SaharaClusterFailure, sahara_ctx.setup)
self.assertRaises(exceptions.ContextSetupFailure, sahara_ctx.setup)

View File

@ -178,7 +178,7 @@ class SaharaImageTestCase(test.ScenarioTestCase):
ctx = self.existing_image_context
sahara_ctx = sahara_image.SaharaImage(ctx)
self.assertRaises(exceptions.BenchmarkSetupFailure,
self.assertRaises(exceptions.ContextSetupFailure,
sahara_ctx.setup)
mock_glance_create_client.images.get.asser_called_once_with("some_id")

View File

@ -67,7 +67,7 @@ class OpenStackServicesTestCase(test.TestCase):
"nova": {"service_name": "service_name"}}},
"users": [{"credential": mock.MagicMock()}]}
ctx = api_versions.OpenStackAPIVersions(context_obj)
self.assertRaises(exceptions.BenchmarkSetupFailure, ctx.setup)
self.assertRaises(exceptions.ContextSetupFailure, ctx.setup)
self.service_catalog.get_endpoints.assert_called_once_with()
self.assertFalse(self.mock_kc.services.list.called)

View File

@ -425,7 +425,7 @@ class CinderScenarioTestCase(test.ScenarioTestCase):
def test__delete_encryption_type(self):
volume_type = mock.Mock()
self.assertRaises(exceptions.EncryptionTypeDeleteException,
self.assertRaises(exceptions.RallyException,
self.scenario._delete_encryption_type,
volume_type)

View File

@ -692,7 +692,7 @@ class NovaScenarioTestCase(test.ScenarioTestCase):
self._test_atomic_action_timer(nova_scenario.atomic_actions(),
"nova.migrate")
self.assertRaises(rally_exceptions.MigrateException,
self.assertRaises(rally_exceptions.RallyException,
nova_scenario._migrate,
fake_server, skip_host_check=False)

View File

@ -400,7 +400,7 @@ class CinderMixinTestCase(test.ScenarioTestCase):
def test_delete_encryption_type_raise(self):
resp = mock.MagicMock(status_code=404)
self.cinder.volume_encryption_types.delete.return_value = [resp]
self.assertRaises(exceptions.EncryptionTypeDeleteException,
self.assertRaises(exceptions.RallyException,
self.service.delete_encryption_type, "type")
self.cinder.volume_encryption_types.delete.assert_called_once_with(
"type")

View File

@ -0,0 +1,50 @@
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from rally import exceptions
from tests.unit import test
class ExceptionTestCase(test.TestCase):
@mock.patch("rally.exceptions._exception_map")
def test_find_exception(self, mock__exception_map):
mock_response = mock.Mock()
exc_class = mock.Mock()
mock__exception_map.get.return_value = exc_class
mock_response.json.return_value = {
"error": {"args": "args", "msg": "msg"}
}
exc_instance = exceptions.find_exception(mock_response)
self.assertEqual(exc_instance, exc_class.return_value)
mock__exception_map.reset_mock()
exc_class.reset_mock()
mock_response.reset_mock()
mock_response.json.return_value = {
"error": {"args": None, "msg": "msg"}
}
exc_instance = exceptions.find_exception(mock_response)
self.assertEqual(exc_instance, exc_class.return_value)
def test_make_exception(self):
exc = exceptions.RallyException("exc")
self.assertEqual(exc, exceptions.make_exception(exc))
mock_exc = mock.Mock()
self.assertIsInstance(exceptions.make_exception(mock_exc),
exceptions.RallyException)