Delete vip port if create_vip_port raise exception

Sometimes on heavy load over Neutron, operations over
neutron client could raise a NeutronClientException that
could cover, e.g. a timeout. In those case, sometimes the
request finish after the client timeout and we have
leftover resource.

create_vip_port is called from Octavia API just before
the create LB request, if this call raise a timeout
maybe the vip port is finally created and linked to a LB
that is not going to be created, so we have this port
unuse.

This patch will try to remove the leftover port for those
situations.

Closes-Bug: #1973765
Change-Id: Iad9839ce99d50b969924b3fe369301b6dfed369d
(cherry picked from commit cd3264a07e)
This commit is contained in:
Fernando Royo 2022-05-17 15:32:24 +02:00
parent b651d58fb1
commit 3a8aa3349a
2 changed files with 37 additions and 0 deletions

View File

@ -2010,6 +2010,18 @@ class OvnProviderHelper():
port = ports['ports'][0]
LOG.debug('VIP Port already exists, uuid: %s', port['id'])
return {'port': port}
except n_exc.NeutronClientException as e:
# NOTE (froyo): whatever other exception as e.g. Timeout
# we should try to ensure no leftover port remains
ports = neutron_client.list_ports(
network_id=vip_d[constants.VIP_NETWORK_ID],
name=f'{ovn_const.LB_VIP_PORT_PREFIX}{lb_id}')
if ports['ports']:
port = ports['ports'][0]
LOG.debug('Leftover port %s has been found. Trying to '
'delete it', port['id'])
self.delete_vip_port(port['id'])
raise e
@tenacity.retry(
retry=tenacity.retry_if_exception_type(

View File

@ -3202,6 +3202,31 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
net_cli.assert_has_calls(expected_call)
self.helper._update_status_to_octavia.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_vip_port')
def test_create_vip_port_vip_neutron_client_other_exception(
self, del_port, net_cli):
net_cli.return_value.create_port.side_effect = [
n_exc.NeutronClientException]
net_cli.return_value.list_ports.return_value = {
'ports': [
{'name': 'ovn-lb-vip-' + self.loadbalancer_id,
'id': self.loadbalancer_id}]}
self.assertRaises(
n_exc.NeutronClientException,
self.helper.create_vip_port,
self.project_id,
self.loadbalancer_id,
self.vip_dict)
expected_call = [
mock.call().list_ports(
network_id='%s' % self.vip_dict['vip_network_id'],
name='%s%s' % (ovn_const.LB_VIP_PORT_PREFIX,
self.loadbalancer_id))]
net_cli.assert_has_calls(expected_call)
del_port.assert_called_once_with(self.loadbalancer_id)
self.helper._update_status_to_octavia.assert_not_called()
def test_get_pool_member_id(self):
ret = self.helper.get_pool_member_id(
self.pool_id, mem_addr_port='192.168.2.149:1010')