Update pool member operating status for haproxy

Collection of stats is a period task for which the HAProxy driver also
returns member statuses, including 'status' field which maps to
MemberV2.operating_status. Updating such field in neutron-lbaas DB
ensures the stored operational status is up-to-date. Subsequently, the
operating status of pools, listeners and load balancers can also be
correctly reported to users upon querying in for the load balancer
status tree API.

This fixes cases where a pool member becomes offline in the dataplane
but is not observed in neutron-lbaas. If a member turns back online
again, its operating status will be updated too.

Partial-Bug: #1548774

Change-Id: Ief872b0463002b4e339f8eab71b37a4225d461cc
(cherry picked from commit 80a086695d)
This commit is contained in:
Carlos Goncalves 2017-11-18 10:21:43 +00:00
parent dbdbbee9e7
commit ebc3f735e5
3 changed files with 23 additions and 5 deletions

View File

@ -261,9 +261,13 @@ class LoadBalancerPluginDbv2(base_db.CommonDbMixin,
if provisioning_status and (model_db.provisioning_status !=
provisioning_status):
model_db.provisioning_status = provisioning_status
LOG.debug("Provisioning status of %s (id=%s) updated to: %s",
model_db.NAME, model_db.id, provisioning_status)
if (operating_status and hasattr(model_db, 'operating_status') and
model_db.operating_status != operating_status):
model_db.operating_status = operating_status
LOG.debug("Operating status of %s (id=%s) updated to: %s",
model_db.NAME, model_db.id, operating_status)
def create_loadbalancer_graph(self, context, loadbalancer,
allocate_vip=True):

View File

@ -298,9 +298,9 @@ class HaproxyNSDriver(agent_device_driver.AgentDeviceDriver):
for stats in parsed_stats:
if stats.get('type') == STATS_TYPE_SERVER_RESPONSE:
res[stats['svname']] = {
lb_const.STATS_STATUS: (constants.INACTIVE
lb_const.OPERATING_STATUS: (lb_const.OFFLINE
if stats['status'] == 'DOWN'
else constants.ACTIVE),
else lb_const.ONLINE),
lb_const.STATS_HEALTH: stats['check_status'],
lb_const.STATS_FAILED_CHECKS: stats['chkfail']
}
@ -458,7 +458,20 @@ class LoadBalancerManager(agent_device_driver.BaseLoadBalancerManager):
self.refresh(loadbalancer)
def get_stats(self, loadbalancer_id):
return self.driver.get_stats(loadbalancer_id)
stats = self.driver.get_stats(loadbalancer_id)
# NOTE(cgoncalves): haproxy stats include member status which maps to
# MemberV2.operating_status. Take the opportunty to update member
# operating status.
members = stats.get('members')
if members:
for member_id, value in members.items():
if lb_const.OPERATING_STATUS in value:
self.driver.plugin_rpc.update_status(
'member', member_id,
operating_status=value[lb_const.OPERATING_STATUS])
return stats
def update(self, old_loadbalancer, loadbalancer):
self.refresh(loadbalancer)

View File

@ -196,12 +196,12 @@ class TestHaproxyNSDriver(base.BaseTestCase):
'total_connections': '10',
'members': {
'32a6c2a3-420a-44c3-955d-86bd2fc6871e': {
'status': 'ACTIVE',
'operating_status': 'ONLINE',
'health': 'L7OK',
'failed_checks': '0'
},
'd9aea044-8867-4e80-9875-16fb808fa0f9': {
'status': 'INACTIVE',
'operating_status': 'OFFLINE',
'health': 'L4CON',
'failed_checks': '9'
}
@ -594,6 +594,7 @@ class TestLoadBalancerManager(BaseTestLoadBalancerManager):
self.lb_manager.refresh.assert_called_once_with(self.in_lb)
def test_get_stats(self):
self.driver.get_stats.return_value = {'members': {}}
self.lb_manager.get_stats(self.in_lb.id)
self.driver.get_stats.assert_called_once_with(self.in_lb.id)