Pass the extension driver exception to plugin
The extension driver is intercepted by driver manager currently. It will cover the errors/exceptions happened in extension drivers. The extension process will continue even if preceding extension driver get a wrong/useless extended result, or even no result. This patch make process_[create|update]_<resource>() and extend_<resource>_dict() methods return the exception, and log it with proper level respectively, and also include a minor optimization for the extend_<resource>_dict() methods. Change-Id: I20a249c47b58292125476bc44b2372ca959509e3 Closes-Bug: #1468990
This commit is contained in:
parent
6ee7b12d94
commit
73845d564c
|
@ -21,3 +21,8 @@ from neutron.common import exceptions
|
|||
class MechanismDriverError(exceptions.NeutronException):
|
||||
"""Mechanism driver call failed."""
|
||||
message = _("%(method)s failed.")
|
||||
|
||||
|
||||
class ExtensionDriverError(exceptions.InvalidInput):
|
||||
"""Extension driver call failed."""
|
||||
message = _("Extension %(driver)s failed.")
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_utils import excutils
|
||||
import six
|
||||
import stevedore
|
||||
|
||||
|
@ -764,10 +765,10 @@ class ExtensionManager(stevedore.named.NamedExtensionManager):
|
|||
try:
|
||||
getattr(driver.obj, method_name)(plugin_context, data, result)
|
||||
except Exception:
|
||||
LOG.exception(
|
||||
_LE("Extension driver '%(name)s' failed in %(method)s"),
|
||||
{'name': driver.name, 'method': method_name}
|
||||
)
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.info(_LI("Extension driver '%(name)s' failed in "
|
||||
"%(method)s"),
|
||||
{'name': driver.name, 'method': method_name})
|
||||
|
||||
def process_create_network(self, plugin_context, data, result):
|
||||
"""Notify all extension drivers during network creation."""
|
||||
|
@ -799,23 +800,30 @@ class ExtensionManager(stevedore.named.NamedExtensionManager):
|
|||
self._call_on_ext_drivers("process_update_port", plugin_context,
|
||||
data, result)
|
||||
|
||||
def _call_on_dict_driver(self, method_name, session, base_model, result):
|
||||
for driver in self.ordered_ext_drivers:
|
||||
try:
|
||||
getattr(driver.obj, method_name)(session, base_model, result)
|
||||
except Exception:
|
||||
LOG.error(_LE("Extension driver '%(name)s' failed in "
|
||||
"%(method)s"),
|
||||
{'name': driver.name, 'method': method_name})
|
||||
raise ml2_exc.ExtensionDriverError(driver=driver.name)
|
||||
|
||||
LOG.debug("%(method)s succeeded for driver %(driver)s",
|
||||
{'method': method_name, 'driver': driver.name})
|
||||
|
||||
def extend_network_dict(self, session, base_model, result):
|
||||
"""Notify all extension drivers to extend network dictionary."""
|
||||
for driver in self.ordered_ext_drivers:
|
||||
driver.obj.extend_network_dict(session, base_model, result)
|
||||
LOG.debug("Extended network dict for driver '%(drv)s'",
|
||||
{'drv': driver.name})
|
||||
self._call_on_dict_driver("extend_network_dict", session, base_model,
|
||||
result)
|
||||
|
||||
def extend_subnet_dict(self, session, base_model, result):
|
||||
"""Notify all extension drivers to extend subnet dictionary."""
|
||||
for driver in self.ordered_ext_drivers:
|
||||
driver.obj.extend_subnet_dict(session, base_model, result)
|
||||
LOG.debug("Extended subnet dict for driver '%(drv)s'",
|
||||
{'drv': driver.name})
|
||||
self._call_on_dict_driver("extend_subnet_dict", session, base_model,
|
||||
result)
|
||||
|
||||
def extend_port_dict(self, session, base_model, result):
|
||||
"""Notify all extension drivers to extend port dictionary."""
|
||||
for driver in self.ordered_ext_drivers:
|
||||
driver.obj.extend_port_dict(session, base_model, result)
|
||||
LOG.debug("Extended port dict for driver '%(drv)s'",
|
||||
{'drv': driver.name})
|
||||
self._call_on_dict_driver("extend_port_dict", session, base_model,
|
||||
result)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# under the License.
|
||||
|
||||
import mock
|
||||
import uuid
|
||||
|
||||
from neutron import context
|
||||
from neutron import manager
|
||||
|
@ -31,6 +32,58 @@ class ExtensionDriverTestCase(test_plugin.Ml2PluginV2TestCase):
|
|||
self._plugin = manager.NeutronManager.get_plugin()
|
||||
self._ctxt = context.get_admin_context()
|
||||
|
||||
def _verify_network_create(self, code, exc_reason):
|
||||
tenant_id = str(uuid.uuid4())
|
||||
data = {'network': {'name': 'net1',
|
||||
'tenant_id': tenant_id}}
|
||||
req = self.new_create_request('networks', data)
|
||||
res = req.get_response(self.api)
|
||||
self.assertEqual(code, res.status_int)
|
||||
|
||||
network = self.deserialize(self.fmt, res)
|
||||
if exc_reason:
|
||||
self.assertEqual(exc_reason,
|
||||
network['NeutronError']['type'])
|
||||
|
||||
return (network, tenant_id)
|
||||
|
||||
def _verify_network_update(self, network, code, exc_reason):
|
||||
net_id = network['network']['id']
|
||||
new_name = 'a_brand_new_name'
|
||||
data = {'network': {'name': new_name}}
|
||||
req = self.new_update_request('networks', data, net_id)
|
||||
res = req.get_response(self.api)
|
||||
self.assertEqual(code, res.status_int)
|
||||
error = self.deserialize(self.fmt, res)
|
||||
self.assertEqual(exc_reason,
|
||||
error['NeutronError']['type'])
|
||||
|
||||
def test_faulty_process_create(self):
|
||||
with mock.patch.object(ext_test.TestExtensionDriver,
|
||||
'process_create_network',
|
||||
side_effect=TypeError):
|
||||
net, tenant_id = self._verify_network_create(500,
|
||||
'HTTPInternalServerError')
|
||||
# Verify the operation is rolled back
|
||||
query_params = "tenant_id=%s" % tenant_id
|
||||
nets = self._list('networks', query_params=query_params)
|
||||
self.assertFalse(nets['networks'])
|
||||
|
||||
def test_faulty_process_update(self):
|
||||
with mock.patch.object(ext_test.TestExtensionDriver,
|
||||
'process_update_network',
|
||||
side_effect=TypeError):
|
||||
network, tid = self._verify_network_create(201, None)
|
||||
self._verify_network_update(network, 500,
|
||||
'HTTPInternalServerError')
|
||||
|
||||
def test_faulty_extend_dict(self):
|
||||
with mock.patch.object(ext_test.TestExtensionDriver,
|
||||
'extend_network_dict',
|
||||
side_effect=TypeError):
|
||||
network, tid = self._verify_network_create(201, None)
|
||||
self._verify_network_update(network, 400, 'ExtensionDriverError')
|
||||
|
||||
def test_network_attr(self):
|
||||
with self.network() as network:
|
||||
# Test create network
|
||||
|
|
Loading…
Reference in New Issue