Add a enabled by files healthcheck plugin
Implements: blueprint enable-by-files-healthcheck Change-Id: Ia8a54cbd38f2faf70bbe91032da36448f2fa2de7
This commit is contained in:
parent
e2ea8dc556
commit
01cd608104
@ -8,6 +8,9 @@
|
|||||||
.. automodule:: oslo_middleware.healthcheck.disable_by_file
|
.. automodule:: oslo_middleware.healthcheck.disable_by_file
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
.. automodule:: oslo_middleware.healthcheck.enable_by_files
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
Available Plugins
|
Available Plugins
|
||||||
------------------
|
------------------
|
||||||
|
@ -39,6 +39,7 @@ except ImportError:
|
|||||||
greenlet = None
|
greenlet = None
|
||||||
|
|
||||||
from oslo_middleware import base
|
from oslo_middleware import base
|
||||||
|
from oslo_middleware.basic_auth import ConfigInvalid
|
||||||
from oslo_middleware.healthcheck import opts
|
from oslo_middleware.healthcheck import opts
|
||||||
|
|
||||||
|
|
||||||
@ -397,6 +398,11 @@ Reason
|
|||||||
for r in self._conf_get('allowed_source_ranges')]
|
for r in self._conf_get('allowed_source_ranges')]
|
||||||
self._ignore_proxied_requests = self._conf_get(
|
self._ignore_proxied_requests = self._conf_get(
|
||||||
'ignore_proxied_requests')
|
'ignore_proxied_requests')
|
||||||
|
|
||||||
|
# (abhishekk): Verify that if `enable_by_files` and
|
||||||
|
# `disable_by_file` backends are not enabled at same time.
|
||||||
|
self._verify_configured_plugins()
|
||||||
|
|
||||||
self._backends = stevedore.NamedExtensionManager(
|
self._backends = stevedore.NamedExtensionManager(
|
||||||
self.NAMESPACE, self._conf_get('backends'),
|
self.NAMESPACE, self._conf_get('backends'),
|
||||||
name_order=True, invoke_on_load=True,
|
name_order=True, invoke_on_load=True,
|
||||||
@ -414,6 +420,16 @@ Reason
|
|||||||
self._default_accept = 'text/plain'
|
self._default_accept = 'text/plain'
|
||||||
self._ignore_path = False
|
self._ignore_path = False
|
||||||
|
|
||||||
|
def _verify_configured_plugins(self):
|
||||||
|
backends = self._conf_get('backends')
|
||||||
|
desired_plugins = ['disable_by_file', 'enable_by_files']
|
||||||
|
|
||||||
|
if set(desired_plugins).issubset(set(backends)):
|
||||||
|
raise ConfigInvalid('`enable_by_files` and `disable_by_file`'
|
||||||
|
' healthcheck middleware should not be '
|
||||||
|
'configured at once.')
|
||||||
|
|
||||||
|
|
||||||
def _conf_get(self, key, group='healthcheck'):
|
def _conf_get(self, key, group='healthcheck'):
|
||||||
return super(Healthcheck, self)._conf_get(key, group=group)
|
return super(Healthcheck, self)._conf_get(key, group=group)
|
||||||
|
|
||||||
|
60
oslo_middleware/healthcheck/enable_by_files.py
Normal file
60
oslo_middleware/healthcheck/enable_by_files.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Copyright 2024 Red Hat.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from oslo_middleware.healthcheck import opts
|
||||||
|
from oslo_middleware.healthcheck import pluginbase
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class EnableByFilesHealthcheck(pluginbase.HealthcheckBaseExtension):
|
||||||
|
"""EnableByFilesHealthcheck healthcheck middleware plugin
|
||||||
|
|
||||||
|
This plugin checks presence of a file at a specified location.
|
||||||
|
|
||||||
|
Example of middleware configuration:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[app:healthcheck]
|
||||||
|
paste.app_factory = oslo_middleware:Healthcheck.app_factory
|
||||||
|
path = /healthcheck
|
||||||
|
backends = enable_by_files
|
||||||
|
enable_by_file_paths = /var/lib/glance/images/.marker,
|
||||||
|
/var/lib/glance/os_glance_staging_store/.marker
|
||||||
|
# set to True to enable detailed output, False is the default
|
||||||
|
detailed = False
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(EnableByFilesHealthcheck, self).__init__(*args, **kwargs)
|
||||||
|
self.oslo_conf.register_opts(opts.ENABLE_BY_FILES_OPTS,
|
||||||
|
group='healthcheck')
|
||||||
|
self.file_paths = self._conf_get('enable_by_file_paths')
|
||||||
|
|
||||||
|
def healthcheck(self, server_port):
|
||||||
|
for file_path in self.file_paths:
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
LOG.warning('EnableByFiles healthcheck middleware: Path %s '
|
||||||
|
'is not present', file_path)
|
||||||
|
return pluginbase.HealthcheckResult(
|
||||||
|
available=False, reason="FILE PATH MISSING",
|
||||||
|
details='File path %s is missing' % file_path)
|
||||||
|
return pluginbase.HealthcheckResult(
|
||||||
|
available=True, reason="OK",
|
||||||
|
details='Specified file paths are available')
|
@ -57,3 +57,11 @@ DISABLE_BY_FILES_OPTS = [
|
|||||||
'Expects a "port:path" list of strings. Used by '
|
'Expects a "port:path" list of strings. Used by '
|
||||||
'DisableByFilesPortsHealthcheck plugin.'),
|
'DisableByFilesPortsHealthcheck plugin.'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
ENABLE_BY_FILES_OPTS = [
|
||||||
|
cfg.ListOpt('enable_by_file_paths',
|
||||||
|
default=[],
|
||||||
|
help='Check the presence of files. Used by '
|
||||||
|
'EnableByFilesHealthcheck plugin.'),
|
||||||
|
]
|
||||||
|
@ -157,7 +157,8 @@ def list_opts_healthcheck():
|
|||||||
return [
|
return [
|
||||||
('healthcheck', copy.deepcopy(healthcheck_opts.HEALTHCHECK_OPTS +
|
('healthcheck', copy.deepcopy(healthcheck_opts.HEALTHCHECK_OPTS +
|
||||||
healthcheck_opts.DISABLE_BY_FILE_OPTS +
|
healthcheck_opts.DISABLE_BY_FILE_OPTS +
|
||||||
healthcheck_opts.DISABLE_BY_FILES_OPTS))
|
healthcheck_opts.DISABLE_BY_FILES_OPTS +
|
||||||
|
healthcheck_opts.ENABLE_BY_FILES_OPTS))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,3 +35,17 @@ class TestPasteDeploymentEntryPoints(base.BaseTestCase):
|
|||||||
factory_names = [extension.name for extension in em]
|
factory_names = [extension.name for extension in em]
|
||||||
self.assertThat(factory_names,
|
self.assertThat(factory_names,
|
||||||
matchers.ContainsAll(factory_classes))
|
matchers.ContainsAll(factory_classes))
|
||||||
|
|
||||||
|
def test_healthcheck_entry_points(self):
|
||||||
|
healthcheck_plugins = {
|
||||||
|
'disable_by_file': 'DisableByFileHealthcheck',
|
||||||
|
'disable_by_files_ports': 'DisableByFilesPortsHealthcheck',
|
||||||
|
'enable_by_files': 'EnableByFilesHealthcheck'
|
||||||
|
}
|
||||||
|
|
||||||
|
em = stevedore.ExtensionManager('oslo.middleware.healthcheck')
|
||||||
|
|
||||||
|
# Ensure all the healthcheck plugins are defined by their names
|
||||||
|
plugin_names = [extension.name for extension in em]
|
||||||
|
self.assertThat(plugin_names,
|
||||||
|
matchers.ContainsAll(healthcheck_plugins))
|
||||||
|
@ -24,6 +24,7 @@ import requests
|
|||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
|
from oslo_middleware.basic_auth import ConfigInvalid
|
||||||
from oslo_middleware import healthcheck
|
from oslo_middleware import healthcheck
|
||||||
from oslo_middleware.healthcheck import __main__
|
from oslo_middleware.healthcheck import __main__
|
||||||
|
|
||||||
@ -201,6 +202,63 @@ class HealthcheckTests(test_base.BaseTestCase):
|
|||||||
server_port=81)
|
server_port=81)
|
||||||
self.assertIn('disable_by_files_ports', self.app._backends.names())
|
self.assertIn('disable_by_files_ports', self.app._backends.names())
|
||||||
|
|
||||||
|
def test_enablefile_disablefile_configured(self):
|
||||||
|
conf = {'backends': 'disable_by_file,enable_by_files'}
|
||||||
|
self.assertRaises(ConfigInvalid,
|
||||||
|
healthcheck.Healthcheck, self.application, conf)
|
||||||
|
|
||||||
|
def test_enablefile_unconfigured(self):
|
||||||
|
conf = {'backends': 'enable_by_files'}
|
||||||
|
self._do_test(conf, expected_body=b'OK')
|
||||||
|
self.assertIn('enable_by_files', self.app._backends.names())
|
||||||
|
|
||||||
|
def test_enablefile_enabled(self):
|
||||||
|
filename = self.create_tempfiles([('.test', '.foobar')])[0]
|
||||||
|
conf = {'backends': 'enable_by_files',
|
||||||
|
'enable_by_file_paths': filename}
|
||||||
|
self._do_test(conf, expected_body=b'OK')
|
||||||
|
self.assertIn('enable_by_files', self.app._backends.names())
|
||||||
|
|
||||||
|
def test_enablefile_enabled_head(self):
|
||||||
|
filename = self.create_tempfiles([('.test', '.foobar')])[0]
|
||||||
|
conf = {'backends': 'enable_by_files',
|
||||||
|
'enable_by_file_paths': filename}
|
||||||
|
self._do_test(conf, expected_body=b'', method='HEAD',
|
||||||
|
expected_code=webob.exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
def test_enablefile_enabled_html_detailed(self):
|
||||||
|
filename = self.create_tempfiles([('.test', '.foobar')])[0]
|
||||||
|
conf = {'backends': 'enable_by_files',
|
||||||
|
'enable_by_file_paths': filename, 'detailed': True}
|
||||||
|
res = self._do_test_request(conf, accept="text/html")
|
||||||
|
self.assertIn(b'Result of 1 checks:', res.body)
|
||||||
|
self.assertIn(b'<TD>OK</TD>', res.body)
|
||||||
|
self.assertEqual(webob.exc.HTTPOk.code, res.status_int)
|
||||||
|
|
||||||
|
def test_enablefile_disabled(self):
|
||||||
|
conf = {'backends': 'enable_by_files',
|
||||||
|
'enable_by_file_paths': '.foobar'}
|
||||||
|
self._do_test(conf,
|
||||||
|
expected_code=webob.exc.HTTPServiceUnavailable.code,
|
||||||
|
expected_body=b'FILE PATH MISSING')
|
||||||
|
self.assertIn('enable_by_files', self.app._backends.names())
|
||||||
|
|
||||||
|
def test_enablefile_disabled_head(self):
|
||||||
|
conf = {'backends': 'enable_by_files',
|
||||||
|
'enable_by_file_paths': '.foobar'}
|
||||||
|
self._do_test(conf,
|
||||||
|
expected_code=webob.exc.HTTPServiceUnavailable.code,
|
||||||
|
expected_body=b'', method='HEAD')
|
||||||
|
self.assertIn('enable_by_files', self.app._backends.names())
|
||||||
|
|
||||||
|
def test_enablefile_disabled_html_detailed(self):
|
||||||
|
conf = {'backends': 'enable_by_files',
|
||||||
|
'enable_by_file_paths': '.foobar', 'detailed': True}
|
||||||
|
res = self._do_test_request(conf, accept="text/html")
|
||||||
|
self.assertIn(b'<TD>FILE PATH MISSING</TD>', res.body)
|
||||||
|
self.assertEqual(webob.exc.HTTPServiceUnavailable.code,
|
||||||
|
res.status_int)
|
||||||
|
|
||||||
def test_json_response(self):
|
def test_json_response(self):
|
||||||
expected_body = jsonutils.dumps({'detailed': False, 'reasons': []},
|
expected_body = jsonutils.dumps({'detailed': False, 'reasons': []},
|
||||||
indent=4,
|
indent=4,
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The new ``enable_by_files`` healthcheck plugin has been added.
|
||||||
|
This plugin will help to check whether specified file paths in
|
||||||
|
``[healthcheck] enable_by_file_paths`` are present or not.
|
@ -38,6 +38,7 @@ oslo.config.opts =
|
|||||||
oslo.middleware.healthcheck =
|
oslo.middleware.healthcheck =
|
||||||
disable_by_file = oslo_middleware.healthcheck.disable_by_file:DisableByFileHealthcheck
|
disable_by_file = oslo_middleware.healthcheck.disable_by_file:DisableByFileHealthcheck
|
||||||
disable_by_files_ports = oslo_middleware.healthcheck.disable_by_file:DisableByFilesPortsHealthcheck
|
disable_by_files_ports = oslo_middleware.healthcheck.disable_by_file:DisableByFilesPortsHealthcheck
|
||||||
|
enable_by_files = oslo_middleware.healthcheck.enable_by_files:EnableByFilesHealthcheck
|
||||||
|
|
||||||
paste.app_factory =
|
paste.app_factory =
|
||||||
healthcheck = oslo_middleware:Healthcheck.app_factory
|
healthcheck = oslo_middleware:Healthcheck.app_factory
|
||||||
|
Loading…
Reference in New Issue
Block a user