From df31ac1f11b8139d8b930d05565003ba74150e82 Mon Sep 17 00:00:00 2001 From: Miguel Angel Ajo Date: Wed, 19 Aug 2015 15:15:21 +0200 Subject: [PATCH] Make NeutronDbObjectDuplicateEntry exception more verbose NeutronObjectDuplicateEntry is an exception derived from Conflict, which is mapped to HTTPConflict. When such exception is thrown during an API layer call, we will provide more detail to the caller about what was exactly duplicated, and for which fields, the information is extracted from the DB exception. NeutronObjectDuplicateEntry is renamed into NeutronDbObjectDuplicate to make clear it is for handling db duplicate exceptions, in the future we could generalize to a base NeutronObjectDuplicate class if we need separate handling for other object backings (mem, keystore, etc). Change-Id: I6ec5883b3456ebc842f3f7bffd8cc924293f5766 --- neutron/objects/base.py | 19 +++++++++++++++---- neutron/tests/unit/objects/test_base.py | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/neutron/objects/base.py b/neutron/objects/base.py index c4bb98f56..371fd896d 100644 --- a/neutron/objects/base.py +++ b/neutron/objects/base.py @@ -13,6 +13,7 @@ import abc from oslo_db import exception as obj_exc +from oslo_utils import reflection from oslo_versionedobjects import base as obj_base import six @@ -24,8 +25,16 @@ class NeutronObjectUpdateForbidden(exceptions.NeutronException): message = _("Unable to update the following object fields: %(fields)s") -class NeutronObjectDuplicateEntry(exceptions.Conflict): - message = _("Failed to create a duplicate object") +class NeutronDbObjectDuplicateEntry(exceptions.Conflict): + message = _("Failed to create a duplicate %(object_type)s: " + "for attribute(s) %(attributes)s with value(s) %(values)s") + + def __init__(self, object_class, db_exception): + super(NeutronDbObjectDuplicateEntry, self).__init__( + object_type=reflection.get_class_name(object_class, + fully_qualified=False), + attributes=db_exception.columns, + values=db_exception.value) def get_updatable_fields(cls, fields): @@ -139,8 +148,10 @@ class NeutronDbObject(NeutronObject): fields = self._get_changed_persistent_fields() try: db_obj = db_api.create_object(self._context, self.db_model, fields) - except obj_exc.DBDuplicateEntry: - raise NeutronObjectDuplicateEntry() + except obj_exc.DBDuplicateEntry as db_exc: + raise NeutronDbObjectDuplicateEntry(object_class=self.__class__, + db_exception=db_exc) + self.from_db_object(db_obj) def update(self): diff --git a/neutron/tests/unit/objects/test_base.py b/neutron/tests/unit/objects/test_base.py index 381ff8b29..d447b37ae 100644 --- a/neutron/tests/unit/objects/test_base.py +++ b/neutron/tests/unit/objects/test_base.py @@ -215,7 +215,7 @@ class BaseObjectIfaceTestCase(_BaseObjectTestCase, test_base.BaseTestCase): with mock.patch.object(db_api, 'create_object', side_effect=obj_exc.DBDuplicateEntry): obj = self._test_class(self.context, **self.db_obj) - self.assertRaises(base.NeutronObjectDuplicateEntry, obj.create) + self.assertRaises(base.NeutronDbObjectDuplicateEntry, obj.create) @mock.patch.object(db_api, 'update_object') def test_update_no_changes(self, update_mock): -- 2.45.2