Merge "Introduce new queries to return DVR routers for a host"
This commit is contained in:
commit
66f4e0dd1c
|
@ -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)
|
||||
|
|
|
@ -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', {
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue