From 80a086695d11aa65251889671a3d729f62779c80 Mon Sep 17 00:00:00 2001 From: Carlos Goncalves Date: Sat, 18 Nov 2017 10:21:43 +0000 Subject: [PATCH] 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 --- .../db/loadbalancer/loadbalancer_dbv2.py | 4 ++++ .../drivers/haproxy/namespace_driver.py | 19 ++++++++++++++++--- .../drivers/haproxy/test_namespace_driver.py | 5 +++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/neutron_lbaas/db/loadbalancer/loadbalancer_dbv2.py b/neutron_lbaas/db/loadbalancer/loadbalancer_dbv2.py index 2fdec66e8..f9dd1a63c 100644 --- a/neutron_lbaas/db/loadbalancer/loadbalancer_dbv2.py +++ b/neutron_lbaas/db/loadbalancer/loadbalancer_dbv2.py @@ -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): diff --git a/neutron_lbaas/drivers/haproxy/namespace_driver.py b/neutron_lbaas/drivers/haproxy/namespace_driver.py index 05632412e..f2c5b6e78 100644 --- a/neutron_lbaas/drivers/haproxy/namespace_driver.py +++ b/neutron_lbaas/drivers/haproxy/namespace_driver.py @@ -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) diff --git a/neutron_lbaas/tests/unit/drivers/haproxy/test_namespace_driver.py b/neutron_lbaas/tests/unit/drivers/haproxy/test_namespace_driver.py index 59e6134e4..c63fb8d54 100644 --- a/neutron_lbaas/tests/unit/drivers/haproxy/test_namespace_driver.py +++ b/neutron_lbaas/tests/unit/drivers/haproxy/test_namespace_driver.py @@ -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)