Fix LB failover when in ERROR

Load balancers in ERROR provisioning status could not be failed over.

One possible scenario where LBs go into ERROR is when services are
started before compute nodes are up on a cluster reboot:

- Octavia services are started
- Health Manager does not receive heartbeat and triggers failover
- Failover fails due to lack of availabble compute nodes to spawn
  amphora VMs

Story: 2005078
Task: 29657

Change-Id: Ic4b4516cd6b2a254ea32939668c906486066da42
This commit is contained in:
Carlos Goncalves 2019-02-22 23:34:44 +00:00
parent 6e0bed1c54
commit 503e3949f8
3 changed files with 17 additions and 2 deletions

View File

@ -106,6 +106,16 @@ class LoadBalancersController(base.BaseController):
raise exceptions.LBPendingStateError( raise exceptions.LBPendingStateError(
state=prov_status, id=id) state=prov_status, id=id)
def _test_and_set_failover_prov_status(self, session, id):
lb_repo = self.repositories.load_balancer
if not lb_repo.set_status_for_failover(session, id,
constants.PENDING_UPDATE):
prov_status = lb_repo.get(session, id=id).provisioning_status
LOG.info("Invalid state %(state)s of loadbalancer resource %(id)s",
{"state": prov_status, "id": id})
raise exceptions.LBPendingStateError(
state=prov_status, id=id)
@staticmethod @staticmethod
def _validate_network_and_fill_or_validate_subnet(load_balancer): def _validate_network_and_fill_or_validate_subnet(load_balancer):
network = validate.network_exists_optionally_contains_subnet( network = validate.network_exists_optionally_contains_subnet(
@ -717,7 +727,7 @@ class FailoverController(LoadBalancersController):
driver = driver_factory.get_driver(db_lb.provider) driver = driver_factory.get_driver(db_lb.provider)
with db_api.get_lock_session() as lock_session: with db_api.get_lock_session() as lock_session:
self._test_lb_status(lock_session, self.lb_id) self._test_and_set_failover_prov_status(lock_session, self.lb_id)
LOG.info("Sending failover request for load balancer %s to the " LOG.info("Sending failover request for load balancer %s to the "
"provider %s", self.lb_id, driver.name) "provider %s", self.lb_id, driver.name)
driver_utils.call_provider( driver_utils.call_provider(

View File

@ -1955,7 +1955,7 @@ class TestLoadBalancer(base.BaseAPITest):
status=constants.ERROR) status=constants.ERROR)
self.app.put(self._get_full_path( self.app.put(self._get_full_path(
self.LB_PATH.format(lb_id=lb_dict.get('id')) + "/failover"), self.LB_PATH.format(lb_id=lb_dict.get('id')) + "/failover"),
status=409) status=202)
def test_failover_not_authorized(self): def test_failover_not_authorized(self):
project_id = uuidutils.generate_uuid() project_id = uuidutils.generate_uuid()

View File

@ -0,0 +1,5 @@
---
fixes:
- |
Fix load balancers that could not be failed over when in ERROR provisioning
status.