]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
ML2 mechanism driver access to binding details
authorBob Kukura <rkukura@redhat.com>
Mon, 24 Feb 2014 21:33:26 +0000 (16:33 -0500)
committerBob Kukura <rkukura@redhat.com>
Wed, 26 Feb 2014 14:16:07 +0000 (09:16 -0500)
The following properties are added to the PortContext object passed to
ML2 mechanism drivers for port operations:

* bound_driver - name of current bound driver
* original_bound_driver - name previously bound driver in an update
* original_bound_segment - network segment used in previous binding

Some issues with the existing ML2 port binding unit tests were also
fixed.

The remainder of the fix for bug 1276395, making these binding details
available to mechanism drivers when a port is deleted, will be
addressed as part of the fix for bug 1276391.

Partial-Bug: #1276395
Change-Id: I9ecff4a4e044920ed2dde709c89aeb9bc773220d

neutron/plugins/ml2/driver_api.py
neutron/plugins/ml2/driver_context.py
neutron/tests/unit/ml2/_test_mech_agent.py
neutron/tests/unit/ml2/drivers/mechanism_logger.py
neutron/tests/unit/ml2/drivers/mechanism_test.py
neutron/tests/unit/ml2/test_port_binding.py

index f6167e761cd4d32380bdf8d7633e9bc1bf2b2bf8..78a37d982529b7fa98c950d1c187c6711bbc8ccd 100644 (file)
@@ -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.
index 89f4e61ac7fe814e12c0541e4ebf493d64fca59d..facee4e30045c768e0c652cf4d6a311c307f2531 100644 (file)
@@ -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],
index 0714b58907dac00f4ecd37a433a8d4c493c27439..73b926f051184983f5ad48bbe58eb453ea926720 100644 (file)
@@ -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
index ca92dbc648ac54f60916c5640611478dc669d3b4..c23ef81aaaf76c2705f90eb06976280b96002a65 100644 (file)
@@ -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):
index 0b3d98af71e848844a9052caa59011e12520c701..a0c05c962eaeeb8abddda7e88a0cea22b14f67b9 100644 (file)
@@ -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)
index 86e066892df2e20a419af5450dccea089af43428..6117d0667a22a0836dce0b35d16d9fb57e7a8f22 100644 (file)
@@ -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', '')