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
This commit is contained in:
Kevin Benton 2014-06-18 00:17:02 -07:00
parent ff9173ede2
commit ddc62e2d25
2 changed files with 42 additions and 2 deletions

View File

@ -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

View 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'),