diff --git a/neutron/scheduler/l3_agent_scheduler.py b/neutron/scheduler/l3_agent_scheduler.py index d30a2c03ea2..d15d1fd9754 100644 --- a/neutron/scheduler/l3_agent_scheduler.py +++ b/neutron/scheduler/l3_agent_scheduler.py @@ -302,6 +302,11 @@ class L3Scheduler(object): LOG.debug("Router %(router)s already scheduled for agent " "%(agent)s", {'router': router_id, 'agent': agent['id']}) + port_id = port_binding.port_id + # Below call will also delete entry from L3HARouterAgentPortBinding + # and RouterPort tables + plugin._core_plugin.delete_port(context, port_id, + l3_port_check=False) except l3.RouterNotFound: LOG.debug('Router %s has already been removed ' 'by concurrent operation', router_id) diff --git a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py index 56abd752d90..29892a2b37a 100644 --- a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py +++ b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py @@ -1368,6 +1368,35 @@ class L3HATestCaseMixin(testlib_api.SqlTestCase, self.plugin, self.adminContext, router['id'], router['tenant_id'], agent) + def test_create_ha_port_and_bind_wont_create_redundant_ports(self): + # When migrating from HA to DVR+HA router, create_ha_port_and_bind + # should create only one network:router_ha_interface port on a router + # when binding to same agent. So we need only one agent for testing + # (preferably with dvr_snat mode). + for agent in self.adminContext.session.query( + agent_model.Agent).all(): + agent.admin_state_up = False + l3_dvr_snat_agent = helpers.register_l3_agent( + 'fake_l3_host_dvr_snat', constants.L3_AGENT_MODE_DVR_SNAT) + router = self._create_ha_router(tenant_id='foo_tenant') + self.plugin.schedule_router(self.adminContext, router['id']) + router['admin_state_up'] = False + updated_router1 = self.plugin.update_router( + self.adminContext, router['id'], {'router': router}) + updated_router1['distributed'] = True + self.plugin.update_router( + self.adminContext, router['id'], {'router': updated_router1}) + + self.plugin.router_scheduler.create_ha_port_and_bind( + self.plugin, self.adminContext, router['id'], + router['tenant_id'], l3_dvr_snat_agent) + filters = {'device_owner': ['network:router_ha_interface'], + 'device_id': [router['id']]} + self.core_plugin = directory.get_plugin() + ports = self.core_plugin.get_ports( + self.adminContext, filters=filters) + self.assertEqual(1, len(ports)) + def test_create_ha_port_and_bind_catch_router_not_found(self): router = self._create_ha_router(tenant_id='foo_tenant') self.plugin.schedule_router(self.adminContext, router['id'])