from neutron.extensions import l3agentscheduler
from neutron.i18n import _LE, _LI, _LW
from neutron import manager
+from neutron.plugins.common import constants as service_constants
LOG = logging.getLogger(__name__)
return False
if router.get('distributed'):
return False
- # non-dvr case: centralized router is already bound to some agent
+ if router.get('ha'):
+ return True
+ # legacy router case: router is already bound to some agent
raise l3agentscheduler.RouterHostedByL3Agent(
router_id=router_id,
agent_id=bindings[0].l3_agent_id)
agent_id = agent['id']
if self.router_scheduler:
try:
- self.router_scheduler.bind_router(context, router_id, agent)
+ if router.get('ha'):
+ plugin = manager.NeutronManager.get_service_plugins().get(
+ service_constants.L3_ROUTER_NAT)
+ self.router_scheduler.create_ha_port_and_bind(
+ plugin, context, router['id'],
+ router['tenant_id'], agent)
+ else:
+ self.router_scheduler.bind_router(
+ context, router_id, agent)
except db_exc.DBError:
raise l3agentscheduler.RouterSchedulingFailed(
router_id=router_id, agent_id=agent_id)
"""
agent = self._get_agent(context, agent_id)
self._unbind_router(context, router_id, agent_id)
+
+ router = self.get_router(context, router_id)
+ if router.get('ha'):
+ plugin = manager.NeutronManager.get_service_plugins().get(
+ service_constants.L3_ROUTER_NAT)
+ plugin.delete_ha_interfaces_on_host(context, router_id, agent.host)
+
l3_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_L3)
if l3_notifier:
l3_notifier.router_removed_from_agent(
if router.get('ha'):
if not self._router_has_binding(context, router['id'],
l3_agent.id):
- self._create_ha_router_binding(
+ self.create_ha_port_and_bind(
plugin, context, router['id'],
router['tenant_id'], l3_agent)
else:
return False
return True
- def _create_ha_router_binding(self, plugin, context, router_id, tenant_id,
- agent):
+ def create_ha_port_and_bind(self, plugin, context, router_id,
+ tenant_id, agent):
"""Creates and binds a new HA port for this agent."""
ha_network = plugin.get_ha_network(context, tenant_id)
port_binding = plugin.add_ha_port(context.elevated(), router_id,
if max_agents_not_reached:
if not self._router_has_binding(admin_ctx, router_id,
agent.id):
- self._create_ha_router_binding(plugin, admin_ctx,
- router_id, tenant_id,
- agent)
+ self.create_ha_port_and_bind(plugin, admin_ctx,
+ router_id, tenant_id,
+ agent)
scheduled = True
return scheduled
'_router_has_binding',
return_value=has_binding) as mock_has_binding,\
mock.patch.object(self.scheduler,
- '_create_ha_router_binding') as mock_bind:
+ 'create_ha_port_and_bind') as mock_bind:
self.scheduler._bind_routers(mock.ANY, mock.ANY, routers, agent)
mock_has_binding.assert_called_once_with(mock.ANY, 'foo_router',
'foo_agent')
self.plugin = L3HAPlugin()
self.setup_coreplugin('neutron.plugins.ml2.plugin.Ml2Plugin')
+ cfg.CONF.set_override('service_plugins',
+ ['neutron.services.l3_router.'
+ 'l3_router_plugin.L3RouterPlugin'])
mock.patch.object(l3_hamode_db.L3_HA_NAT_db_mixin,
'_notify_ha_interfaces_updated').start()
class L3AgentSchedulerDbMixinTestCase(L3HATestCaseMixin):
- def test_reschedule_ha_routers_from_down_agents(self):
+ def _setup_ha_router(self):
router = self._create_ha_router()
self.plugin.schedule_router(self.adminContext, router['id'])
- agents = self.plugin.get_l3_agents_hosting_routers(
- self.adminContext, [router['id']],
- admin_state_up=True)
+ agents = self._get_agents_scheduled_for_router(router)
+ return router, agents
+
+ def test_reschedule_ha_routers_from_down_agents(self):
+ agents = self._setup_ha_router()[1]
self.assertEqual(2, len(agents))
self._set_l3_agent_dead(self.agent_id1)
with mock.patch.object(self.plugin, 'reschedule_router') as reschedule:
self.assertEqual({'agents': []},
self.plugin._get_agents_dict_for_router([]))
+ def test_manual_add_ha_router_to_agent(self):
+ cfg.CONF.set_override('max_l3_agents_per_router', 2)
+ router, agents = self._setup_ha_router()
+ self.assertEqual(2, len(agents))
+ agent = helpers.register_l3_agent(host='myhost_3')
+ # We allow to exceed max l3 agents per router via manual scheduling
+ self.plugin.add_router_to_l3_agent(
+ self.adminContext, agent.id, router['id'])
+ agents = self._get_agents_scheduled_for_router(router)
+ self.assertIn(agent.id, [_agent.id for _agent in agents])
+ self.assertEqual(3, len(agents))
+
+ def test_manual_remove_ha_router_from_agent(self):
+ router, agents = self._setup_ha_router()
+ self.assertEqual(2, len(agents))
+ agent = agents.pop()
+ # Remove router from agent and make sure it is removed
+ self.plugin.remove_router_from_l3_agent(
+ self.adminContext, agent.id, router['id'])
+ agents = self._get_agents_scheduled_for_router(router)
+ self.assertEqual(1, len(agents))
+ self.assertNotIn(agent.id, [_agent.id for _agent in agents])
+
+ def test_manual_remove_ha_router_from_all_agents(self):
+ router, agents = self._setup_ha_router()
+ self.assertEqual(2, len(agents))
+ agent = agents.pop()
+ self.plugin.remove_router_from_l3_agent(
+ self.adminContext, agent.id, router['id'])
+ agent = agents.pop()
+ self.plugin.remove_router_from_l3_agent(
+ self.adminContext, agent.id, router['id'])
+ agents = self._get_agents_scheduled_for_router(router)
+ self.assertEqual(0, len(agents))
+
+ def _get_agents_scheduled_for_router(self, router):
+ return self.plugin.get_l3_agents_hosting_routers(
+ self.adminContext, [router['id']],
+ admin_state_up=True)
+
+ def test_delete_ha_interfaces_from_agent(self):
+ router, agents = self._setup_ha_router()
+ agent = agents.pop()
+ self.plugin.remove_router_from_l3_agent(
+ self.adminContext, agent.id, router['id'])
+ session = self.adminContext.session
+ db = l3_hamode_db.L3HARouterAgentPortBinding
+ results = session.query(db).filter_by(
+ router_id=router['id'])
+ results = [binding.l3_agent_id for binding in results.all()]
+ self.assertNotIn(agent.id, results)
+
+ def test_add_ha_interface_to_l3_agent(self):
+ agent = self.plugin.get_agents_db(self.adminContext)[0]
+ router = self._create_ha_router()
+ self.plugin.add_router_to_l3_agent(self.adminContext, agent.id,
+ router['id'])
+ # Verify agent has HA interface
+ ha_ports = self.plugin.get_ha_router_port_bindings(self.adminContext,
+ [router['id']])
+ self.assertIn(agent.id, [ha_port.l3_agent_id for ha_port in ha_ports])
+
class L3HAChanceSchedulerTestCase(L3HATestCaseMixin):