From: Kevin Benton Date: Wed, 18 Jun 2014 07:17:02 +0000 (-0700) Subject: Big Switch ML2: sync detection in port-update X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=ddc62e2d25abc7459fd28f21a6e0b12fb600d896;p=openstack-build%2Fneutron-build.git Big Switch ML2: sync detection in port-update 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 --- diff --git a/neutron/plugins/ml2/drivers/mech_bigswitch/driver.py b/neutron/plugins/ml2/drivers/mech_bigswitch/driver.py index b3acb6671..f0173ef84 100644 --- a/neutron/plugins/ml2/drivers/mech_bigswitch/driver.py +++ b/neutron/plugins/ml2/drivers/mech_bigswitch/driver.py @@ -18,12 +18,14 @@ # @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 diff --git a/neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py b/neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py index dab3c5b63..ea884ae51 100644 --- a/neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py +++ b/neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py @@ -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'),