From: Oleg Bondarev Date: Wed, 25 Nov 2015 12:14:18 +0000 (+0300) Subject: DVR:don't reschedule the l3 agent running on compute node X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=13ce7c85552ee6af9856bf701b55d2293ba5610d;p=openstack-build%2Fneutron-build.git DVR:don't reschedule the l3 agent running on compute node For a DVR router, when it updates router gateway_ip, it should not reschedule the l3 agents running on compute nodes whose mode is dvr, it just need to reschedule the l3 agents running on network nodes whose mode is dvr_snat. Change-Id: Ib8ea6797c88cefb473eff9a8a7b2517a6aa90ca4 Closes-bug: #1496204 Co-Authored-By: Oleg Bondarev --- diff --git a/neutron/db/l3_agentschedulers_db.py b/neutron/db/l3_agentschedulers_db.py index e2a01bb82..9a76b1fd5 100644 --- a/neutron/db/l3_agentschedulers_db.py +++ b/neutron/db/l3_agentschedulers_db.py @@ -279,6 +279,11 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase, RouterL3AgentBinding.l3_agent_id == agent_id) query.delete() + def _unschedule_router(self, context, router_id, agents_ids): + with context.session.begin(subtransactions=True): + for agent_id in agents_ids: + self._unbind_router(context, router_id, agent_id) + def reschedule_router(self, context, router_id, candidates=None): """Reschedule router to (a) new l3 agent(s) @@ -288,8 +293,8 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase, cur_agents = self.list_l3_agents_hosting_router( context, router_id)['agents'] with context.session.begin(subtransactions=True): - for agent in cur_agents: - self._unbind_router(context, router_id, agent['id']) + cur_agents_ids = [agent['id'] for agent in cur_agents] + self._unschedule_router(context, router_id, cur_agents_ids) self.schedule_router(context, router_id, candidates=candidates) new_agents = self.list_l3_agents_hosting_router( diff --git a/neutron/db/l3_dvrscheduler_db.py b/neutron/db/l3_dvrscheduler_db.py index 0bd446973..28081904d 100644 --- a/neutron/db/l3_dvrscheduler_db.py +++ b/neutron/db/l3_dvrscheduler_db.py @@ -389,12 +389,14 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): context, router_id, chosen_agent) return chosen_agent - def _unbind_router(self, context, router_id, agent_id): + def _unschedule_router(self, context, router_id, agents_ids): router = self.get_router(context, router_id) - super(L3_DVRsch_db_mixin, self)._unbind_router(context, router_id, - agent_id) if router.get('distributed', False): - self.unbind_snat(context, router_id, agent_id) + # for DVR router unscheduling means just unscheduling SNAT portion + self.unbind_snat_servicenode(context, router_id) + else: + super(L3_DVRsch_db_mixin, self)._unschedule_router( + context, router_id, agents_ids) def _get_active_l3_agent_routers_sync_data(self, context, host, agent, router_ids): diff --git a/neutron/tests/unit/db/test_agentschedulers_db.py b/neutron/tests/unit/db/test_agentschedulers_db.py index eafb2235a..dde3b3a20 100644 --- a/neutron/tests/unit/db/test_agentschedulers_db.py +++ b/neutron/tests/unit/db/test_agentschedulers_db.py @@ -755,21 +755,20 @@ class OvsAgentSchedulerTestCase(OvsAgentSchedulerTestCaseBase): self.assertFalse(ret_b) def test_router_is_not_rescheduled_from_dvr_agent(self): - router = {'name': 'router1', - 'admin_state_up': True, - 'distributed': True} - subnet_ids = {'id': '1234'} - r = self.l3plugin.create_router( - self.adminContext, {'router': router}) - dvr_agent = self._register_dvr_agents()[1] + with self.subnet() as s, \ + mock.patch.object( + self.l3plugin, + 'check_ports_exist_on_l3agent') as port_exists: + net_id = s['subnet']['network_id'] + self._set_net_external(net_id) + router = {'name': 'router1', + 'admin_state_up': True, + 'external_gateway_info': {'network_id': net_id}, + 'distributed': True} + r = self.l3plugin.create_router( + self.adminContext, {'router': router}) + dvr_snat_agent, dvr_agent = self._register_dvr_agents() - with mock.patch.object( - self.l3plugin, - 'check_ports_exist_on_l3agent') as port_exists,\ - mock.patch.object( - self.l3plugin, - 'get_subnet_ids_on_router') as rtr_subnets: - rtr_subnets.return_value = [subnet_ids] port_exists.return_value = True self.l3plugin.schedule_router( self.adminContext, r['id']) @@ -777,12 +776,24 @@ class OvsAgentSchedulerTestCase(OvsAgentSchedulerTestCaseBase): self.assertEqual(2, len(agents['agents'])) self.assertIn(dvr_agent['host'], [a['host'] for a in agents['agents']]) + # router should not be unscheduled from dvr agent self._take_down_agent_and_run_reschedule(dvr_agent['host']) agents = self._list_l3_agents_hosting_router(r['id']) self.assertEqual(2, len(agents['agents'])) self.assertIn(dvr_agent['host'], [a['host'] for a in agents['agents']]) + # another dvr_snat agent is needed to test that router is not + # unscheduled from dead dvr agent in case rescheduling between + # dvr_snat agents happens + helpers.register_l3_agent( + host='hostC', agent_mode=constants.L3_AGENT_MODE_DVR_SNAT) + self._take_down_agent_and_run_reschedule(dvr_snat_agent['host']) + agents = self._list_l3_agents_hosting_router(r['id']) + self.assertEqual(2, len(agents['agents'])) + self.assertIn(dvr_agent['host'], + [a['host'] for a in agents['agents']]) + def test_router_reschedule_succeeded_after_failed_notification(self): l3_plugin = (manager.NeutronManager.get_service_plugins() [service_constants.L3_ROUTER_NAT])