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
This commit is contained in:
parent
4503d21268
commit
ff3cfe054b
|
@ -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
|
||||
|
|
|
@ -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 '
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue