]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Big Switch ML2: sync detection in port-update
authorKevin Benton <blak111@gmail.com>
Wed, 18 Jun 2014 07:17:02 +0000 (00:17 -0700)
committerKevin Benton <blak111@gmail.com>
Wed, 18 Jun 2014 07:24:27 +0000 (00:24 -0700)
Adds logic to the update_port_postcommit method of the
Big Switch ML2 driver to detect when afailure to update
the port via REST was caused by the backend being out-of-sync
with neutron.

This was accomplished by checking for the NXNETWORK message
which indicates that a port request referenced a network that
does not exist on the backend. This only occurs when they are
out-of-sync so the driver will then trigger a full topology sync.

The same logic exists in the port creation method shared with
the Big Switch plugin. However, the Big Switch ML2 driver does
not send port requests to the controller unless the port binding
host ID is set, which doesn't occur until a port update after
binding in the ML2 scenario. Therefore, the logic has to be repeated
in the ML2 driver port update operation.

Closes-Bug: #1331335
Change-Id: Id6488fbdea2c8c22a34e775977d94389c8da74f8

neutron/plugins/ml2/drivers/mech_bigswitch/driver.py
neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py

index b3acb6671d00f33ac4c16b76c5d10ae65d561fdc..f0173ef84669568cb2fc9d2b4a940781eb8b4d7c 100644 (file)
 # @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
 # @author: Kevin Benton, Big Switch Networks, Inc.
 import copy
+import httplib
 
 import eventlet
 from oslo.config import cfg
 
 from neutron import context as ctx
 from neutron.extensions import portbindings
+from neutron.openstack.common import excutils
 from neutron.openstack.common import log
 from neutron.plugins.bigswitch import config as pl_config
 from neutron.plugins.bigswitch import plugin
@@ -84,8 +86,24 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
         # update port on the network controller
         port = self._prepare_port_for_controller(context)
         if port:
-            self.servers.rest_update_port(port["network"]["tenant_id"],
-                                          port["network"]["id"], port)
+            try:
+                self.servers.rest_update_port(port["network"]["tenant_id"],
+                                              port["network"]["id"], port)
+            except servermanager.RemoteRestError as e:
+                with excutils.save_and_reraise_exception() as ctxt:
+                    if (cfg.CONF.RESTPROXY.auto_sync_on_failure and
+                        e.status == httplib.NOT_FOUND and
+                        servermanager.NXNETWORK in e.reason):
+                        ctxt.reraise = False
+                        LOG.error(_("Iconsistency with backend controller "
+                                    "triggering full synchronization."))
+                        topoargs = self.servers.get_topo_function_args
+                        self._send_all_data(
+                            send_ports=topoargs['get_ports'],
+                            send_floating_ips=topoargs['get_floating_ips'],
+                            send_routers=topoargs['get_routers'],
+                            triggered_by_tenant=port["network"]["tenant_id"]
+                        )
 
     def delete_port_postcommit(self, context):
         # delete port on the network controller
index dab3c5b632afbcfcbb7ca11b378a233d8794b8cb..ea884ae514c74405b5b35eedb577e468cfa36e8b 100644 (file)
@@ -19,6 +19,7 @@ import contextlib
 import mock
 import webob.exc
 
+from neutron import context as neutron_context
 from neutron.extensions import portbindings
 from neutron import manager
 from neutron.plugins.bigswitch import servermanager
@@ -110,6 +111,27 @@ class TestBigSwitchMechDriverPortsV2(test_db_plugin.TestPortsV2,
             ])
         self.spawn_p.start()
 
+    def test_udpate404_triggers_background_sync(self):
+        with contextlib.nested(
+            mock.patch(SERVER_POOL + '.rest_update_port',
+                       side_effect=servermanager.RemoteRestError(
+                           reason=servermanager.NXNETWORK, status=404)),
+            mock.patch(DRIVER + '._send_all_data'),
+            self.port()
+        ) as (mock_update, mock_send_all, p):
+            plugin = manager.NeutronManager.get_plugin()
+            context = neutron_context.get_admin_context()
+            plugin.update_port(context, p['port']['id'],
+                               {'port': {'device_id': 'devid',
+                                         'binding:host_id': 'host'}})
+            mock_send_all.assert_has_calls([
+                mock.call(
+                    send_routers=False, send_ports=True,
+                    send_floating_ips=False,
+                    triggered_by_tenant=p['port']['tenant_id']
+                )
+            ])
+
     def test_backend_request_contents(self):
         with contextlib.nested(
             mock.patch(SERVER_POOL + '.rest_create_port'),