From 25e65df7974c238517ab51ea07079ab0482ad44a Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Wed, 14 Sep 2016 16:52:07 -0400 Subject: [PATCH] Fix migration of legacy router to DVR We have to ensure ML2's create_port method is not called in a transaction. This adds a temporary hack to set an attribute on the context to skip this check to accomodate an L3 code-path that has a port creation entangled in a transaction. This attribute will ultimately be removed once this path is refactored. Change-Id: I9c41a7848b22c437bedcdd7eb57f7c9da873b06d Closes-bug: #1619312 --- neutron/db/l3_dvr_db.py | 2 ++ .../l3_router/test_l3_dvr_router_plugin.py | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py index 32f9d9b11d0..39d8f3925ab 100644 --- a/neutron/db/l3_dvr_db.py +++ b/neutron/db/l3_dvr_db.py @@ -139,6 +139,8 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, # router, make sure to create corresponding # snat interface ports that are to be consumed by # the Service Node. + # TODO(haleyb): move this out of transaction + setattr(context, 'GUARD_TRANSACTION', False) if not self._create_snat_intf_ports_if_not_exists( context.elevated(), router_db): LOG.debug("SNAT interface ports not created: %s", 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 ea650287b10..912abb88207 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 @@ -1532,3 +1532,38 @@ class L3DvrTestCase(ml2_test_base.ML2TestFramework): self.context, router['id']) self.assertEqual(1, len(agents['agents'])) self.assertEqual(self.l3_agent['id'], agents['agents'][0]['id']) + + +class L3DvrTestCaseMigration(L3DvrTestCase): + def test_update_router_db_centralized_to_distributed_with_ports(self): + with self.subnet() as subnet1: + kwargs = {'arg_list': (external_net.EXTERNAL,), + external_net.EXTERNAL: True} + with self.network(**kwargs) as ext_net, \ + self.subnet(network=ext_net, + cidr='30.0.0.0/24'): + router = self._create_router(distributed=False) + self.l3_plugin.add_router_interface( + self.context, router['id'], + {'subnet_id': subnet1['subnet']['id']}) + self.l3_plugin._update_router_gw_info( + self.context, router['id'], + {'network_id': ext_net['network']['id']}) + self.assertEqual( + 0, len(self.l3_plugin._get_snat_sync_interfaces( + self.context, [router['id']]))) + + # router needs to be in admin state down in order to be + # upgraded to DVR + self.l3_plugin.update_router( + self.context, router['id'], + {'router': {'admin_state_up': False}}) + self.assertFalse(router['distributed']) + self.l3_plugin.update_router( + self.context, router['id'], + {'router': {'distributed': True}}) + router = self.l3_plugin.get_router(self.context, router['id']) + self.assertTrue(router['distributed']) + self.assertEqual( + 1, len(self.l3_plugin._get_snat_sync_interfaces( + self.context, [router['id']])))