]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
DVR: fix router rescheduling on server side
authorOleg Bondarev <obondarev@mirantis.com>
Wed, 12 Aug 2015 09:29:25 +0000 (12:29 +0300)
committerOleg Bondarev <obondarev@mirantis.com>
Wed, 12 Aug 2015 09:41:37 +0000 (12:41 +0300)
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

neutron/db/l3_dvrscheduler_db.py
neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_agent_scheduler.py

index 605a9356352665d0ff53006240a6ae171b25ac83..5e937611a5213d6d64317af33cb56101594a5baa 100644 (file)
@@ -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):
index e512b102fb7e81357ac7e7093b3d14e0dcf84fb2..96bfbcdbebe75ca09a54f40ad206a3d82e8643c1 100644 (file)
@@ -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,\