[L3] Check agent gateway port robustly

In patch [1] it introduced a binding of DB uniq constraint for L3
agent gateway. In some extreme case the DvrFipGatewayPortAgentBinding
is in DB while the gateway port not. The current code path only checks
the binding existence which will pass a "None" port to the following
code path that results an AttributeError. This patch adds a simple check
for that gateway port, if it is not created, new one.

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

Closes-Bug: #1883089
Change-Id: Ia90f2ee435b0a3476dbea028d3200cefe11e35e4
This commit is contained in:
LIU Yulong 2020-06-13 23:14:47 +08:00
parent f260d2aef3
commit 5fdfd4cbfc
2 changed files with 38 additions and 1 deletions

View File

@ -1065,13 +1065,14 @@ class _DVRAgentInterfaceMixin(object):
try:
fip_agent_port_obj.create()
except o_exc.NeutronDbObjectDuplicateEntry:
LOG.debug("Floating IP Agent Gateway port for network "
LOG.debug("Floating IP Gateway port agent binding for network "
"%(network)s already exists on host %(host)s. "
"Probably it was just created by other worker.",
{'network': network_id,
'host': host})
agent_port = self._get_agent_gw_ports_exist_for_network(
context, network_id, host, l3_agent_db['id'])
if agent_port:
LOG.debug("Floating IP Agent Gateway port %(gw)s found "
"for the destination host: %(dest_host)s",
{'gw': agent_port,

View File

@ -763,6 +763,42 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
mock.call(self.ctx, network_id, 'host', fipagent['id'])])
self.assertIsNotNone(fport)
def test_create_fip_agent_gw_port_agent_binding_exists(self):
network_id = _uuid()
fport_db = {'id': _uuid()}
self.mixin._get_agent_gw_ports_exist_for_network = mock.Mock(
side_effect=[None, None])
fipagent = agent_obj.Agent(
self.ctx,
id=_uuid(),
binary='foo-agent',
host='host',
agent_type='L3 agent',
topic='foo_topic',
configurations={"agent_mode": "dvr"})
self.mixin._get_agent_by_type_and_host = mock.Mock(
return_value=fipagent)
self.mixin._populate_mtu_and_subnets_for_ports = mock.Mock()
with mock.patch.object(
router_obj.DvrFipGatewayPortAgentBinding, 'create',
side_effect=o_exc.NeutronDbObjectDuplicateEntry(
mock.Mock(), mock.Mock())
) as dvr_fip_gateway_port_agent_binding_create,\
mock.patch.object(
plugin_utils, "create_port", return_value=fport_db):
fport = self.mixin.create_fip_agent_gw_port_if_not_exists(
self.ctx,
network_id,
'host')
dvr_fip_gateway_port_agent_binding_create.assert_called_once_with()
self.mixin._get_agent_gw_ports_exist_for_network.assert_has_calls([
mock.call(self.ctx, network_id, 'host', fipagent['id']),
mock.call(self.ctx, network_id, 'host', fipagent['id'])])
self.mixin._populate_mtu_and_subnets_for_ports.assert_has_calls([
mock.call(self.ctx, [fport_db])])
self.assertIsNotNone(fport)
def test_create_floatingip_agent_gw_port_with_non_dvr_router(self):
floatingip = {
'id': _uuid(),