]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
ML2: ODL driver sets port status
authorRobert Kukura <kukura@noironetworks.com>
Thu, 3 Apr 2014 21:01:00 +0000 (17:01 -0400)
committerRobert Kukura <kukura@noironetworks.com>
Fri, 4 Apr 2014 00:50:45 +0000 (20:50 -0400)
The OpenDaylight mechanism driver does not depend on an L2 agent to
plug the port. Now that nova waits for notification that the port
status is ACTIVE, the ML2 driver API is extended so that the mechanism
driver that binds a port can optionally set the port status, and the
OpenDaylight mechanism driver uses this to set the port status to
ACTIVE.

Closes-Bug: 1301449
Change-Id: I171c405f36b4f2354d9585e8ae3dfa50ddaa9a7e

neutron/plugins/ml2/driver_api.py
neutron/plugins/ml2/driver_context.py
neutron/plugins/ml2/drivers/mechanism_odl.py
neutron/plugins/ml2/plugin.py
neutron/tests/unit/ml2/drivers/mechanism_test.py
neutron/tests/unit/ml2/test_port_binding.py

index 264a1b63e147c3e679a4147c585def7385915982..2384b0cf9d68c7cece3ec2b7e89be8a429d667ad 100644 (file)
@@ -270,12 +270,14 @@ class PortContext(object):
         pass
 
     @abc.abstractmethod
-    def set_binding(self, segment_id, vif_type, vif_details):
+    def set_binding(self, segment_id, vif_type, vif_details,
+                    status=None):
         """Set the binding for the port.
 
         :param segment_id: Network segment bound for the port.
         :param vif_type: The VIF type for the bound port.
         :param vif_details: Dictionary with details for VIF driver.
+        :param status: Port status to set if not None.
 
         Called by MechanismDriver.bind_port to indicate success and
         specify binding details to use for port. The segment_id must
index facee4e30045c768e0c652cf4d6a311c307f2531..0c1180619f892d628743263ddbff270aa7bbb442 100644 (file)
@@ -84,6 +84,7 @@ class PortContext(MechanismDriverContext, api.PortContext):
         else:
             self._original_bound_segment_id = None
             self._original_bound_driver = None
+        self._new_port_status = None
 
     @property
     def current(self):
@@ -125,8 +126,10 @@ class PortContext(MechanismDriverContext, api.PortContext):
                                        filters={'agent_type': [agent_type],
                                                 'host': [self._binding.host]})
 
-    def set_binding(self, segment_id, vif_type, vif_details):
+    def set_binding(self, segment_id, vif_type, vif_details,
+                    status=None):
         # TODO(rkukura) Verify binding allowed, segment in network
         self._binding.segment = segment_id
         self._binding.vif_type = vif_type
         self._binding.vif_details = jsonutils.dumps(vif_details)
+        self._new_port_status = status
index b099a5f98de435ce1c1273207e49dd048ca6815f..87d89afcb3a6340d0506e64ee0caa19caad280c1 100644 (file)
@@ -20,6 +20,7 @@ import time
 from oslo.config import cfg
 import requests
 
+from neutron.common import constants as n_const
 from neutron.common import exceptions as n_exc
 from neutron.common import utils
 from neutron.extensions import portbindings
@@ -332,7 +333,8 @@ class OpenDaylightMechanismDriver(api.MechanismDriver):
             if self.check_segment(segment):
                 context.set_binding(segment[api.ID],
                                     self.vif_type,
-                                    self.vif_details)
+                                    self.vif_details,
+                                    status=n_const.PORT_STATUS_ACTIVE)
                 LOG.debug(_("Bound using segment: %s"), segment)
                 return
             else:
index 4080ea07e50c4509e5180ba7a24ef8602e9bad60..a72c5128abaefaab6d6f5f52fc577b58b09d783a 100644 (file)
@@ -259,6 +259,19 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
             self.mechanism_manager.bind_port(mech_context)
             self._update_port_dict_binding(port, binding)
 
+            # Update the port status if requested by the bound driver.
+            if binding.segment and mech_context._new_port_status:
+                # REVISIT(rkukura): This function is currently called
+                # inside a transaction with the port either newly
+                # created or locked for update. After the fix for bug
+                # 1276391 is merged, this will no longer be true, and
+                # the port status update will need to be handled in
+                # the transaction that commits the new binding.
+                port_db = db.get_port(mech_context._plugin_context.session,
+                                      port['id'])
+                port_db.status = mech_context._new_port_status
+                port['status'] = mech_context._new_port_status
+
         return ret_value
 
     def _update_port_dict_binding(self, port, binding):
index 64b793ae4ecba05e19dbb9ddf00f34dc7843ab6a..6a0ca1e863050ed5a37f08393ec4320bf9747529 100644 (file)
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from neutron.common import constants as const
 from neutron.extensions import portbindings
 from neutron.plugins.ml2 import driver_api as api
 
@@ -163,3 +164,8 @@ class TestMechanismDriver(api.MechanismDriver):
             context.set_binding(segment, portbindings.VIF_TYPE_BRIDGE,
                                 {portbindings.CAP_PORT_FILTER: True})
             self.bound_ports.add(context.current['id'])
+        elif host == "host-ovs-filter-active":
+            context.set_binding(segment, portbindings.VIF_TYPE_OVS,
+                                {portbindings.CAP_PORT_FILTER: True},
+                                status=const.PORT_STATUS_ACTIVE)
+            self.bound_ports.add(context.current['id'])
index c9263c200379c109c01266536c3dc14f7ac9d959..86ff76cb03fd0db710d1a042656441dbff3ff1cb 100644 (file)
@@ -41,20 +41,25 @@ class PortBindingTestCase(test_plugin.NeutronDbPluginV2TestCase):
         self.plugin = manager.NeutronManager.get_plugin()
         self.plugin.start_rpc_listener()
 
-    def _check_response(self, port, vif_type, has_port_filter, bound):
+    def _check_response(self, port, vif_type, has_port_filter, bound, status):
         self.assertEqual(port[portbindings.VIF_TYPE], vif_type)
         vif_details = port[portbindings.VIF_DETAILS]
+        port_status = port['status']
         if bound:
             # TODO(rkukura): Replace with new VIF security details
             self.assertEqual(vif_details[portbindings.CAP_PORT_FILTER],
                              has_port_filter)
+            self.assertEqual(port_status, status or 'DOWN')
+        else:
+            self.assertEqual(port_status, 'DOWN')
 
-    def _test_port_binding(self, host, vif_type, has_port_filter, bound):
+    def _test_port_binding(self, host, vif_type, has_port_filter, bound,
+                           status=None):
         host_arg = {portbindings.HOST_ID: host}
         with self.port(name='name', arg_list=(portbindings.HOST_ID,),
                        **host_arg) as port:
             self._check_response(port['port'], vif_type, has_port_filter,
-                                 bound)
+                                 bound, status)
             port_id = port['port']['id']
             neutron_context = context.get_admin_context()
             details = self.plugin.callbacks.get_device_details(
@@ -84,6 +89,11 @@ class PortBindingTestCase(test_plugin.NeutronDbPluginV2TestCase):
                                 portbindings.VIF_TYPE_BRIDGE,
                                 True, True)
 
+    def test_binding_status_active(self):
+        self._test_port_binding("host-ovs-filter-active",
+                                portbindings.VIF_TYPE_OVS,
+                                True, True, 'ACTIVE')
+
     def _test_update_port_binding(self, host, new_host=None):
         with mock.patch.object(self.plugin,
                                '_notify_port_updated') as notify_mock: