diff options
-rw-r--r-- | oslo_middleware/healthcheck/__init__.py | 22 | ||||
-rw-r--r-- | oslo_middleware/healthcheck/disable_by_file.py | 38 | ||||
-rw-r--r-- | oslo_middleware/healthcheck/opts.py | 46 | ||||
-rw-r--r-- | oslo_middleware/healthcheck/pluginbase.py | 11 | ||||
-rw-r--r-- | oslo_middleware/opts.py | 31 | ||||
-rw-r--r-- | oslo_middleware/tests/test_healthcheck.py | 5 | ||||
-rw-r--r-- | setup.cfg | 1 |
7 files changed, 128 insertions, 26 deletions
diff --git a/oslo_middleware/healthcheck/__init__.py b/oslo_middleware/healthcheck/__init__.py index ce2b03a..65c2791 100644 --- a/oslo_middleware/healthcheck/__init__.py +++ b/oslo_middleware/healthcheck/__init__.py @@ -37,6 +37,7 @@ except ImportError: greenlet = None from oslo_middleware import base +from oslo_middleware.healthcheck import opts def _find_objects(t): @@ -374,18 +375,16 @@ Reason </HTML> """ - def __init__(self, application, conf): - super(Healthcheck, self).__init__(application) - self._path = conf.get('path', '/healthcheck') - self._show_details = strutils.bool_from_string(conf.get('detailed')) - self._backend_names = [] - backends = conf.get('backends') - if backends: - self._backend_names = backends.split(',') + def __init__(self, *args, **kwargs): + super(Healthcheck, self).__init__(*args, **kwargs) + self.oslo_conf.register_opts(opts.HEALTHCHECK_OPTS, + group='healthcheck') + self._path = self._conf_get('path') + self._show_details = self._conf_get('detailed') self._backends = stevedore.NamedExtensionManager( - self.NAMESPACE, self._backend_names, + self.NAMESPACE, self._conf_get('backends'), name_order=True, invoke_on_load=True, - invoke_args=(conf,)) + invoke_args=(self.oslo_conf, self.conf)) self._accept_to_functor = collections.OrderedDict([ # Order here matters... ('text/plain', self._make_text_response), @@ -398,6 +397,9 @@ Reason # middleware actually can cause issues). self._default_accept = 'text/plain' + def _conf_get(self, key, group='healthcheck'): + return super(Healthcheck, self)._conf_get(key, group=group) + @staticmethod def _get_threadstacks(): threadstacks = [] diff --git a/oslo_middleware/healthcheck/disable_by_file.py b/oslo_middleware/healthcheck/disable_by_file.py index 7fbb14b..1b3ffa3 100644 --- a/oslo_middleware/healthcheck/disable_by_file.py +++ b/oslo_middleware/healthcheck/disable_by_file.py @@ -17,6 +17,7 @@ import logging import os from oslo_middleware._i18n import _LW +from oslo_middleware.healthcheck import opts from oslo_middleware.healthcheck import pluginbase LOG = logging.getLogger(__name__) @@ -40,23 +41,25 @@ class DisableByFilesPortsHealthcheck(pluginbase.HealthcheckBaseExtension): 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) + + def __init__(self, *args, **kwargs): + super(DisableByFilesPortsHealthcheck, self).__init__(*args, **kwargs) + self.oslo_conf.register_opts(opts.DISABLE_BY_FILES_OPTS, + group='healthcheck') self.status_files = {} - self.status_files.update( - self._iter_paths_ports(self.conf.get('disable_by_file_paths'))) + paths = self._conf_get('disable_by_file_paths') + self.status_files.update(self._iter_paths_ports(paths)) @staticmethod def _iter_paths_ports(paths): - if paths: - for port_path in paths.split(","): - port_path = port_path.strip() - if port_path: - # On windows, drive letters are followed by colons, - # which makes split() return 3 elements in this case - port, path = port_path.split(":", 1) - port = int(port) - yield (port, path) + for port_path in paths: + port_path = port_path.strip() + if port_path: + # On windows, drive letters are followed by colons, + # which makes split() return 3 elements in this case + port, path = port_path.split(":", 1) + port = int(port) + yield (port, path) def healthcheck(self, server_port): path = self.status_files.get(server_port) @@ -92,9 +95,14 @@ class DisableByFileHealthcheck(pluginbase.HealthcheckBaseExtension): disable_by_file_path = /var/run/nova/healthcheck_disable """ + def __init__(self, *args, **kwargs): + super(DisableByFileHealthcheck, self).__init__(*args, **kwargs) + self.oslo_conf.register_opts(opts.DISABLE_BY_FILE_OPTS, + group='healthcheck') + def healthcheck(self, server_port): - path = self.conf.get('disable_by_file_path') - if path is None: + path = self._conf_get('disable_by_file_path') + if not path: LOG.warning(_LW('DisableByFile healthcheck middleware enabled ' 'without disable_by_file_path set')) return pluginbase.HealthcheckResult( diff --git a/oslo_middleware/healthcheck/opts.py b/oslo_middleware/healthcheck/opts.py new file mode 100644 index 0000000..d283f4d --- /dev/null +++ b/oslo_middleware/healthcheck/opts.py @@ -0,0 +1,46 @@ +# 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. + +from oslo_config import cfg + + +HEALTHCHECK_OPTS = [ + cfg.StrOpt('path', + default='/healthcheck', + help='The path to respond to healtcheck requests on.'), + cfg.BoolOpt('detailed', + default=False, + help='Show more detailed information as part of the response'), + cfg.ListOpt('backends', + default=[], + help='Additional backends that can perform health checks and ' + 'report that information back as part of a request.'), +] + + +DISABLE_BY_FILE_OPTS = [ + cfg.StrOpt('disable_by_file_path', + default=None, + help='Check the presence of a file to determine if an ' + 'application is running on a port. Used by ' + 'DisableByFileHealthcheck plugin.'), +] + + +DISABLE_BY_FILES_OPTS = [ + cfg.ListOpt('disable_by_file_paths', + default=[], + help='Check the presence of a file based on a port to ' + 'determine if an application is running on a port. ' + 'Expects a "port:path" list of strings. Used by ' + 'DisableByFilesPortsHealthcheck plugin.'), +] diff --git a/oslo_middleware/healthcheck/pluginbase.py b/oslo_middleware/healthcheck/pluginbase.py index e370967..eb8013d 100644 --- a/oslo_middleware/healthcheck/pluginbase.py +++ b/oslo_middleware/healthcheck/pluginbase.py @@ -29,7 +29,9 @@ class HealthcheckResult(object): @six.add_metaclass(abc.ABCMeta) class HealthcheckBaseExtension(object): - def __init__(self, conf): + + def __init__(self, oslo_conf, conf): + self.oslo_conf = oslo_conf self.conf = conf @abc.abstractmethod @@ -38,3 +40,10 @@ class HealthcheckBaseExtension(object): return: HealthcheckResult object """ + + def _conf_get(self, key, group='healthcheck'): + if key in self.conf: + # Validate value type + self.oslo_conf.set_override(key, self.conf[key], group=group, + enforce_type=True) + return getattr(getattr(self.oslo_conf, group), key) diff --git a/oslo_middleware/opts.py b/oslo_middleware/opts.py index e66e723..1584f9b 100644 --- a/oslo_middleware/opts.py +++ b/oslo_middleware/opts.py @@ -19,6 +19,7 @@ __all__ = [ 'list_opts_ssl', 'list_opts_cors', 'list_opts_http_proxy_to_wsgi', + 'list_opts_healthcheck', ] @@ -26,6 +27,7 @@ import copy import itertools from oslo_middleware import cors +from oslo_middleware.healthcheck import opts as healthcheck_opts from oslo_middleware import http_proxy_to_wsgi from oslo_middleware import sizelimit from oslo_middleware import ssl @@ -56,6 +58,7 @@ def list_opts(): list_opts_ssl(), list_opts_cors(), list_opts_http_proxy_to_wsgi(), + list_opts_healthcheck(), ) ) @@ -155,3 +158,31 @@ def list_opts_http_proxy_to_wsgi(): return [ ('oslo_middleware', copy.deepcopy(http_proxy_to_wsgi.OPTS)), ] + + +def list_opts_healthcheck(): + """Return a list of oslo.config options for healthcheck. + + The returned list includes all oslo.config options which may be registered + at runtime by the library. + + Each element of the list is a tuple. The first element is the name of the + group under which the list of elements in the second element will be + registered. A group name of None corresponds to the [DEFAULT] group in + config files. + + This function is also discoverable via the 'oslo.middleware' entry point + under the 'oslo.config.opts' namespace. + + The purpose of this is to allow tools like the Oslo sample config file + generator to discover the options exposed to users by this library. + + :returns: a list of (group_name, opts) tuples + """ + # standard opts and the most common plugin to turn up in sample config. + # can figure out a better way of exposing plugin opts later if required. + return [ + ('healthcheck', copy.deepcopy(healthcheck_opts.HEALTHCHECK_OPTS + + healthcheck_opts.DISABLE_BY_FILE_OPTS + + healthcheck_opts.DISABLE_BY_FILES_OPTS)) + ] diff --git a/oslo_middleware/tests/test_healthcheck.py b/oslo_middleware/tests/test_healthcheck.py index df73969..793a895 100644 --- a/oslo_middleware/tests/test_healthcheck.py +++ b/oslo_middleware/tests/test_healthcheck.py @@ -17,6 +17,7 @@ import threading import time import mock +from oslo_config import fixture as config from oslotest import base as test_base import requests import webob.dec @@ -50,6 +51,10 @@ class HealthcheckMainTests(test_base.BaseTestCase): class HealthcheckTests(test_base.BaseTestCase): + def setUp(self): + super(HealthcheckTests, self).setUp() + self.useFixture(config.Config()) + @staticmethod @webob.dec.wsgify def application(req): @@ -29,6 +29,7 @@ oslo.config.opts = oslo.middleware.sizelimit = oslo_middleware.opts:list_opts_sizelimit oslo.middleware.ssl = oslo_middleware.opts:list_opts_ssl oslo.middleware.http_proxy_to_wsgi = oslo_middleware.opts:list_opts_http_proxy_to_wsgi + oslo.middleware.healthcheck = oslo_middleware.opts:list_opts_healthcheck oslo.middleware.healthcheck = disable_by_file = oslo_middleware.healthcheck.disable_by_file:DisableByFileHealthcheck |