summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--neutron/db/l3_dvr_db.py26
-rw-r--r--neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py57
-rw-r--r--neutron/tests/unit/db/test_l3_dvr_db.py30
3 files changed, 101 insertions, 12 deletions
diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py
index b847dc9b14..deb6c417d3 100644
--- a/neutron/db/l3_dvr_db.py
+++ b/neutron/db/l3_dvr_db.py
@@ -727,18 +727,20 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
msg = _("Unable to create the SNAT Interface Port")
raise n_exc.BadRequest(resource='router', msg=msg)
- with context.session.begin(subtransactions=True):
- router_port = l3_models.RouterPort(
- port_id=snat_port['id'],
- router_id=router.id,
- port_type=const.DEVICE_OWNER_ROUTER_SNAT
- )
- context.session.add(router_port)
-
- if do_pop:
- return self._populate_mtu_and_subnets_for_ports(context,
- [snat_port])
- return snat_port
+ with p_utils.delete_port_on_error(
+ self._core_plugin, context.elevated(), snat_port['id']):
+ with context.session.begin(subtransactions=True):
+ router_port = l3_models.RouterPort(
+ port_id=snat_port['id'],
+ router_id=router.id,
+ port_type=const.DEVICE_OWNER_ROUTER_SNAT
+ )
+ context.session.add(router_port)
+
+ if do_pop:
+ return self._populate_mtu_and_subnets_for_ports(context,
+ [snat_port])
+ return snat_port
def _create_snat_intf_ports_if_not_exists(self, context, router):
"""Function to return the snat interface port list.
diff --git a/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py b/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py
index df4d705509..f5ca1e72c8 100644
--- a/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py
+++ b/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py
@@ -82,6 +82,63 @@ class L3DvrTestCase(L3DvrTestCaseBase):
self.l3_plugin._get_agent_gw_ports_exist_for_network(
self.context, 'network_id', 'host', 'agent_id'))
+ def test_csnat_ports_are_created_and_deleted_based_on_router_subnet(self):
+ kwargs = {'arg_list': (external_net.EXTERNAL,),
+ external_net.EXTERNAL: True}
+ net1 = self._make_network(self.fmt, 'net1', True)
+ subnet1 = self._make_subnet(
+ self.fmt, net1, '10.1.0.1', '10.1.0.0/24', enable_dhcp=True)
+ subnet2 = self._make_subnet(
+ self.fmt, net1, '10.2.0.1', '10.2.0.0/24', enable_dhcp=True)
+ ext_net = self._make_network(self.fmt, 'ext_net', True, **kwargs)
+ self._make_subnet(
+ self.fmt, ext_net, '20.0.0.1', '20.0.0.0/24', enable_dhcp=True)
+ # Create first router and add an interface
+ router1 = self._create_router()
+ ext_net_id = ext_net['network']['id']
+ net1_id = net1['network']['id']
+ # Set gateway to router
+ self.l3_plugin._update_router_gw_info(
+ self.context, router1['id'],
+ {'network_id': ext_net_id})
+ # Now add router interface (subnet1) from net1 to router
+ self.l3_plugin.add_router_interface(
+ self.context, router1['id'],
+ {'subnet_id': subnet1['subnet']['id']})
+ # Now add router interface (subnet2) from net1 to router
+ self.l3_plugin.add_router_interface(
+ self.context, router1['id'],
+ {'subnet_id': subnet2['subnet']['id']})
+ # Now check the valid snat interfaces passed to the agent
+ snat_router_intfs = self.l3_plugin._get_snat_sync_interfaces(
+ self.context, [router1['id']])
+ self.assertEqual(2, len(snat_router_intfs[router1['id']]))
+ # Also make sure that there are no csnat ports created and
+ # left over.
+ csnat_ports = self.core_plugin.get_ports(
+ self.context, filters={
+ 'network_id': [net1_id],
+ 'device_owner': [constants.DEVICE_OWNER_ROUTER_SNAT]})
+ self.assertEqual(2, len(csnat_ports))
+ # Now remove router interface (subnet1) from net1 to router
+ self.l3_plugin.remove_router_interface(
+ self.context, router1['id'],
+ {'subnet_id': subnet1['subnet']['id']})
+ # Now remove router interface (subnet2) from net1 to router
+ self.l3_plugin.remove_router_interface(
+ self.context, router1['id'],
+ {'subnet_id': subnet2['subnet']['id']})
+ snat_router_intfs = self.l3_plugin._get_snat_sync_interfaces(
+ self.context, [router1['id']])
+ self.assertEqual(0, len(snat_router_intfs[router1['id']]))
+ # Also make sure that there are no csnat ports created and
+ # left over.
+ csnat_ports = self.core_plugin.get_ports(
+ self.context, filters={
+ 'network_id': [net1_id],
+ 'device_owner': [constants.DEVICE_OWNER_ROUTER_SNAT]})
+ self.assertEqual(0, len(csnat_ports))
+
def _test_remove_router_interface_leaves_snat_intact(self, by_subnet):
with self.subnet() as subnet1, \
self.subnet(cidr='20.0.0.0/24') as subnet2:
diff --git a/neutron/tests/unit/db/test_l3_dvr_db.py b/neutron/tests/unit/db/test_l3_dvr_db.py
index 4ff3ab1576..4461f15e8f 100644
--- a/neutron/tests/unit/db/test_l3_dvr_db.py
+++ b/neutron/tests/unit/db/test_l3_dvr_db.py
@@ -28,6 +28,7 @@ from neutron.db import agents_db
from neutron.db import common_db_mixin
from neutron.db import l3_agentschedulers_db
from neutron.db import l3_dvr_db
+from neutron.db.models import l3 as l3_models
from neutron.extensions import l3
from neutron.extensions import portbindings
from neutron.tests.unit.db import test_db_base_plugin_v2
@@ -793,6 +794,35 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
self.assertEqual(const.DEVICE_OWNER_ROUTER_GW,
router_ports[0]['device_owner'])
+ def test_csnat_port_not_created_on_RouterPort_update_exception(self):
+ router_dict = {'name': 'test_router', 'admin_state_up': True,
+ 'distributed': True}
+ router = self._create_router(router_dict)
+ with self.network() as net_ext,\
+ self.subnet() as subnet:
+ ext_net_id = net_ext['network']['id']
+ self.core_plugin.update_network(
+ self.ctx, ext_net_id,
+ {'network': {'router:external': True}})
+ self.mixin.update_router(
+ self.ctx, router['id'],
+ {'router': {'external_gateway_info':
+ {'network_id': ext_net_id}}})
+ net_id = subnet['subnet']['network_id']
+ with mock.patch.object(
+ l3_models, 'RouterPort', side_effect=Exception):
+ self.assertRaises(
+ l3.RouterInterfaceAttachmentConflict,
+ self.mixin.add_router_interface,
+ self.ctx, router['id'],
+ {'subnet_id': subnet['subnet']['id']})
+ filters = {
+ 'network_id': [net_id],
+ 'device_owner': [const.DEVICE_OWNER_ROUTER_SNAT]
+ }
+ router_ports = self.core_plugin.get_ports(self.ctx, filters)
+ self.assertEqual(0, len(router_ports))
+
def test_add_router_interface_by_port_failure(self):
router_dict = {'name': 'test_router',
'admin_state_up': True,