Merge "Introduce new queries to return DVR routers for a host"

This commit is contained in:
Jenkins 2016-01-27 04:22:18 +00:00 committed by Gerrit Code Review
commit 66f4e0dd1c
3 changed files with 248 additions and 3 deletions

View File

@ -366,6 +366,14 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase,
context, constants.AGENT_TYPE_L3, host)
if not agentschedulers_db.services_available(agent.admin_state_up):
return []
return self._get_router_ids_for_agent(context, agent, router_ids)
def _get_router_ids_for_agent(self, context, agent, router_ids):
"""Get IDs of routers that the agent should host
Overridden for DVR to handle agents in 'dvr' mode which have
no explicit bindings with routers
"""
query = context.session.query(RouterL3AgentBinding.router_id)
query = query.filter(
RouterL3AgentBinding.l3_agent_id == agent.id)
@ -378,10 +386,13 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase,
def list_active_sync_routers_on_active_l3_agent(
self, context, host, router_ids):
router_ids = self.list_router_ids_on_host(context, host, router_ids)
agent = self._get_agent_by_type_and_host(
context, constants.AGENT_TYPE_L3, host)
if not agentschedulers_db.services_available(agent.admin_state_up):
return []
router_ids = self._get_router_ids_for_agent(
context, agent, router_ids)
if router_ids:
agent = self._get_agent_by_type_and_host(
context, constants.AGENT_TYPE_L3, host)
return self._get_active_l3_agent_routers_sync_data(context, host,
agent,
router_ids)

View File

