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
This commit is contained in:
Assaf Muller 2014-10-05 15:02:59 +03:00
parent de3bd2e61a
commit c8dfdb47a8
5 changed files with 98 additions and 13 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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])
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)
for agent_id, binding in zip(
[self.agent1['id'], self.agent2['id']], bindings):
binding.l3_agent_id = agent_id
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):

View File

@ -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):