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.

(manually cherry picked from commit
cd3264a07e)

Closes-Bug: #1973765
Change-Id: Iad9839ce99d50b969924b3fe369301b6dfed369d
This commit is contained in:
Fernando Royo 2022-07-04 10:43:54 +02:00
parent 1b162af1ad
commit 4d15d0d2f6
2 changed files with 37 additions and 0 deletions

View File

@ -2009,6 +2009,18 @@ class OvnProviderHelper(object):
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['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

@ -3856,6 +3856,31 @@ class TestOvnProviderHelper(TestOvnOctaviaBase):
net_cli.assert_has_calls(expected_call)
self.helper._update_status_to_octavia.assert_not_called()
@mock.patch('ovn_octavia_provider.driver.get_neutron_client')
@mock.patch.object(ovn_driver.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')