Add mechanism driver error details to MechanismDriverError
Now the ML2 core plugin maps driver errors to MechanismDriverError and hides the error details from the caller. This patch change MechanismDriverError from an instance of NeutronException to an instance of MultipleExceptions. Add add exceptions from mechanism driver as inner_exceptions of MultipleExceptions. As a result, the api layer will unwrap the MechanismDriverError and return the real error to client. Change-Id: I3a46932848d59f7f027640bfb598650f064b0a12 Closes-bug: #1273730
This commit is contained in:
parent
665fd24623
commit
8398ec0d77
|
@ -18,11 +18,18 @@
|
|||
from neutron_lib import exceptions
|
||||
|
||||
from neutron._i18n import _
|
||||
from neutron.common import exceptions as n_exc
|
||||
|
||||
|
||||
class MechanismDriverError(exceptions.NeutronException):
|
||||
class MechanismDriverError(n_exc.MultipleExceptions):
|
||||
"""Mechanism driver call failed."""
|
||||
message = _("%(method)s failed.")
|
||||
|
||||
def __init__(self, method, errors=None):
|
||||
# The message is not used by api, because api will unwrap
|
||||
# MultipleExceptions and return inner exceptions. Keep it
|
||||
# for backward-compatibility, in case other code use it.
|
||||
self.message = _("%s failed.") % method
|
||||
super(MechanismDriverError, self).__init__(errors)
|
||||
|
||||
|
||||
class ExtensionDriverError(exceptions.InvalidInput):
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
# under the License.
|
||||
|
||||
from neutron_lib import constants as const
|
||||
from neutron_lib import exceptions
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from neutron._i18n import _LW
|
||||
from neutron._i18n import _, _LW
|
||||
from neutron import context as n_context
|
||||
from neutron.db import api as db_api
|
||||
from neutron.plugins.ml2.common import exceptions as ml2_exc
|
||||
from neutron.plugins.ml2 import driver_api as api
|
||||
from neutron.plugins.ml2.drivers.l2pop import config # noqa
|
||||
from neutron.plugins.ml2.drivers.l2pop import db as l2pop_db
|
||||
|
@ -114,9 +114,9 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
|||
|
||||
if (orig['mac_address'] != port['mac_address'] and
|
||||
context.status == const.PORT_STATUS_ACTIVE):
|
||||
LOG.warning(_LW("unable to modify mac_address of ACTIVE port "
|
||||
"%s"), port['id'])
|
||||
raise ml2_exc.MechanismDriverError(method='update_port_precommit')
|
||||
msg = _("unable to modify mac_address of ACTIVE port "
|
||||
"%s") % port['id']
|
||||
raise exceptions.InvalidInput(error_message=msg)
|
||||
|
||||
def update_port_postcommit(self, context):
|
||||
port = context.current
|
||||
|
|
|
@ -404,7 +404,7 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
|
|||
raise_db_retriable=False. See neutron.db.api.is_retriable for
|
||||
what db exception is retriable
|
||||
"""
|
||||
error = False
|
||||
errors = []
|
||||
for driver in self.ordered_mech_drivers:
|
||||
try:
|
||||
getattr(driver.obj, method_name)(context)
|
||||
|
@ -419,12 +419,13 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
|
|||
_LE("Mechanism driver '%(name)s' failed in %(method)s"),
|
||||
{'name': driver.name, 'method': method_name}
|
||||
)
|
||||
error = True
|
||||
errors.append(e)
|
||||
if not continue_on_failure:
|
||||
break
|
||||
if error:
|
||||
if errors:
|
||||
raise ml2_exc.MechanismDriverError(
|
||||
method=method_name
|
||||
method=method_name,
|
||||
errors=errors
|
||||
)
|
||||
|
||||
def create_network_precommit(self, context):
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
import mock
|
||||
from neutron_lib import constants
|
||||
from neutron_lib import exceptions
|
||||
from oslo_serialization import jsonutils
|
||||
import testtools
|
||||
|
||||
|
@ -24,7 +25,6 @@ from neutron import context
|
|||
from neutron.extensions import portbindings
|
||||
from neutron.extensions import providernet as pnet
|
||||
from neutron import manager
|
||||
from neutron.plugins.ml2.common import exceptions as ml2_exc
|
||||
from neutron.plugins.ml2 import driver_context
|
||||
from neutron.plugins.ml2.drivers.l2pop import db as l2pop_db
|
||||
from neutron.plugins.ml2.drivers.l2pop import mech_driver as l2pop_mech_driver
|
||||
|
@ -1022,5 +1022,5 @@ class TestL2PopulationMechDriver(base.BaseTestCase):
|
|||
original_port=original_port)
|
||||
|
||||
mech_driver = l2pop_mech_driver.L2populationMechanismDriver()
|
||||
with testtools.ExpectedException(ml2_exc.MechanismDriverError):
|
||||
with testtools.ExpectedException(exceptions.InvalidInput):
|
||||
mech_driver.update_port_precommit(ctx)
|
||||
|
|
|
@ -1991,18 +1991,22 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||
|
||||
def test_create_network_faulty(self):
|
||||
|
||||
err_msg = "Some errors"
|
||||
with mock.patch.object(mech_test.TestMechanismDriver,
|
||||
'create_network_postcommit',
|
||||
side_effect=ml2_exc.MechanismDriverError):
|
||||
side_effect=(exc.InvalidInput(
|
||||
error_message=err_msg))):
|
||||
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(500, res.status_int)
|
||||
self.assertEqual(400, res.status_int)
|
||||
error = self.deserialize(self.fmt, res)
|
||||
self.assertEqual('MechanismDriverError',
|
||||
self.assertEqual('InvalidInput',
|
||||
error['NeutronError']['type'])
|
||||
# Check the client can see the root cause of error.
|
||||
self.assertIn(err_msg, error['NeutronError']['message'])
|
||||
query_params = "tenant_id=%s" % tenant_id
|
||||
nets = self._list('networks', query_params=query_params)
|
||||
self.assertFalse(nets['networks'])
|
||||
|
@ -2032,9 +2036,11 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||
|
||||
def test_update_network_faulty(self):
|
||||
|
||||
err_msg = "Some errors"
|
||||
with mock.patch.object(mech_test.TestMechanismDriver,
|
||||
'update_network_postcommit',
|
||||
side_effect=ml2_exc.MechanismDriverError):
|
||||
side_effect=(exc.InvalidInput(
|
||||
error_message=err_msg))):
|
||||
with mock.patch.object(mech_logger.LoggerMechanismDriver,
|
||||
'update_network_postcommit') as unp:
|
||||
|
||||
|
@ -2050,10 +2056,12 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||
data = {'network': {'name': new_name}}
|
||||
req = self.new_update_request('networks', data, net_id)
|
||||
res = req.get_response(self.api)
|
||||
self.assertEqual(500, res.status_int)
|
||||
self.assertEqual(400, res.status_int)
|
||||
error = self.deserialize(self.fmt, res)
|
||||
self.assertEqual('MechanismDriverError',
|
||||
self.assertEqual('InvalidInput',
|
||||
error['NeutronError']['type'])
|
||||
# Check the client can see the root cause of error.
|
||||
self.assertIn(err_msg, error['NeutronError']['message'])
|
||||
# Test if other mechanism driver was called
|
||||
self.assertTrue(unp.called)
|
||||
net = self._show('networks', net_id)
|
||||
|
@ -2063,9 +2071,11 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||
|
||||
def test_create_subnet_faulty(self):
|
||||
|
||||
err_msg = "Some errors"
|
||||
with mock.patch.object(mech_test.TestMechanismDriver,
|
||||
'create_subnet_postcommit',
|
||||
side_effect=ml2_exc.MechanismDriverError):
|
||||
side_effect=(exc.InvalidInput(
|
||||
error_message=err_msg))):
|
||||
|
||||
with self.network() as network:
|
||||
net_id = network['network']['id']
|
||||
|
@ -2078,10 +2088,12 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||
'gateway_ip': '10.0.20.1'}}
|
||||
req = self.new_create_request('subnets', data)
|
||||
res = req.get_response(self.api)
|
||||
self.assertEqual(500, res.status_int)
|
||||
self.assertEqual(400, res.status_int)
|
||||
error = self.deserialize(self.fmt, res)
|
||||
self.assertEqual('MechanismDriverError',
|
||||
self.assertEqual('InvalidInput',
|
||||
error['NeutronError']['type'])
|
||||
# Check the client can see the root cause of error.
|
||||
self.assertIn(err_msg, error['NeutronError']['message'])
|
||||
query_params = "network_id=%s" % net_id
|
||||
subnets = self._list('subnets', query_params=query_params)
|
||||
self.assertFalse(subnets['subnets'])
|
||||
|
@ -2119,9 +2131,11 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||
|
||||
def test_update_subnet_faulty(self):
|
||||
|
||||
err_msg = "Some errors"
|
||||
with mock.patch.object(mech_test.TestMechanismDriver,
|
||||
'update_subnet_postcommit',
|
||||
side_effect=ml2_exc.MechanismDriverError):
|
||||
side_effect=(exc.InvalidInput(
|
||||
error_message=err_msg))):
|
||||
with mock.patch.object(mech_logger.LoggerMechanismDriver,
|
||||
'update_subnet_postcommit') as usp:
|
||||
|
||||
|
@ -2143,10 +2157,12 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||
data = {'subnet': {'name': new_name}}
|
||||
req = self.new_update_request('subnets', data, subnet_id)
|
||||
res = req.get_response(self.api)
|
||||
self.assertEqual(500, res.status_int)
|
||||
self.assertEqual(400, res.status_int)
|
||||
error = self.deserialize(self.fmt, res)
|
||||
self.assertEqual('MechanismDriverError',
|
||||
self.assertEqual('InvalidInput',
|
||||
error['NeutronError']['type'])
|
||||
# Check the client can see the root cause of error.
|
||||
self.assertIn(err_msg, error['NeutronError']['message'])
|
||||
# Test if other mechanism driver was called
|
||||
self.assertTrue(usp.called)
|
||||
subnet = self._show('subnets', subnet_id)
|
||||
|
@ -2156,9 +2172,11 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||
|
||||
def test_create_port_faulty(self):
|
||||
|
||||
err_msg = "Some errors"
|
||||
with mock.patch.object(mech_test.TestMechanismDriver,
|
||||
'create_port_postcommit',
|
||||
side_effect=ml2_exc.MechanismDriverError):
|
||||
side_effect=(exc.InvalidInput(
|
||||
error_message=err_msg))):
|
||||
|
||||
with self.network() as network:
|
||||
net_id = network['network']['id']
|
||||
|
@ -2170,10 +2188,12 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||
'fixed_ips': []}}
|
||||
req = self.new_create_request('ports', data)
|
||||
res = req.get_response(self.api)
|
||||
self.assertEqual(500, res.status_int)
|
||||
self.assertEqual(400, res.status_int)
|
||||
error = self.deserialize(self.fmt, res)
|
||||
self.assertEqual('MechanismDriverError',
|
||||
self.assertEqual('InvalidInput',
|
||||
error['NeutronError']['type'])
|
||||
# Check the client can see the root cause of error.
|
||||
self.assertIn(err_msg, error['NeutronError']['message'])
|
||||
query_params = "network_id=%s" % net_id
|
||||
ports = self._list('ports', query_params=query_params)
|
||||
self.assertFalse(ports['ports'])
|
||||
|
|
Loading…
Reference in New Issue