diff options
author | Joshua Harlow <harlowja@yahoo-inc.com> | 2015-10-22 17:15:24 -0700 |
---|---|---|
committer | Joshua Harlow <harlowja@yahoo-inc.com> | 2015-10-22 17:23:08 -0700 |
commit | ff3cfe054bc31937376228a6a4830face6f3914b (patch) | |
tree | 8303e40a24595264aaa92f52b941716a482414b7 | |
parent | 4503d21268075feb05932217df38f7b38cd5994c (diff) | |
download | oslo-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__.py | 3 | ||||
-rw-r--r-- | oslo_middleware/healthcheck/disable_by_file.py | 53 | ||||
-rw-r--r-- | oslo_middleware/healthcheck/pluginbase.py | 2 | ||||
-rw-r--r-- | oslo_middleware/tests/test_healthcheck.py | 41 | ||||
-rw-r--r-- | setup.cfg | 1 |
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()) @@ -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 |