diff --git a/neutron/plugins/ml2/managers.py b/neutron/plugins/ml2/managers.py index 7421e4b0f6..a5feb70408 100644 --- a/neutron/plugins/ml2/managers.py +++ b/neutron/plugins/ml2/managers.py @@ -98,6 +98,16 @@ class TypeManager(stevedore.named.NamedExtensionManager): def release_segment(self, session, segment): network_type = segment.get(api.NETWORK_TYPE) driver = self.drivers.get(network_type) + # ML2 may have been reconfigured since the segment was created, + # so a driver may no longer exist for this network_type. + # REVISIT: network_type-specific db entries may become orphaned + # if a network is deleted and the driver isn't available to release + # the segment. This may be fixed with explicit foreign-key references + # or consistency checks on driver initialization. + if not driver: + LOG.error(_("Failed to release segment '%s' because " + "network type is not supported."), segment) + return driver.obj.release_segment(session, segment) diff --git a/neutron/tests/unit/ml2/test_ml2_plugin.py b/neutron/tests/unit/ml2/test_ml2_plugin.py index 408c7ea5b9..da878b4152 100644 --- a/neutron/tests/unit/ml2/test_ml2_plugin.py +++ b/neutron/tests/unit/ml2/test_ml2_plugin.py @@ -25,6 +25,7 @@ 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 config +from neutron.plugins.ml2 import driver_api from neutron.plugins.ml2 import plugin as ml2_plugin from neutron.tests.unit import _test_extension_portbindings as test_bindings from neutron.tests.unit.ml2.drivers import mechanism_logger as mech_logger @@ -289,6 +290,17 @@ class TestMultiSegmentNetworks(Ml2PluginV2TestCase): res = network_req.get_response(self.api) self.assertEqual(res.status_int, 400) + def test_release_segment_no_type_driver(self): + segment = {driver_api.NETWORK_TYPE: 'faketype', + driver_api.PHYSICAL_NETWORK: 'physnet1', + driver_api.ID: 1} + with mock.patch('neutron.plugins.ml2.managers.LOG') as log: + self.driver.type_manager.release_segment(session=None, + segment=segment) + log.error.assert_called_once_with( + "Failed to release segment '%s' because " + "network type is not supported.", segment) + def test_create_provider_fail(self): segment = {pnet.NETWORK_TYPE: None, pnet.PHYSICAL_NETWORK: 'phys_net',