summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Harlow <harlowja@yahoo-inc.com>2015-10-22 17:15:24 -0700
committerJoshua Harlow <harlowja@yahoo-inc.com>2015-10-22 17:23:08 -0700
commitff3cfe054bc31937376228a6a4830face6f3914b (patch)
tree8303e40a24595264aaa92f52b941716a482414b7
parent4503d21268075feb05932217df38f7b38cd5994c (diff)
downloadoslo-middleware-ff3cfe054bc31937376228a6a4830face6f3914b.tar.gz
Add a disabled by ports -> files healthcheck plugin
Since most openstack applications do not run on a single port it is useful to be able to have a single healthcheck plugin that can respond to requests for different ports with different files; this way for example keystone admin port can be disabled while its public port can be kept active (without having to run two different applications, one for the admin endpoint and one for the public endpoint). Change-Id: I0bafb5a2091e54c9f01f24812438296b75afaf63
-rw-r--r--oslo_middleware/healthcheck/__init__.py3
-rw-r--r--oslo_middleware/healthcheck/disable_by_file.py53
-rw-r--r--oslo_middleware/healthcheck/pluginbase.py2
-rw-r--r--oslo_middleware/tests/test_healthcheck.py41
-rw-r--r--setup.cfg1
5 files changed, 94 insertions, 6 deletions
diff --git a/oslo_middleware/healthcheck/__init__.py b/oslo_middleware/healthcheck/__init__.py
index 9e46bd8..d3b6a35 100644
--- a/oslo_middleware/healthcheck/__init__.py
+++ b/oslo_middleware/healthcheck/__init__.py
@@ -343,7 +343,8 @@ class Healthcheck(base.ConfigurableMiddleware):
def process_request(self, req):
if req.path != self._path:
return None
- results = [ext.obj.healthcheck() for ext in self._backends]
+ results = [ext.obj.healthcheck(req.server_port)
+ for ext in self._backends]
healthy = self._are_results_healthy(results)
if req.method == "HEAD":
functor = self._make_head_response
diff --git a/oslo_middleware/healthcheck/disable_by_file.py b/oslo_middleware/healthcheck/disable_by_file.py
index cd438cf..e422f91 100644
--- a/oslo_middleware/healthcheck/disable_by_file.py
+++ b/oslo_middleware/healthcheck/disable_by_file.py
@@ -22,6 +22,57 @@ from oslo_middleware.healthcheck import pluginbase
LOG = logging.getLogger(__name__)
+class DisableByFilesPortsHealthcheck(pluginbase.HealthcheckBaseExtension):
+ """DisableByFilesPorts healthcheck middleware plugin
+
+ This plugin checks presence of a file that is provided for a application
+ running on a certain port to report if the service is unavailable
+ or not.
+
+ Example of middleware configuration:
+
+ .. code-block:: ini
+
+ [filter:healthcheck]
+ paste.filter_factory = oslo_middleware:Healthcheck.factory
+ path = /healthcheck
+ backends = disable_by_files_ports
+ disable_by_file_paths = 5000:/var/run/keystone/healthcheck_disable, \
+ 35357:/var/run/keystone/admin_healthcheck_disable
+ """
+ def __init__(self, conf):
+ super(DisableByFilesPortsHealthcheck, self).__init__(conf)
+ self.status_files = {}
+ self.status_files.update(
+ self._iter_paths_ports(self.conf.get('disable_by_file_paths')))
+
+ @staticmethod
+ def _iter_paths_ports(paths):
+ if paths:
+ for port_path in paths.split(","):
+ port_path = port_path.strip()
+ if port_path:
+ port, path = port_path.split(":")
+ port = int(port)
+ yield (port, path)
+
+ def healthcheck(self, server_port):
+ path = self.status_files.get(server_port)
+ if not path:
+ LOG.warning(_LW('DisableByFilesPorts healthcheck middleware'
+ ' enabled without disable_by_file_paths set'
+ ' for port %s') % server_port)
+ return pluginbase.HealthcheckResult(available=True,
+ reason="OK")
+ else:
+ if not os.path.exists(path):
+ return pluginbase.HealthcheckResult(available=True,
+ reason="OK")
+ else:
+ return pluginbase.HealthcheckResult(available=False,
+ reason="DISABLED BY FILE")
+
+
class DisableByFileHealthcheck(pluginbase.HealthcheckBaseExtension):
"""DisableByFile healthcheck middleware plugin
@@ -39,7 +90,7 @@ class DisableByFileHealthcheck(pluginbase.HealthcheckBaseExtension):
disable_by_file_path = /var/run/nova/healthcheck_disable
"""
- def healthcheck(self):
+ def healthcheck(self, server_port):
path = self.conf.get('disable_by_file_path')
if path is None:
LOG.warning(_LW('DisableByFile healthcheck middleware enabled '
diff --git a/oslo_middleware/healthcheck/pluginbase.py b/oslo_middleware/healthcheck/pluginbase.py
index ffd3e08..e95749c 100644
--- a/oslo_middleware/healthcheck/pluginbase.py
+++ b/oslo_middleware/healthcheck/pluginbase.py
@@ -28,7 +28,7 @@ class HealthcheckBaseExtension(object):
self.conf = conf
@abc.abstractmethod
- def healthcheck():
+ def healthcheck(self, server_port):
"""method called by the healthcheck middleware
return: HealthcheckResult object
diff --git a/oslo_middleware/tests/test_healthcheck.py b/oslo_middleware/tests/test_healthcheck.py
index 144d274..3ffb03f 100644
--- a/oslo_middleware/tests/test_healthcheck.py
+++ b/oslo_middleware/tests/test_healthcheck.py
@@ -29,18 +29,21 @@ class HealthcheckTests(test_base.BaseTestCase):
return 'Hello, World!!!'
def _do_test_request(self, conf={}, path='/healthcheck',
- accept='text/plain', method='GET'):
+ accept='text/plain', method='GET',
+ server_port=80):
self.app = healthcheck.Healthcheck(self.application, conf)
req = webob.Request.blank(path, accept=accept, method=method)
+ req.server_port = server_port
res = req.get_response(self.app)
return res
def _do_test(self, conf={}, path='/healthcheck',
expected_code=webob.exc.HTTPOk.code,
expected_body=b'', accept='text/plain',
- method='GET'):
+ method='GET', server_port=80):
res = self._do_test_request(conf=conf, path=path,
- accept=accept, method=method)
+ accept=accept, method=method,
+ server_port=server_port)
self.assertEqual(expected_code, res.status_int)
self.assertEqual(expected_body, res.body)
@@ -125,3 +128,35 @@ class HealthcheckTests(test_base.BaseTestCase):
expected_code=webob.exc.HTTPServiceUnavailable.code,
expected_body=b'DISABLED BY FILE\nDISABLED BY FILE')
self.assertIn('disable_by_file', self.app._backends.names())
+
+ def test_disable_by_port_file(self):
+ filename = self.create_tempfiles([('test', 'foobar')])[0]
+ conf = {'backends': 'disable_by_files_ports',
+ 'disable_by_file_paths': "80:%s" % filename}
+ self._do_test(conf,
+ expected_code=webob.exc.HTTPServiceUnavailable.code,
+ expected_body=b'DISABLED BY FILE')
+ self.assertIn('disable_by_files_ports', self.app._backends.names())
+
+ def test_no_disable_by_port_file(self):
+ filename = self.create_tempfiles([('test', 'foobar')])[0]
+ conf = {'backends': 'disable_by_files_ports',
+ 'disable_by_file_paths': "8000:%s" % filename}
+ self._do_test(conf,
+ expected_code=webob.exc.HTTPOk.code,
+ expected_body=b'OK')
+ self.assertIn('disable_by_files_ports', self.app._backends.names())
+
+ def test_disable_by_port_many_files(self):
+ filename = self.create_tempfiles([('test', 'foobar')])[0]
+ filename2 = self.create_tempfiles([('test2', 'foobar2')])[0]
+ conf = {'backends': 'disable_by_files_ports',
+ 'disable_by_file_paths': "80:%s,81:%s" % (filename, filename2)}
+ self._do_test(conf,
+ expected_code=webob.exc.HTTPServiceUnavailable.code,
+ expected_body=b'DISABLED BY FILE')
+ self._do_test(conf,
+ expected_code=webob.exc.HTTPServiceUnavailable.code,
+ expected_body=b'DISABLED BY FILE',
+ server_port=81)
+ self.assertIn('disable_by_files_ports', self.app._backends.names())
diff --git a/setup.cfg b/setup.cfg
index 63cf0d6..8ad6c42 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -36,6 +36,7 @@ oslo.config.opts =
oslo.middleware.healthcheck =
disable_by_file = oslo_middleware.healthcheck.disable_by_file:DisableByFileHealthcheck
+ disable_by_files_ports = oslo_middleware.healthcheck.disable_by_file:DisableByFilesPortsHealthcheck
[build_sphinx]
source-dir = doc/source