From: Oleg Bondarev Date: Wed, 12 Aug 2015 09:29:25 +0000 (+0300) Subject: DVR: fix router rescheduling on server side X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=4418bf426ac48935b27d235139912c2e3ec1d1b5;p=openstack-build%2Fneutron-build.git DVR: fix router rescheduling on server side This fixes router rescheduling for dvr routers to correctly handle CSNAT portion rescheduling on server side. Next patch will make L3 agent aware of possible SNAT role rescheduling to/from it. Partial-Bug: #1472205 Change-Id: I069500a2f1de9a734124544a3f2d793e9fa2d27c --- diff --git a/neutron/db/l3_dvrscheduler_db.py b/neutron/db/l3_dvrscheduler_db.py index 605a93563..5e937611a 100644 --- a/neutron/db/l3_dvrscheduler_db.py +++ b/neutron/db/l3_dvrscheduler_db.py @@ -31,6 +31,7 @@ from neutron.db import agents_db from neutron.db import l3_agentschedulers_db as l3agent_sch_db from neutron.db import model_base from neutron.db import models_v2 +from neutron.extensions import l3agentscheduler from neutron.i18n import _LI, _LW from neutron import manager from neutron.plugins.common import constants as service_constants @@ -342,7 +343,10 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): return snat_candidates = self.get_snat_candidates(sync_router, active_l3_agents) - if snat_candidates: + if not snat_candidates: + LOG.warn(_LW('No candidates found for SNAT')) + return + else: try: chosen_agent = self.bind_snat_servicenode( context, router_id, snat_candidates) @@ -353,6 +357,43 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): context, router_id, chosen_agent) return chosen_agent + def reschedule_router(self, context, router_id, candidates=None): + """Reschedule router to new l3 agents + + Remove the router from l3 agents currently hosting it and + schedule it again + """ + router = self.get_router(context, router_id) + is_distributed = router.get('distributed', False) + if not is_distributed: + return super(L3_DVRsch_db_mixin, self).reschedule_router( + context, router_id, candidates) + + old_agents = self.list_l3_agents_hosting_router( + context, router_id)['agents'] + with context.session.begin(subtransactions=True): + for agent in old_agents: + self._unbind_router(context, router_id, agent['id']) + self.unbind_snat_servicenode(context, router_id) + + self.schedule_router(context, router_id, candidates=candidates) + new_agents = self.list_l3_agents_hosting_router( + context, router_id)['agents'] + if not new_agents: + raise l3agentscheduler.RouterReschedulingFailed( + router_id=router_id) + + l3_notifier = self.agent_notifiers.get(n_const.AGENT_TYPE_L3) + if l3_notifier: + old_hosts = [agent['host'] for agent in old_agents] + new_hosts = [agent['host'] for agent in new_agents] + for host in set(old_hosts) - set(new_hosts): + l3_notifier.router_removed_from_agent( + context, router_id, host) + for host in new_hosts: + l3_notifier.router_added_to_agent( + context, [router_id], host) + def _get_active_l3_agent_routers_sync_data(self, context, host, agent, router_ids): if n_utils.is_extension_supported(self, n_const.L3_HA_MODE_EXT_ALIAS): diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_agent_scheduler.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_agent_scheduler.py index e512b102f..96bfbcdbe 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_agent_scheduler.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_agent_scheduler.py @@ -997,6 +997,34 @@ class OvsAgentSchedulerTestCase(OvsAgentSchedulerTestCaseBase): set([a['configurations']['agent_mode'] for a in l3agents['agents']])) + def test_dvr_router_csnat_rescheduling(self): + helpers.register_l3_agent( + host=L3_HOSTA, agent_mode=constants.L3_AGENT_MODE_DVR_SNAT) + helpers.register_l3_agent( + host=L3_HOSTB, agent_mode=constants.L3_AGENT_MODE_DVR_SNAT) + with self.subnet() as s: + net_id = s['subnet']['network_id'] + self._set_net_external(net_id) + + router = {'name': 'router1', + 'external_gateway_info': {'network_id': net_id}, + 'admin_state_up': True, + 'distributed': True} + r = self.l3plugin.create_router(self.adminContext, + {'router': router}) + self.l3plugin.schedule_router( + self.adminContext, r['id']) + l3agents = self._list_l3_agents_hosting_router(r['id']) + self.assertEqual(2, len(l3agents['agents'])) + csnat_agent_host = self.l3plugin.get_snat_bindings( + self.adminContext, [r['id']])[0]['l3_agent']['host'] + self._take_down_agent_and_run_reschedule(csnat_agent_host) + l3agents = self._list_l3_agents_hosting_router(r['id']) + self.assertEqual(1, len(l3agents['agents'])) + new_csnat_agent_host = self.l3plugin.get_snat_bindings( + self.adminContext, [r['id']])[0]['l3_agent']['host'] + self.assertNotEqual(csnat_agent_host, new_csnat_agent_host) + def test_router_sync_data(self): with self.subnet() as s1,\ self.subnet(cidr='10.0.2.0/24') as s2,\