From: Swaminathan Vasudevan Date: Tue, 5 Aug 2014 23:16:23 +0000 (-0700) Subject: Implement migration of legacy routers to distributed X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=f005dd5c9b982eca03722a7b2684eeb42a83be2b;p=openstack-build%2Fneutron-build.git Implement migration of legacy routers to distributed This patch addresses the necessary changes required for the router migration or conversion from legacy to distributed. The _update_router_db() method was modified to add logic to support the SNAT functionality of DVR by calling create_snat_intf_ports_if_not_exists(). A call to _unbind_router() was also called to force the scheduling of the router with 'distributed' enabled. Right now we will be supporting migration from legacy to distributed only. Closes-bug: #1348309 Partially-implements: blueprint neutron-ovs-dvr Co-Authored-By: Michael Smith Change-Id: I6f252271bb5b52ce57184ad7b0bf1ce280b965fb --- diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py index a68d8ca46..c4c023729 100644 --- a/neutron/db/l3_dvr_db.py +++ b/neutron/db/l3_dvr_db.py @@ -77,11 +77,12 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, LOG.info(_LI("Centralizing distributed router %s " "is not supported"), router_db['id']) raise NotImplementedError() + # TODO(Swami): Add a check for Services FWaaS and VPNaaS def _update_distributed_attr( self, context, router_id, router_db, data, gw_info): """Update the model to support the dvr case of a router.""" - if not attributes.is_attr_set(gw_info) and data.get('distributed'): + if data.get('distributed'): old_owner = l3_const.DEVICE_OWNER_ROUTER_INTF new_owner = DEVICE_OWNER_DVR_INTERFACE for rp in router_db.attached_ports.filter_by(port_type=old_owner): @@ -93,15 +94,28 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, router_db = super( L3_NAT_with_dvr_db_mixin, self)._update_router_db( context, router_id, data, gw_info) + migrating_to_distributed = ( + not router_db.extra_attributes.distributed and + data.get('distributed') is True) self._validate_router_migration(router_db, data) - # FIXME(swami): need to add migration status so that the scheduler - # can pick the migration request and move stuff over. For now - # only the distributed flag and router interface's owner change. - # Instead of complaining on _validate_router_migration, let's - # succeed here and complete the task in a follow-up patch router_db.extra_attributes.update(data) self._update_distributed_attr( context, router_id, router_db, data, gw_info) + if migrating_to_distributed: + if router_db['gw_port_id']: + # If the Legacy router is getting migrated to a DVR + # router, make sure to create corresponding + # snat interface ports that are to be consumed by + # the Service Node. + if not self.create_snat_intf_ports_if_not_exists( + context.elevated(), router_db): + LOG.debug("SNAT interface ports not created: %s", + router_db['id']) + cur_agents = self.list_l3_agents_hosting_router( + context, router_db['id'])['agents'] + for agent in cur_agents: + self._unbind_router(context, router_db['id'], + agent['id']) return router_db def _delete_current_gw_port(self, context, router_id, router, new_network): @@ -116,6 +130,8 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, super(L3_NAT_with_dvr_db_mixin, self)._create_gw_port(context, router_id, router, new_network) + # Make sure that the gateway port exists before creating the + # snat interface ports for distributed router. if router.extra_attributes.distributed and router.gw_port: snat_p_list = self.create_snat_intf_ports_if_not_exists( context.elevated(), router) diff --git a/neutron/tests/unit/db/test_l3_dvr_db.py b/neutron/tests/unit/db/test_l3_dvr_db.py index b9b8b3bba..2fd04ac28 100644 --- a/neutron/tests/unit/db/test_l3_dvr_db.py +++ b/neutron/tests/unit/db/test_l3_dvr_db.py @@ -76,18 +76,23 @@ class L3DvrTestCase(testlib_api.SqlTestCase): def test_update_router_db_centralized_to_distributed(self): router = {'name': 'foo_router', 'admin_state_up': True} + agent = {'id': _uuid()} distributed = {'distributed': True} router_db = self._create_router(router) router_id = router_db['id'] self.assertFalse(router_db.extra_attributes.distributed) - with mock.patch.object(self.mixin, '_update_distributed_attr') as f: - with mock.patch.object(self.mixin, '_get_router') as g: - g.return_value = router_db - router_db = self.mixin._update_router_db( - self.ctx, router_id, distributed, mock.ANY) - # Assert that the DB value has changed - self.assertTrue(router_db.extra_attributes.distributed) - self.assertEqual(1, f.call_count) + self.mixin._get_router = mock.Mock(return_value=router_db) + self.mixin._validate_router_migration = mock.Mock() + self.mixin._update_distributed_attr = mock.Mock() + self.mixin.list_l3_agents_hosting_router = mock.Mock( + return_value={'agents': [agent]}) + self.mixin._unbind_router = mock.Mock() + router_db = self.mixin._update_router_db( + self.ctx, router_id, distributed, mock.ANY) + # Assert that the DB value has changed + self.assertTrue(router_db.extra_attributes.distributed) + self.assertEqual(1, + self.mixin._update_distributed_attr.call_count) def _test_get_device_owner(self, is_distributed=False, expected=l3_const.DEVICE_OWNER_ROUTER_INTF,