Add new STATS worker message.

This implements phase 1 of monitoring by basically checking that
HAProxy is alive. A new STATS message is recognized. The response
to this message will, so far, contain only a PASS/FAIL response,
and an error message in the case of FAIL.

The next phase will be to add backend node checking. This will
likely be combined with reporting usage statistics at a later phase.

Change-Id: Ie381c4cbb91dad90074f5addd3c4e3cf24dd33d8
This commit is contained in:
David Shrewsbury
2013-04-08 09:51:26 -04:00
parent 197eaab8b5
commit 912f0fe55d
4 changed files with 76 additions and 43 deletions

View File

@@ -1,17 +0,0 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
class ServiceUnavailable(Exception):
pass

View File

@@ -64,6 +64,8 @@ class LBaaSController(object):
return self._action_discover()
elif action == 'ARCHIVE':
return self._action_archive()
elif action == 'STATS':
return self._action_stats()
else:
self.logger.error("Invalid `%s` value: %s" %
(self.ACTION_FIELD, action))
@@ -331,3 +333,21 @@ class LBaaSController(object):
else:
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_SUCCESS
return self.msg
def _action_stats(self):
""" Get load balancer statistics. """
try:
# TODO: Do something with the returned statistics
self.driver.get_stats(protocol=None)
except NotImplementedError:
error = "Selected driver does not support STATS action."
self.logger.error(error)
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_FAILURE
self.msg[self.ERROR_FIELD] = error
except Exception as e:
self.logger.error("STATS failed: %s, %s" % (e.__class__, e))
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_FAILURE
self.msg[self.ERROR_FIELD] = str(e)
else:
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_SUCCESS
return self.msg

View File

@@ -0,0 +1,50 @@
# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import subprocess
class HAProxyQuery(object):
""" Class used for querying the HAProxy statistics socket. """
def __init__(self, stats_socket):
"""
stats_socket
Path to the HAProxy statistics socket file.
"""
self.socket = stats_socket
def _query(self, query):
"""
Send the given query to the haproxy statistics socket.
Return the output of a successful query as a string with trailing
newlines removed, or raise an Exception if the query fails.
"""
cmd = 'echo "%s" | sudo -n /usr/bin/socat stdio %s' % \
(query, self.socket)
try:
output = subprocess.check_output(cmd, shell=True)
except subprocess.CalledProcessError:
raise Exception("HAProxy '%s' query failed." % query)
return output.rstrip()
def show_info(self):
""" Get and parse output from 'show info' command. """
results = self._query('show info')
list_results = results.split('\n')
# TODO: Parse the results into a well defined format.
return list_results

View File

@@ -12,13 +12,12 @@
# License for the specific language governing permissions and limitations
# under the License.
import csv
import os
import subprocess
from libra.common.exc import ServiceUnavailable
from libra.common.lbstats import LBStatistics
from libra.worker.drivers.haproxy.services_base import ServicesBase
from libra.worker.drivers.haproxy.query import HAProxyQuery
class UbuntuServices(ServicesBase):
@@ -141,32 +140,13 @@ class UbuntuServices(ServicesBase):
"""
if not os.path.exists(self._haproxy_pid):
raise ServiceUnavailable()
raise Exception("HAProxy is not running.")
stats = LBStatistics()
query = HAProxyQuery('/var/run/haproxy-stats.socket')
cmd = 'echo "show stat" | ' \
'sudo -n /usr/bin/socat stdio /var/run/haproxy-stats.socket'
try:
csv_output = subprocess.check_output(cmd, shell=True)
except subprocess.CalledProcessError as e:
raise Exception("Failed to get statistics: %s" % e)
# Remove leading '# ' from string and trailing newlines
csv_output = csv_output[2:].rstrip()
# Turn string into a list, removing last two empty lines
csv_lines = csv_output.split('\n')
proxy_name = "%s-in" % protocol.lower()
service_name = "FRONTEND"
reader = csv.DictReader(csv_lines)
for row in reader:
if row['pxname'] == proxy_name and row['svname'] == service_name:
if row['bout']:
stats.bytes_out = long(row['bout'])
if row['bin']:
stats.bytes_in = long(row['bin'])
break
# TODO: Do something with the returned results. For now, we are
# basically just treating this as a 'ping' to the process.
query.show_info()
return stats