Clean dvr fip gateway entry when fip agent gw port is deleted

In [1] there was introduced new db table which stored information about
which DVR L3 agent has got already floating ip gateway port. It was to
avoid race conditions and ensure that there is always only one such port
per network and per agent (host).
Unfortunately in [1] there was no added removal of correct record from
this db table so it was causing problems when such port had to be
recreated after it was already on the host and was deleted.

This patch adds removal of such entry from db when needed.

Closes-Bug: #1866336

[1] https://review.opendev.org/#/c/702547/

Change-Id: I56efd1b9f09c0449ce531a185fcf4db353f99fe1
This commit is contained in:
Slawek Kaplonski 2020-03-02 13:56:21 +01:00
parent 129c68ef39
commit 2baeae7519
2 changed files with 46 additions and 3 deletions

View File

@ -360,6 +360,22 @@ class DVRResourceOperationHandler(object):
self.l3plugin.l3_rpc_notifier.delete_fipnamespace_for_ext_net(
payload.context, network_id)
def _delete_fip_agent_port(self, context, network_id, host_id):
try:
l3_agent_db = self._get_agent_by_type_and_host(
context, const.AGENT_TYPE_L3, host_id)
except agent_exc.AgentNotFoundByTypeHost:
LOG.warning("%(ag)s agent not found for the given host: %(host)s",
{'ag': const.AGENT_TYPE_L3,
'host': host_id})
return
try:
l3_obj.DvrFipGatewayPortAgentBinding(
context, network_id=network_id,
agent_id=l3_agent_db['id']).delete()
except n_exc.ObjectNotFound:
pass
def delete_floatingip_agent_gateway_port(self, context, host_id,
ext_net_id):
"""Function to delete FIP gateway port with given ext_net_id."""
@ -371,6 +387,8 @@ class DVRResourceOperationHandler(object):
for p in ports:
if not host_id or p[portbindings.HOST_ID] == host_id:
self._core_plugin.ipam.delete_port(context, p['id'])
self._delete_fip_agent_port(
context, ext_net_id, p[portbindings.HOST_ID])
if host_id:
return

View File

@ -395,7 +395,8 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
routers = self.mixin._build_routers_list(self.ctx, routers, gw_ports)
self.assertIsNone(routers[0].get('gw_port'))
def _helper_delete_floatingip_agent_gateway_port(self, port_host):
def _helper_delete_floatingip_agent_gateway_port(
self, port_host, delete_dvr_fip_agent_port_side_effect=None):
ports = [{
'id': 'my_port_id',
portbindings.HOST_ID: 'foo_host',
@ -411,17 +412,31 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
plugin = mock.Mock()
directory.add_plugin(plugin_constants.CORE, plugin)
plugin.get_ports.return_value = ports
self.mixin.delete_floatingip_agent_gateway_port(
self.ctx, port_host, 'ext_network_id')
self.mixin._get_agent_by_type_and_host = mock.Mock(
return_value={'id': uuidutils.generate_uuid()})
with mock.patch.object(
router_obj, "DvrFipGatewayPortAgentBinding"
) as dvr_fip_agent_port_obj:
dvr_fip_agent_port_obj_instance = (
dvr_fip_agent_port_obj.return_value)
dvr_fip_agent_port_obj_instance.delete.side_effect = (
delete_dvr_fip_agent_port_side_effect)
self.mixin.delete_floatingip_agent_gateway_port(
self.ctx, port_host, 'ext_network_id')
plugin.get_ports.assert_called_with(self.ctx, filters={
'network_id': ['ext_network_id'],
'device_owner': [const.DEVICE_OWNER_AGENT_GW]})
if port_host:
plugin.ipam.delete_port.assert_called_once_with(
self.ctx, 'my_port_id')
dvr_fip_agent_port_obj_instance.delete.assert_called_once()
else:
plugin.ipam.delete_port.assert_called_with(
self.ctx, 'my_new_port_id')
dvr_fip_agent_port_obj_instance.delete.assert_called()
def test_delete_floatingip_agent_gateway_port_without_host_id(self):
self._helper_delete_floatingip_agent_gateway_port(None)
@ -430,6 +445,16 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
self._helper_delete_floatingip_agent_gateway_port(
'foo_host')
def test_delete_floatingip_agent_gateway_port_no_host_id_fip_gw_not_found(
self):
self._helper_delete_floatingip_agent_gateway_port(
None, exceptions.ObjectNotFound(id='my_port_id'))
def test_delete_floatingip_agent_gateway_port_host_id_fip_gw_not_found(
self):
self._helper_delete_floatingip_agent_gateway_port(
'foo_host', exceptions.ObjectNotFound(id='my_port_id'))
def _setup_delete_current_gw_port_deletes_dvr_internal_ports(
self, port=None, gw_port=True, new_network_id='ext_net_id_2'):
router_db = {