Fix Load balancer remains on PENDING_CREATE

On LB creation process, when heavy load env situation
arises, neutron client could return several errors
that is currently not under control. At this way
Octavia API is not receiving an update status and LB
keeps on PENDING_CREATE without any apparent error.

This patch cover error on request over neutron client
(subnet, list ports...) in order to update to Octavia
API with ERROR status in case this situation achieved.

Closes-Bug: #1974052

Change-Id: I04edbbd631f63b79c10916ce2391bb0cb95c1c19
(cherry picked from commit 28d378868f)
This commit is contained in:
Fernando Royo 2022-05-18 17:28:43 +02:00
parent a7d5827a78
commit 4d86a7151c
2 changed files with 49 additions and 17 deletions

View File

@ -888,27 +888,49 @@ class OvnProviderHelper():
def lb_create(self, loadbalancer, protocol=None):
port = None
subnet = {}
neutron_client = clients.get_neutron_client()
if loadbalancer.get(constants.VIP_PORT_ID):
# In case we don't have vip_network_id
port = neutron_client.show_port(
loadbalancer[constants.VIP_PORT_ID])['port']
for ip in port['fixed_ips']:
if ip['ip_address'] == loadbalancer[constants.VIP_ADDRESS]:
subnet = neutron_client.show_subnet(
ip['subnet_id'])['subnet']
break
elif (loadbalancer.get(constants.VIP_NETWORK_ID) and
loadbalancer.get(constants.VIP_ADDRESS)):
ports = neutron_client.list_ports(
network_id=loadbalancer[constants.VIP_NETWORK_ID])
for p in ports['ports']:
for ip in p['fixed_ips']:
try:
neutron_client = clients.get_neutron_client()
if loadbalancer.get(constants.VIP_PORT_ID):
# In case we don't have vip_network_id
port = neutron_client.show_port(
loadbalancer[constants.VIP_PORT_ID])['port']
for ip in port['fixed_ips']:
if ip['ip_address'] == loadbalancer[constants.VIP_ADDRESS]:
port = p
subnet = neutron_client.show_subnet(
ip['subnet_id'])['subnet']
break
elif (loadbalancer.get(constants.VIP_NETWORK_ID) and
loadbalancer.get(constants.VIP_ADDRESS)):
ports = neutron_client.list_ports(
network_id=loadbalancer[constants.VIP_NETWORK_ID])
for p in ports['ports']:
for ip in p['fixed_ips']:
if ip['ip_address'] == loadbalancer[
constants.VIP_ADDRESS]:
port = p
subnet = neutron_client.show_subnet(
ip['subnet_id'])['subnet']
break
except Exception:
LOG.error('Cannot get info from neutron client')
LOG.exception(ovn_const.EXCEPTION_MSG, "creation of loadbalancer")
# Any Exception set the status to ERROR
if isinstance(port, dict):
try:
self.delete_vip_port(port.get('id'))
LOG.warning("Deleting the VIP port %s since LB went into "
"ERROR state", str(port.get('id')))
except Exception:
LOG.exception("Error deleting the VIP port %s upon "
"loadbalancer %s creation failure",
str(port.get('id')),
str(loadbalancer[constants.ID]))
status = {
constants.LOADBALANCERS: [
{constants.ID: loadbalancer[constants.ID],
constants.PROVISIONING_STATUS: constants.ERROR,
constants.OPERATING_STATUS: constants.ERROR}]}
return status
# If protocol set make sure its lowercase
protocol = protocol.lower() if protocol else []

View File

@ -632,6 +632,16 @@ class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
def test_lb_create_on_multi_protocol_SCTP(self):
self._test_lb_create_on_multi_protocol('SCTP')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_create_neutron_client_exception(self, net_cli):
net_cli.return_value.list_ports.return_value = self.ports
net_cli.return_value.show_subnet.side_effect = [n_exc.NotFound]
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_vip_port')
def test_lb_create_exception(self, del_port, net_cli):