diff --git a/neutron/plugins/ml2/driver_api.py b/neutron/plugins/ml2/driver_api.py index f6167e761cd..78a37d98252 100644 --- a/neutron/plugins/ml2/driver_api.py +++ b/neutron/plugins/ml2/driver_api.py @@ -218,7 +218,7 @@ class PortContext(object): @abstractproperty def original(self): - """Return the original state of the port + """Return the original state of the port. Return the original state of the port, prior to a call to update_port. Method is only valid within calls to @@ -236,6 +236,31 @@ class PortContext(object): """Return the currently bound segment dictionary.""" pass + @abstractproperty + def original_bound_segment(self): + """Return the original bound segment dictionary. + + Return the original bound segment dictionary, prior to a call + to update_port. Method is only valid within calls to + update_port_precommit and update_port_postcommit. + """ + pass + + @abstractproperty + def bound_driver(self): + """Return the currently bound mechanism driver name.""" + pass + + @abstractproperty + def original_bound_driver(self): + """Return the original bound mechanism driver name. + + Return the original bound mechanism driver name, prior to a + call to update_port. Method is only valid within calls to + update_port_precommit and update_port_postcommit. + """ + pass + @abstractmethod def host_agents(self, agent_type): """Get agents of the specified type on port's host. diff --git a/neutron/plugins/ml2/driver_context.py b/neutron/plugins/ml2/driver_context.py index 89f4e61ac7f..facee4e3004 100644 --- a/neutron/plugins/ml2/driver_context.py +++ b/neutron/plugins/ml2/driver_context.py @@ -78,6 +78,12 @@ class PortContext(MechanismDriverContext, api.PortContext): network) self._binding = db.ensure_port_binding(plugin_context.session, port['id']) + if original_port: + self._original_bound_segment_id = self._binding.segment + self._original_bound_driver = self._binding.driver + else: + self._original_bound_segment_id = None + self._original_bound_driver = None @property def current(self): @@ -99,6 +105,21 @@ class PortContext(MechanismDriverContext, api.PortContext): if segment[api.ID] == id: return segment + @property + def original_bound_segment(self): + if self._original_bound_segment_id: + for segment in self._network_context.network_segments: + if segment[api.ID] == self._original_bound_segment_id: + return segment + + @property + def bound_driver(self): + return self._binding.driver + + @property + def original_bound_driver(self): + return self._original_bound_driver + def host_agents(self, agent_type): return self._plugin.get_agents(self._plugin_context, filters={'agent_type': [agent_type], diff --git a/neutron/tests/unit/ml2/_test_mech_agent.py b/neutron/tests/unit/ml2/_test_mech_agent.py index 0714b58907d..73b926f0511 100644 --- a/neutron/tests/unit/ml2/_test_mech_agent.py +++ b/neutron/tests/unit/ml2/_test_mech_agent.py @@ -67,6 +67,18 @@ class FakePortContext(api.PortContext): if segment[api.ID] == self._bound_segment_id: return segment + @property + def original_bound_segment(self): + return None + + @property + def bound_driver(self): + return None + + @property + def original_bound_driver(self): + return None + def host_agents(self, agent_type): if agent_type == self._agent_type: return self._agents diff --git a/neutron/tests/unit/ml2/drivers/mechanism_logger.py b/neutron/tests/unit/ml2/drivers/mechanism_logger.py index ca92dbc648a..c23ef81aaaf 100644 --- a/neutron/tests/unit/ml2/drivers/mechanism_logger.py +++ b/neutron/tests/unit/ml2/drivers/mechanism_logger.py @@ -83,11 +83,19 @@ class LoggerMechanismDriver(api.MechanismDriver): def _log_port_call(self, method_name, context): network_context = context.network LOG.info(_("%(method)s called with port settings %(current)s " - "(original settings %(original)s) on network %(network)s"), + "(original settings %(original)s) " + "bound to segment %(segment)s " + "(original segment %(original_segment)s) " + "using driver %(driver)s " + "(original driver %(original_driver)s) " + "on network %(network)s"), {'method': method_name, 'current': context.current, 'original': context.original, 'segment': context.bound_segment, + 'original_segment': context.original_bound_segment, + 'driver': context.bound_driver, + 'original_driver': context.original_bound_driver, 'network': network_context.current}) def create_port_precommit(self, context): diff --git a/neutron/tests/unit/ml2/drivers/mechanism_test.py b/neutron/tests/unit/ml2/drivers/mechanism_test.py index 0b3d98af71e..a0c05c962ea 100644 --- a/neutron/tests/unit/ml2/drivers/mechanism_test.py +++ b/neutron/tests/unit/ml2/drivers/mechanism_test.py @@ -84,11 +84,34 @@ class TestMechanismDriver(api.MechanismDriver): assert(isinstance(context, api.PortContext)) assert(isinstance(context.current, dict)) assert(context.current['id'] is not None) + + vif_type = context.current.get(portbindings.VIF_TYPE) + assert(vif_type is not None) + if vif_type in (portbindings.VIF_TYPE_UNBOUND, + portbindings.VIF_TYPE_BINDING_FAILED): + assert(context.bound_segment is None) + assert(context.bound_driver is None) + else: + assert(isinstance(context.bound_segment, dict)) + assert(context.bound_driver == 'test') + if original_expected: assert(isinstance(context.original, dict)) assert(context.current['id'] == context.original['id']) + vif_type = context.original.get(portbindings.VIF_TYPE) + assert(vif_type is not None) + if vif_type in (portbindings.VIF_TYPE_UNBOUND, + portbindings.VIF_TYPE_BINDING_FAILED): + assert(context.original_bound_segment is None) + assert(context.original_bound_driver is None) + else: + assert(isinstance(context.original_bound_segment, dict)) + assert(context.original_bound_driver == 'test') else: - assert(not context.original) + assert(context.original is None) + assert(context.original_bound_segment is None) + assert(context.original_bound_driver is None) + network_context = context.network assert(isinstance(network_context, api.NetworkContext)) self._check_network_context(network_context, False) @@ -112,7 +135,12 @@ class TestMechanismDriver(api.MechanismDriver): self._check_port_context(context, False) def bind_port(self, context): - self._check_port_context(context, False) + # REVISIT(rkukura): Currently, bind_port() is called as part + # of either a create or update transaction. The fix for bug + # 1276391 will change it to be called outside any transaction, + # so the context.original* will no longer be available. + self._check_port_context(context, context.original is not None) + host = context.current.get(portbindings.HOST_ID, None) segment = context.network.network_segments[0][api.ID] if host == "host-ovs-no_filter": @@ -123,8 +151,18 @@ class TestMechanismDriver(api.MechanismDriver): {portbindings.CAP_PORT_FILTER: True}) def validate_port_binding(self, context): - self._check_port_context(context, False) + # REVISIT(rkukura): Currently, validate_port_binding() is + # called as part of either a create or update transaction. The + # fix for bug 1276391 will change it to be called outside any + # transaction (or eliminate it altogether), so the + # context.original* will no longer be available. + self._check_port_context(context, context.original is not None) return True def unbind_port(self, context): - self._check_port_context(context, False) + # REVISIT(rkukura): Currently, unbind_port() is called as part + # of either an update or delete transaction. The fix for bug + # 1276391 will change it to be called outside any transaction + # (or eliminate it altogether), so the context.original* will + # no longer be available. + self._check_port_context(context, context.original is not None) diff --git a/neutron/tests/unit/ml2/test_port_binding.py b/neutron/tests/unit/ml2/test_port_binding.py index 86e066892df..6117d0667a2 100644 --- a/neutron/tests/unit/ml2/test_port_binding.py +++ b/neutron/tests/unit/ml2/test_port_binding.py @@ -108,18 +108,18 @@ class PortBindingTestCase(test_plugin.NeutronDbPluginV2TestCase): self.assertFalse(notify_mock.called) def test_update_with_new_host_binding_notifies_agent(self): - self._test_update_port_binding('host-ovs-no-filter', - 'host-bridge-no-filter') + self._test_update_port_binding('host-ovs-no_filter', + 'host-bridge-filter') def test_update_with_same_host_binding_does_not_notify(self): - self._test_update_port_binding('host-ovs-no-filter', - 'host-ovs-no-filter') + self._test_update_port_binding('host-ovs-no_filter', + 'host-ovs-no_filter') def test_update_without_binding_does_not_notify(self): - self._test_update_port_binding('host-ovs-no-filter') + self._test_update_port_binding('host-ovs-no_filter') def testt_update_from_empty_to_host_binding_notifies_agent(self): - self._test_update_port_binding('', 'host-ovs-no-filter') + self._test_update_port_binding('', 'host-ovs-no_filter') def test_update_from_host_to_empty_binding_notifies_agent(self): - self._test_update_port_binding('host-ovs-no-filter', '') + self._test_update_port_binding('host-ovs-no_filter', '')