From: Kevin Benton Date: Tue, 8 Apr 2014 16:04:08 +0000 (-0700) Subject: BigSwitch: Create router ports synchronously X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=2527d3d30d6b91e5df74ce1b85cb0d079aff4216;p=openstack-build%2Fneutron-build.git 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 --- diff --git a/neutron/plugins/bigswitch/plugin.py b/neutron/plugins/bigswitch/plugin.py index cf9dbe62d..92db9a95e 100644 --- a/neutron/plugins/bigswitch/plugin.py +++ b/neutron/plugins/bigswitch/plugin.py @@ -664,8 +664,12 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base, with context.session.begin(subtransactions=True): self._ensure_default_security_group_on_port(context, port) sgids = self._get_security_groups_on_port(context, port) - # set port status to pending. updated after rest call completes - port['port']['status'] = const.PORT_STATUS_BUILD + # 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 dhcp_opts = port['port'].get(edo_ext.EXTRADHCPOPTS, []) new_port = super(NeutronRestProxyV2, self).create_port(context, port) @@ -691,8 +695,15 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base, # create on network ctrl mapped_port = self._map_state_and_status(new_port) - self.evpool.spawn_n(self.async_port_create, net["tenant_id"], - new_port["network_id"], mapped_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"], + new_port["network_id"], mapped_port) self.notify_security_groups_member_updated(context, new_port) return new_port diff --git a/neutron/tests/unit/bigswitch/test_restproxy_plugin.py b/neutron/tests/unit/bigswitch/test_restproxy_plugin.py index 9e0f0bee3..012dae9a2 100644 --- a/neutron/tests/unit/bigswitch/test_restproxy_plugin.py +++ b/neutron/tests/unit/bigswitch/test_restproxy_plugin.py @@ -20,6 +20,7 @@ import mock from oslo.config import cfg import webob.exc +from neutron.common import constants from neutron import context from neutron.extensions import portbindings from neutron.manager import NeutronManager @@ -81,7 +82,21 @@ class TestBigSwitchProxyPortsV2(test_plugin.TestPortsV2, super(TestBigSwitchProxyPortsV2, 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): + # normal ports go into the pending build state for async creation with self.port() as port: self.assertEqual(port['port']['status'], 'BUILD') self.assertEqual(self.port_create_status, 'BUILD')