BigSwitch: Create router ports synchronously

Since router ports are created as part of a
long transaction with multiple REST calls, they
need to be created sychronously. This is to prevent
the async thread from deleting them from the backend
if it can't find them in cases where they haven't been
committed to the DB yet.

Closes-Bug: #1305331
Change-Id: I2ab3c862dc6b1760199654bbd0969ac5efdbe704
This commit is contained in:
Kevin Benton 2014-04-08 09:04:08 -07:00
parent ec82d2006b
commit 37e9ea249d
2 changed files with 30 additions and 4 deletions

View File

@ -664,7 +664,11 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
self._ensure_default_security_group_on_port(context, port) self._ensure_default_security_group_on_port(context, port)
sgids = self._get_security_groups_on_port(context, port) sgids = self._get_security_groups_on_port(context, port)
# set port status to pending. updated after rest call completes # non-router port status is set to pending. it is then updated
# after the async rest call completes. router ports are synchronous
if port['port']['device_owner'] == l3_db.DEVICE_OWNER_ROUTER_INTF:
port['port']['status'] = const.PORT_STATUS_ACTIVE
else:
port['port']['status'] = const.PORT_STATUS_BUILD port['port']['status'] = const.PORT_STATUS_BUILD
dhcp_opts = port['port'].get(edo_ext.EXTRADHCPOPTS, []) dhcp_opts = port['port'].get(edo_ext.EXTRADHCPOPTS, [])
new_port = super(NeutronRestProxyV2, self).create_port(context, new_port = super(NeutronRestProxyV2, self).create_port(context,
@ -691,6 +695,13 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
# create on network ctrl # create on network ctrl
mapped_port = self._map_state_and_status(new_port) mapped_port = self._map_state_and_status(new_port)
# ports have to be created synchronously when creating a router
# port since adding router interfaces is a multi-call process
if mapped_port['device_owner'] == l3_db.DEVICE_OWNER_ROUTER_INTF:
self.servers.rest_create_port(net["tenant_id"],
new_port["network_id"],
mapped_port)
else:
self.evpool.spawn_n(self.async_port_create, net["tenant_id"], self.evpool.spawn_n(self.async_port_create, net["tenant_id"],
new_port["network_id"], mapped_port) new_port["network_id"], mapped_port)
self.notify_security_groups_member_updated(context, new_port) self.notify_security_groups_member_updated(context, new_port)

View File

@ -20,6 +20,7 @@ import mock
from oslo.config import cfg from oslo.config import cfg
import webob.exc import webob.exc
from neutron.common import constants
from neutron import context from neutron import context
from neutron.extensions import portbindings from neutron.extensions import portbindings
from neutron.manager import NeutronManager from neutron.manager import NeutronManager
@ -81,7 +82,21 @@ class TestBigSwitchProxyPortsV2(test_plugin.TestPortsV2,
super(TestBigSwitchProxyPortsV2, super(TestBigSwitchProxyPortsV2,
self).setUp(self._plugin_name) self).setUp(self._plugin_name)
def test_router_port_status_active(self):
# router ports screw up port auto-deletion so it has to be
# disabled for this test
with self.network(do_delete=False) as net:
with self.subnet(network=net, do_delete=False) as sub:
with self.port(
subnet=sub,
no_delete=True,
device_owner=constants.DEVICE_OWNER_ROUTER_INTF
) as port:
# router ports should be immediately active
self.assertEqual(port['port']['status'], 'ACTIVE')
def test_update_port_status_build(self): def test_update_port_status_build(self):
# normal ports go into the pending build state for async creation
with self.port() as port: with self.port() as port:
self.assertEqual(port['port']['status'], 'BUILD') self.assertEqual(port['port']['status'], 'BUILD')
self.assertEqual(self.port_create_status, 'BUILD') self.assertEqual(self.port_create_status, 'BUILD')