From: Assaf Muller Date: Sun, 5 Oct 2014 12:02:59 +0000 (+0300) Subject: Expose ha_state per router to agent binding via API X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=c8dfdb47a8252dff2bbe1577f74b2d05317d236b;p=openstack-build%2Fneutron-build.git Expose ha_state per router to agent binding via API l3-agent-list-hosting-router will now return with a new 'ha_state' attribute, per agent. It signifies the HA state of the router on that agent. Implements: blueprint report-ha-router-master Change-Id: Ie0f53b7565d53ff791b0cdcca20be2b4415b49cc --- diff --git a/neutron/db/l3_agentschedulers_db.py b/neutron/db/l3_agentschedulers_db.py index 9d9e926ba..b92954479 100644 --- a/neutron/db/l3_agentschedulers_db.py +++ b/neutron/db/l3_agentschedulers_db.py @@ -342,14 +342,9 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase, with context.session.begin(subtransactions=True): bindings = self._get_l3_bindings_hosting_routers( context, [router_id]) - results = [] - for binding in bindings: - l3_agent_dict = self._make_agent_dict(binding.l3_agent) - results.append(l3_agent_dict) - if results: - return {'agents': results} - else: - return {'agents': []} + + return {'agents': [self._make_agent_dict(binding.l3_agent) for + binding in bindings]} def get_l3_agents(self, context, active=None, filters=None): query = context.session.query(agents_db.Agent) diff --git a/neutron/db/l3_hamode_db.py b/neutron/db/l3_hamode_db.py index a7ddfdadc..2e9284ca2 100644 --- a/neutron/db/l3_hamode_db.py +++ b/neutron/db/l3_hamode_db.py @@ -436,6 +436,12 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin): return query.all() + def get_l3_bindings_hosting_router_with_ha_states( + self, context, router_id): + """Return a list of [(agent, ha_state), ...].""" + bindings = self.get_ha_router_port_bindings(context, [router_id]) + return [(binding.agent, binding.state) for binding in bindings] + def _process_sync_ha_data(self, context, routers, host): routers_dict = dict((router['id'], router) for router in routers) diff --git a/neutron/db/l3_hascheduler_db.py b/neutron/db/l3_hascheduler_db.py index a4bbbd55b..d3a60e366 100644 --- a/neutron/db/l3_hascheduler_db.py +++ b/neutron/db/l3_hascheduler_db.py @@ -59,3 +59,24 @@ class L3_HA_scheduler_db_mixin(l3_sch_db.L3AgentSchedulerDbMixin): order_by('count')) return [record[0] for record in query] + + def _get_agents_dict_for_router(self, agents_and_states): + agents = [] + for agent, ha_state in agents_and_states: + l3_agent_dict = self._make_agent_dict(agent) + l3_agent_dict['ha_state'] = ha_state + agents.append(l3_agent_dict) + return {'agents': agents} + + def list_l3_agents_hosting_router(self, context, router_id): + with context.session.begin(subtransactions=True): + router_db = self._get_router(context, router_id) + if router_db.extra_attributes.ha: + bindings = self.get_l3_bindings_hosting_router_with_ha_states( + context, router_id) + else: + bindings = self._get_l3_bindings_hosting_routers( + context, [router_id]) + bindings = [(binding.l3_agent, None) for binding in bindings] + + return self._get_agents_dict_for_router(bindings) diff --git a/neutron/tests/unit/db/test_l3_ha_db.py b/neutron/tests/unit/db/test_l3_ha_db.py index b1bbf3e97..5939d8782 100644 --- a/neutron/tests/unit/db/test_l3_ha_db.py +++ b/neutron/tests/unit/db/test_l3_ha_db.py @@ -26,6 +26,7 @@ from neutron.extensions import l3 from neutron.extensions import l3_ext_ha_mode from neutron import manager from neutron.openstack.common import uuidutils +from neutron.scheduler import l3_agent_scheduler from neutron.tests.unit import testlib_api from neutron.tests.unit import testlib_plugin @@ -93,12 +94,43 @@ class L3HATestFramework(testlib_api.SqlTestCase, def _bind_router(self, router_id): with self.admin_ctx.session.begin(subtransactions=True): - bindings = self.plugin.get_ha_router_port_bindings(self.admin_ctx, - [router_id]) - - for agent_id, binding in zip( - [self.agent1['id'], self.agent2['id']], bindings): - binding.l3_agent_id = agent_id + scheduler = l3_agent_scheduler.ChanceScheduler() + agents_db = self.plugin.get_agents_db(self.admin_ctx) + scheduler.bind_ha_router_to_agents( + self.plugin, + self.admin_ctx, + router_id, + agents_db) + + def test_get_ha_router_port_bindings(self): + router = self._create_router() + self._bind_router(router['id']) + bindings = self.plugin.get_ha_router_port_bindings( + self.admin_ctx, [router['id']]) + binding_dicts = [{'router_id': binding['router_id'], + 'l3_agent_id': binding['l3_agent_id']} + for binding in bindings] + self.assertIn({'router_id': router['id'], + 'l3_agent_id': self.agent1['id']}, binding_dicts) + self.assertIn({'router_id': router['id'], + 'l3_agent_id': self.agent2['id']}, binding_dicts) + + def test_get_l3_bindings_hosting_router_with_ha_states_ha_router(self): + router = self._create_router() + self._bind_router(router['id']) + self.plugin.update_routers_states( + self.admin_ctx, {router['id']: 'active'}, self.agent1['host']) + bindings = self.plugin.get_l3_bindings_hosting_router_with_ha_states( + self.admin_ctx, router['id']) + agent_ids = [(agent[0]['id'], agent[1]) for agent in bindings] + self.assertIn((self.agent1['id'], 'active'), agent_ids) + self.assertIn((self.agent2['id'], 'standby'), agent_ids) + + def test_get_l3_bindings_hosting_router_with_ha_states_not_scheduled(self): + router = self._create_router(ha=False) + bindings = self.plugin.get_l3_bindings_hosting_router_with_ha_states( + self.admin_ctx, router['id']) + self.assertEqual([], bindings) class L3HATestCase(L3HATestFramework): diff --git a/neutron/tests/unit/test_l3_schedulers.py b/neutron/tests/unit/test_l3_schedulers.py index b60a791de..6ecf3bf5d 100644 --- a/neutron/tests/unit/test_l3_schedulers.py +++ b/neutron/tests/unit/test_l3_schedulers.py @@ -1239,6 +1239,37 @@ class L3AgentSchedulerDbMixinTestCase(L3HATestCaseMixin): self.plugin.reschedule_routers_from_down_agents() self.assertFalse(reschedule.called) + def test_list_l3_agents_hosting_ha_router(self): + router = self._create_ha_router() + self.plugin.schedule_router(self.adminContext, router['id']) + + agents = self.plugin.list_l3_agents_hosting_router( + self.adminContext, router['id'])['agents'] + for agent in agents: + self.assertEqual('standby', agent['ha_state']) + + self.plugin.update_routers_states( + self.adminContext, {router['id']: 'active'}, self.agent1.host) + agents = self.plugin.list_l3_agents_hosting_router( + self.adminContext, router['id'])['agents'] + for agent in agents: + expected_state = ('active' if agent['host'] == self.agent1.host + else 'standby') + self.assertEqual(expected_state, agent['ha_state']) + + def test_list_l3_agents_hosting_legacy_router(self): + router = self._create_ha_router(ha=False) + self.plugin.schedule_router(self.adminContext, router['id']) + + agents = self.plugin.list_l3_agents_hosting_router( + self.adminContext, router['id'])['agents'] + for agent in agents: + self.assertIsNone(agent['ha_state']) + + def test_get_agents_dict_for_router_unscheduled_returns_empty_list(self): + self.assertEqual({'agents': []}, + self.plugin._get_agents_dict_for_router([])) + class L3HAChanceSchedulerTestCase(L3HATestCaseMixin):