@ -488,6 +488,60 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
LOG.debug('Hosts for router %s: %s', router_id, hosts)
return hosts
def _get_dvr_subnet_ids_on_host_query(self, context, host):
query = context.session.query(
models_v2.IPAllocation.subnet_id).distinct()
query = query.join(models_v2.IPAllocation.port)
query = query.join(models_v2.Port.port_binding)
query = query.filter(ml2_models.PortBinding.host == host)
owner_filter = or_(
models_v2.Port.device_owner.startswith(
n_const.DEVICE_OWNER_COMPUTE_PREFIX),
models_v2.Port.device_owner.in_(
n_utils.get_other_dvr_serviced_device_owners()))
query = query.filter(owner_filter)
return query
def _get_dvr_router_ids_for_host(self, context, host):
subnet_ids_on_host_query = self._get_dvr_subnet_ids_on_host_query(
context, host)
query = context.session.query(models_v2.Port.device_id).distinct()
query = query.filter(
models_v2.Port.device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE)
query = query.join(models_v2.Port.fixed_ips)
query = query.filter(
models_v2.IPAllocation.subnet_id.in_(subnet_ids_on_host_query))
router_ids = [item[0] for item in query]
LOG.debug('DVR routers on host %s: %s', host, router_ids)
return router_ids
def _get_router_ids_for_agent(self, context, agent_db, router_ids):
result_set = set(super(L3_DVRsch_db_mixin,
self)._get_router_ids_for_agent(
context, agent_db, router_ids))
router_ids = set(router_ids or [])
if router_ids and result_set == router_ids:
# no need for extra dvr checks if requested routers are
# explicitly scheduled to the agent
return list(result_set)
# dvr routers are not explicitly scheduled to agents on hosts with
# dvr serviceable ports, so need special handling
if self._get_agent_mode(agent_db) in [n_const.L3_AGENT_MODE_DVR,
n_const.L3_AGENT_MODE_DVR_SNAT]:
if not router_ids:
result_set |= set(self._get_dvr_router_ids_for_host(
context, agent_db['host']))
else:
for router_id in (router_ids - result_set):
subnet_ids = self.get_subnet_ids_on_router(
context, router_id)
if subnet_ids and self.check_dvr_serviceable_ports_on_host(
context, agent_db['host'], list(subnet_ids)):
result_set.add(router_id)
return list(result_set)
def _notify_l3_agent_new_port(resource, event, trigger, **kwargs):
LOG.debug('Received %(resource)s %(event)s', {

View File

@ -728,6 +728,186 @@ class L3DvrTestCase(ml2_test_base.ML2TestFramework):
agents['agents'][0]['id'])
self.assertFalse(remove_mock.called)
def test__get_dvr_subnet_ids_on_host_query(self):
with self.subnet(cidr='20.0.0.0/24') as subnet1,\
self.subnet(cidr='30.0.0.0/24') as subnet2,\
self.subnet(cidr='40.0.0.0/24') as subnet3,\
self.port(subnet=subnet1,
device_owner=DEVICE_OWNER_COMPUTE) as p1,\
self.port(subnet=subnet2,
device_owner=constants.DEVICE_OWNER_DHCP) as p2,\
self.port(subnet=subnet3,
device_owner=constants.DEVICE_OWNER_NEUTRON_PREFIX)\
as p3,\
self.port(subnet=subnet3,
device_owner=constants.DEVICE_OWNER_COMPUTE_PREFIX)\
as p4:
host = 'host1'
subnet_ids = [item[0] for item in
self.l3_plugin._get_dvr_subnet_ids_on_host_query(
self.context, host)]
self.assertEqual([], subnet_ids)
self.core_plugin.update_port(
self.context, p1['port']['id'],
{'port': {portbindings.HOST_ID: host}})
expected = {subnet1['subnet']['id']}
subnet_ids = [item[0] for item in
self.l3_plugin._get_dvr_subnet_ids_on_host_query(
self.context, host)]
self.assertEqual(expected, set(subnet_ids))
self.core_plugin.update_port(
self.context, p2['port']['id'],
{'port': {portbindings.HOST_ID: host}})
expected.add(subnet2['subnet']['id'])
subnet_ids = [item[0] for item in
self.l3_plugin._get_dvr_subnet_ids_on_host_query(
self.context, host)]
self.assertEqual(expected, set(subnet_ids))
self.core_plugin.update_port(
self.context, p3['port']['id'],
{'port': {portbindings.HOST_ID: host}})
# p3 is non dvr serviceable so no subnet3 expected
subnet_ids = [item[0] for item in
self.l3_plugin._get_dvr_subnet_ids_on_host_query(
self.context, host)]
self.assertEqual(expected, set(subnet_ids))
other_host = 'other' + host
self.core_plugin.update_port(
self.context, p4['port']['id'],
{'port': {portbindings.HOST_ID: other_host}})
# p4 is on other host so no subnet3 expected
subnet_ids = [item[0] for item in
self.l3_plugin._get_dvr_subnet_ids_on_host_query(
self.context, host)]
self.assertEqual(expected, set(subnet_ids))
self.core_plugin.update_port(
self.context, p4['port']['id'],
{'port': {portbindings.HOST_ID: host}})
# finally p4 is on the right host so subnet3 is expected
expected.add(subnet3['subnet']['id'])
subnet_ids = [item[0] for item in
self.l3_plugin._get_dvr_subnet_ids_on_host_query(
self.context, host)]
self.assertEqual(expected, set(subnet_ids))
def test__get_dvr_router_ids_for_host(self):
router1 = self._create_router()
router2 = self._create_router()
host = 'host1'
arg_list = (portbindings.HOST_ID,)
with self.subnet(cidr='20.0.0.0/24') as subnet1,\
self.subnet(cidr='30.0.0.0/24') as subnet2,\
self.port(subnet=subnet1,
device_owner=DEVICE_OWNER_COMPUTE,
arg_list=arg_list,
**{portbindings.HOST_ID: host}),\
self.port(subnet=subnet2,
device_owner=constants.DEVICE_OWNER_DHCP,
arg_list=arg_list,
**{portbindings.HOST_ID: host}):
router_ids = self.l3_plugin._get_dvr_router_ids_for_host(
self.context, host)
self.assertEqual([], router_ids)
self.l3_plugin.add_router_interface(
self.context, router1['id'],
{'subnet_id': subnet1['subnet']['id']})
router_ids = self.l3_plugin._get_dvr_router_ids_for_host(
self.context, host)
expected = {router1['id']}
self.assertEqual(expected, set(router_ids))
self.l3_plugin.add_router_interface(
self.context, router2['id'],
{'subnet_id': subnet2['subnet']['id']})
router_ids = self.l3_plugin._get_dvr_router_ids_for_host(
self.context, host)
expected.add(router2['id'])
self.assertEqual(expected, set(router_ids))
def test__get_router_ids_for_agent(self):
router1 = self._create_router()
router2 = self._create_router()
router3 = self._create_router()
arg_list = (portbindings.HOST_ID,)
host = self.l3_agent['host']
with self.subnet() as ext_subnet,\
self.subnet(cidr='20.0.0.0/24') as subnet1,\
self.subnet(cidr='30.0.0.0/24') as subnet2,\
self.port(subnet=subnet1,
device_owner=DEVICE_OWNER_COMPUTE,
arg_list=arg_list,
**{portbindings.HOST_ID: host}),\
self.port(subnet=subnet2,
device_owner=constants.DEVICE_OWNER_DHCP,
arg_list=arg_list,
**{portbindings.HOST_ID: host}):
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [])
self.assertEqual([], ids)
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [router1['id'], router2['id']])
self.assertEqual([], ids)
self.l3_plugin.add_router_interface(
self.context, router1['id'],
{'subnet_id': subnet1['subnet']['id']})
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [])
self.assertEqual([router1['id']], ids)
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [router1['id']])
self.assertEqual([router1['id']], ids)
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [router1['id'], router2['id']])
self.assertEqual([router1['id']], ids)
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [router2['id']])
self.assertEqual([], ids)
self.l3_plugin.add_router_interface(
self.context, router2['id'],
{'subnet_id': subnet2['subnet']['id']})
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [])
self.assertEqual({router1['id'], router2['id']}, set(ids))
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [router1['id']])
self.assertEqual([router1['id']], ids)
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [router1['id'], router2['id']])
self.assertEqual({router1['id'], router2['id']}, set(ids))
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [router2['id']])
self.assertEqual([router2['id']], ids)
# make net external
ext_net_id = ext_subnet['subnet']['network_id']
self._update('networks', ext_net_id,
{'network': {external_net.EXTERNAL: True}})
# add external gateway to router
self.l3_plugin.update_router(
self.context, router3['id'],
{'router': {
'external_gateway_info': {'network_id': ext_net_id}}})
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [])
self.assertEqual({router1['id'], router2['id'], router3['id']},
set(ids))
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [router3['id']])
self.assertEqual([router3['id']], ids)
ids = self.l3_plugin._get_router_ids_for_agent(
self.context, self.l3_agent, [router1['id'], router3['id']])
self.assertEqual({router1['id'], router3['id']}, set(ids))
def test_remove_router_interface(self):
HOST1 = 'host1'
dvr_agent = helpers.register_l3_agent(