Fix LB failover when IP addresses exhausted

When a load balancer failover was performed on a load balancer where
the VIP address is on a subnet that has no IP addresses available,
the VIP address may be deactivated.
This patch corrects the failover flow to not deallocate the VIP
address on a failover revert flow due to the subnet being out of
IP addresses.

Story: 2008625
Task: 41827
Change-Id: I1fe342d2bdf1301dd89ab7dfaa8e6a23e69c252b
(cherry picked from commit e3ab49c60a)
This commit is contained in:
Michael Johnson 2021-03-04 23:47:15 +00:00
parent 89724475d0
commit 4c9d7405af
4 changed files with 37 additions and 2 deletions

View File

@ -420,8 +420,8 @@ class LoadBalancerFlows(object):
# Check that the VIP port exists and is ok # Check that the VIP port exists and is ok
failover_LB_flow.add( failover_LB_flow.add(
network_tasks.AllocateVIP(requires=constants.LOADBALANCER, network_tasks.AllocateVIPforFailover(
provides=constants.VIP)) requires=constants.LOADBALANCER, provides=constants.VIP))
# Update the database with the VIP information # Update the database with the VIP information
failover_LB_flow.add(database_tasks.UpdateVIPAfterAllocation( failover_LB_flow.add(database_tasks.UpdateVIPAfterAllocation(

View File

@ -462,6 +462,20 @@ class AllocateVIP(BaseNetworkTask):
{'vip': vip.ip_address, 'except': e}) {'vip': vip.ip_address, 'except': e})
class AllocateVIPforFailover(AllocateVIP):
"""Task to allocate/validate the VIP for a failover flow."""
def revert(self, result, loadbalancer, *args, **kwargs):
"""Handle a failure to allocate vip."""
if isinstance(result, failure.Failure):
LOG.exception("Unable to allocate VIP")
return
vip = result
LOG.info("Failover revert is not deallocating vip %s because this is "
"a failover.", vip.ip_address)
class DeallocateVIP(BaseNetworkTask): class DeallocateVIP(BaseNetworkTask):
"""Task to deallocate a VIP.""" """Task to deallocate a VIP."""

View File

@ -716,6 +716,22 @@ class TestNetworkTasks(base.TestCase):
net.revert(vip_mock, LB) net.revert(vip_mock, LB)
mock_driver.deallocate_vip.assert_called_once_with(vip_mock) mock_driver.deallocate_vip.assert_called_once_with(vip_mock)
def test_allocate_vip_for_failover(self, mock_get_net_driver):
mock_driver = mock.MagicMock()
mock_get_net_driver.return_value = mock_driver
net = network_tasks.AllocateVIPforFailover()
mock_driver.allocate_vip.return_value = LB.vip
mock_driver.reset_mock()
self.assertEqual(LB.vip, net.execute(LB))
mock_driver.allocate_vip.assert_called_once_with(LB)
# revert
vip_mock = mock.MagicMock()
net.revert(vip_mock, LB)
mock_driver.deallocate_vip.assert_not_called()
def test_deallocate_vip(self, mock_get_net_driver): def test_deallocate_vip(self, mock_get_net_driver):
mock_driver = mock.MagicMock() mock_driver = mock.MagicMock()
mock_get_net_driver.return_value = mock_driver mock_get_net_driver.return_value = mock_driver

View File

@ -0,0 +1,5 @@
---
fixes:
- |
Fixes an issue with load balancer failover, when the VIP subnet is out of
IP addresses, that could lead to the VIP being deallocated.