From 9f30df85fe78d830331a43fa29fc2d83708c861d Mon Sep 17 00:00:00 2001
From: tianquan <tianquan@cloudin.cn>
Date: Sat, 2 Jul 2016 20:13:13 +0800
Subject: [PATCH] Check compatibility when auto schedule ha routers

When l3 agents do fullsync, the server configured router_auto_schedule
will schedule ha routers whose l3 agent count don't reach
max_l3_agents_per_router to the agent. Need to check compatibility
before binding.

Change-Id: Ie9869eae2bd01c19da5820b4e7ecb7cba7b5692a
Closes-Bug: 1598422
---
 neutron/scheduler/l3_agent_scheduler.py       | 24 ++++++++--------
 .../unit/scheduler/test_l3_agent_scheduler.py | 28 +++++++++++++++++++
 2 files changed, 41 insertions(+), 11 deletions(-)

diff --git a/neutron/scheduler/l3_agent_scheduler.py b/neutron/scheduler/l3_agent_scheduler.py
index 5b5beb9a45c..15ad24e127c 100644
--- a/neutron/scheduler/l3_agent_scheduler.py
+++ b/neutron/scheduler/l3_agent_scheduler.py
@@ -307,17 +307,19 @@ class L3Scheduler(object):
                                                               agent)
         scheduled = False
         admin_ctx = context.elevated()
-        for router, agents in routers_agents:
-            max_agents_not_reached = (
-                not self.max_ha_agents or agents < self.max_ha_agents)
-            if max_agents_not_reached:
-                if not self._router_has_binding(admin_ctx, router['id'],
-                                                agent.id):
-                    self.create_ha_port_and_bind(plugin, admin_ctx,
-                                                 router['id'],
-                                                 router['tenant_id'],
-                                                 agent)
-                    scheduled = True
+        underscheduled_routers = [router for router, agents in routers_agents
+                                  if (not self.max_ha_agents or
+                                      agents < self.max_ha_agents)]
+        schedulable_routers = self._get_routers_can_schedule(
+            admin_ctx, plugin, underscheduled_routers, agent)
+        for router in schedulable_routers:
+            if not self._router_has_binding(admin_ctx, router['id'],
+                                            agent.id):
+                self.create_ha_port_and_bind(plugin, admin_ctx,
+                                             router['id'],
+                                             router['tenant_id'],
+                                             agent)
+                scheduled = True
 
         return scheduled
 
diff --git a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py
index 44cb1555175..ef2b6e0f31f 100644
--- a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py
+++ b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py
@@ -1675,6 +1675,34 @@ class L3HAChanceSchedulerTestCase(L3HATestCaseMixin):
     def test_auto_schedule_all_routers_when_agent_added(self):
         self._auto_schedule_when_agent_added(False)
 
+    def test_auto_schedule_ha_router_when_incompatible_agent_exist(self):
+        handle_internal_only_routers_agent = helpers.register_l3_agent(
+            'host_3', n_const.L3_AGENT_MODE_LEGACY, internal_only=False)
+        router = self._create_ha_router()
+
+        self.plugin.auto_schedule_routers(
+            self.adminContext, handle_internal_only_routers_agent.host, [])
+        agents = self.plugin.get_l3_agents_hosting_routers(
+            self.adminContext, [router['id']],
+            admin_state_up=True)
+        agent_ids = [agent['id'] for agent in agents]
+        self.assertEqual(2, len(agents))
+        self.assertNotIn(handle_internal_only_routers_agent.id, agent_ids)
+
+    def test_auto_schedule_ha_router_when_dvr_agent_exist(self):
+        dvr_agent = helpers.register_l3_agent(
+            HOST_DVR, n_const.L3_AGENT_MODE_DVR)
+        router = self._create_ha_router()
+
+        self.plugin.auto_schedule_routers(self.adminContext, dvr_agent.host,
+                                          [])
+        agents = self.plugin.get_l3_agents_hosting_routers(
+            self.adminContext, [router['id']],
+            admin_state_up=True)
+        agent_ids = [agent['id'] for agent in agents]
+        self.assertEqual(2, len(agents))
+        self.assertNotIn(dvr_agent.id, agent_ids)
+
     def _auto_schedule_when_agent_added(self, specific_router):
         router = self._create_ha_router()
         agents = self.plugin.get_l3_agents_hosting_routers(