oslomiddleware(1)

OSLOMIDDLEWARE(1) oslo.middleware OSLOMIDDLEWARE(1)

NAME

oslomiddleware - oslo.middleware 6.4.0 Latest VersionDownloads

Oslo middleware library includes components that can be injected into wsgi pipelines to intercept request/response flows. The base class can be enhanced with functionality like add/delete/modification of http headers and support for limiting size/connection etc.

  • Free software: Apache license
  • Documentation: https://docs.openstack.org/oslo.middleware/latest/
  • Source: https://opendev.org/openstack/oslo.middleware
  • Bugs: https://bugs.launchpad.net/oslo.middleware
  • Release notes: https://docs.openstack.org/releasenotes/oslo.middleware/

CONTENTS

Installation

At the command line:

$ pip install oslo.middleware


Or, if you have virtualenvwrapper installed:

$ mkvirtualenv oslo.middleware
$ pip install oslo.middleware


Contributing

If you would like to contribute to the development of oslo's libraries, first you must take a look to this page:

https://specs.openstack.org/openstack/oslo-specs/specs/policy/contributing.html


If you would like to contribute to the development of OpenStack, you must follow the steps in this page:

https://docs.openstack.org/infra/manual/developers.html


Once those steps have been completed, changes to OpenStack should be submitted for review via the Gerrit tool, following the workflow documented at:

https://docs.openstack.org/infra/manual/developers.html#development-workflow


Pull requests submitted through GitHub will be ignored.

Bugs should be filed on Launchpad, not GitHub:

https://bugs.launchpad.net/oslo.middleware


Middlewares and configuration

Middlewares can be configured in multiple fashion depending of the application needs. Here is some use-cases:

Configuration from the application

The application code will looks like:

from oslo_middleware import sizelimit
from oslo_config import cfg
conf = cfg.ConfigOpts()
app = sizelimit.RequestBodySizeLimiter(your_wsgi_application, conf)


Configuration with paste-deploy and the oslo.config

The paste filter (in /etc/my_app/api-paste.ini) will looks like:

[filter:sizelimit]
use = egg:oslo.middleware#sizelimit
# In case of the application doesn't use the global oslo.config
# object. The middleware must known the app name to load
# the application configuration, by setting this:
#  oslo_config_project = my_app
# In some cases, you may need to specify the program name for the project
# as well.
#  oslo_config_program = my_app-api


The oslo.config file of the application (eg: /etc/my_app/my_app.conf) will looks like:

[oslo_middleware]
max_request_body_size=1000


Configuration with pastedeploy only

The paste filter (in /etc/my_app/api-paste.ini) will looks like:

[filter:sizelimit]
use = egg:oslo.middleware#sizelimit
max_request_body_size=1000


This will override any configuration done via oslo.config

NOTE:

healthcheck middleware does not yet use oslo.config, see Healthcheck middleware plugins


Cross-project features

Many features are common to all the OpenStack services and are consistent in their configuration and deployment patterns. Unless explicitly noted, you can safely assume that the features in this chapter are supported and configured in a consistent manner.

Cross-origin resource sharing

NOTE:

This is a new feature in OpenStack Liberty.


OpenStack supports Cross-Origin Resource Sharing (CORS), a W3C specification defining a contract by which the single-origin policy of a user agent (usually a browser) may be relaxed. It permits the javascript engine to access an API that does not reside on the same domain, protocol, or port.

This feature is most useful to organizations which maintain one or more custom user interfaces for OpenStack, as it permits those interfaces to access the services directly, rather than requiring an intermediate proxy server. It can, however, also be misused by malicious actors; please review the security advisory below for more information.

Enabling CORS with configuration

In most cases, CORS support is built directly into the service itself. To enable it, simply follow the configuration options exposed in the default configuration file, or add it yourself according to the pattern below.

[cors]
allowed_origin = https://first_ui.example.com
max_age = 3600
allow_methods = GET,POST,PUT,DELETE
allow_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma,X-Custom-Header
expose_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma,X-Custom-Header


Additional origins can be explicitly added. To express this in your configuration file, first begin with a [cors] group as above, into which you place your default configuration values. Then, add as many additional configuration groups as necessary, naming them [cors.{something}] (each name must be unique). The purpose of the suffix to cors. is legibility, we recommend using a reasonable human-readable string:

[cors.ironic_webclient]
# CORS Configuration for a hypothetical ironic webclient, which overrides
# authentication
allowed_origin = https://ironic.example.com:443
allow_credentials = True
[cors.horizon]
# CORS Configuration for horizon, which uses global options.
allowed_origin = https://horizon.example.com:443
[cors.wildcard]
# CORS Configuration for the CORS specified domain wildcard, which only
# permits HTTP GET requests.
allowed_origin = *
allow_methods = GET


For more information about CORS configuration, see cross-origin resource sharing in OpenStack Configuration Reference.

Enabling CORS with PasteDeploy

CORS can also be configured using PasteDeploy. First of all, ensure that OpenStack's oslo_middleware package (version 2.4.0 or later) is available in the Python environment that is running the service. Then, add the following configuration block to your paste.ini file.

[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
allowed_origin = https://website.example.com:443
max_age = 3600
allow_methods = GET,POST,PUT,DELETE
allow_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma,X-Custom-Header
expose_headers = Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma,X-Custom-Header


NOTE:

To add an additional domain in oslo_middleware v2.4.0, add another filter. In v3.0.0 and after, you may add multiple domains in the above allowed_origin field, separated by commas.


Security concerns

CORS specifies a wildcard character *, which permits access to all user agents, regardless of domain, protocol, or host. While there are valid use cases for this approach, it also permits a malicious actor to create a convincing facsimile of a user interface, and trick users into revealing authentication credentials. Please carefully evaluate your use case and the relevant documentation for any risk to your organization.

NOTE:

The CORS specification does not support using this wildcard as a part of a URI. Setting allowed_origin to * would work, while *.openstack.org would not.


Troubleshooting

CORS is very easy to get wrong, as even one incorrect property will violate the prescribed contract. Here are some steps you can take to troubleshoot your configuration.

Check the service log

The CORS middleware used by OpenStack provides verbose debug logging that should reveal most configuration problems. Here are some example log messages, and how to resolve them.

Problem

CORS request from origin 'http://example.com' not permitted.

Solution

A request was received from the origin http://example.com, however this origin was not found in the permitted list. The cause may be a superfluous port notation (ports 80 and 443 do not need to be specified). To correct, ensure that the configuration property for this host is identical to the host indicated in the log message.

Problem

Request method 'DELETE' not in permitted list: GET,PUT,POST

Solution

A user agent has requested permission to perform a DELETE request, however the CORS configuration for the domain does not permit this. To correct, add this method to the allow_methods configuration property.

Problem

Request header 'X-Custom-Header' not in permitted list: X-Other-Header

Solution

A request was received with the header X-Custom-Header, which is not permitted. Add this header to the allow_headers configuration property.

Open your browser's console log

Most browsers provide helpful debug output when a CORS request is rejected. Usually this happens when a request was successful, but the return headers on the response do not permit access to a property which the browser is trying to access.

Manually construct a CORS request

By using curl or a similar tool, you can trigger a CORS response with a properly constructed HTTP request. An example request and response might look like this.

Request example:

$ curl -I -X OPTIONS https://api.example.com/api -H "Origin: https://ui.example.com"


Response example:

HTTP/1.1 204 No Content
Content-Length: 0
Access-Control-Allow-Origin: https://ui.example.com
Access-Control-Allow-Methods: GET,POST,PUT,DELETE
Access-Control-Expose-Headers: origin,authorization,accept,x-total,x-limit,x-marker,x-client,content-type
Access-Control-Allow-Headers: origin,authorization,accept,x-total,x-limit,x-marker,x-client,content-type
Access-Control-Max-Age: 3600


If the service does not return any access control headers, check the service log, such as /var/log/upstart/ironic-api.log for an indication on what went wrong.

oslo.middleware Reference

API

class oslo_middleware.BasicAuthMiddleware(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
Middleware which performs HTTP basic authentication on requests

class oslo_middleware.CORS(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
CORS Middleware.

This middleware allows a WSGI app to serve CORS headers for multiple configured domains.

For more information, see http://www.w3.org/TR/cors/

add_origin(allowed_origin: str | list[str], allow_credentials: bool = True, expose_headers: list[str] | None = None, max_age: int | None = None, allow_methods: list[str] | None = None, allow_headers: list[str] | None = None) -> None
Add another origin to this filter.
Parameters
  • allowed_origin -- Protocol, host, and port for the allowed origin.
  • allow_credentials -- Whether to permit credentials.
  • expose_headers -- A list of headers to expose.
  • max_age -- Maximum cache duration.
  • allow_methods -- List of HTTP methods to permit.
  • allow_headers -- List of HTTP headers to permit from the client.

Returns



classmethod factory(global_conf: dict[str, ty.Any] | None, **local_conf: ty.Any) -> ty.Callable[[WSGIApplication], base.MiddlewareType]
factory method for paste.deploy

allowed_origin: Protocol, host, and port for the allowed origin. allow_credentials: Whether to permit credentials. expose_headers: A list of headers to expose. max_age: Maximum cache duration. allow_methods: List of HTTP methods to permit. allow_headers: List of HTTP headers to permit from the client.


process_response(response: Response, request: Request | None = None) -> Response
Check for CORS headers, and decorate if necessary.

Perform two checks. First, if an OPTIONS request was issued, let the application handle it, and (if necessary) decorate the response with preflight headers. In this case, if a 404 is thrown by the underlying application (i.e. if the underlying application does not handle OPTIONS requests, the response code is overridden.

In the case of all other requests, regular request headers are applied.



class oslo_middleware.CatchErrors(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
Middleware that provides high-level error handling.

It catches all exceptions from subsequent applications in WSGI pipeline to hide internal errors from API response.


class oslo_middleware.CorrelationId(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
Middleware that attaches a correlation id to WSGI request
static process_request(req: webob.request.Request) -> webob.response.Response | None
Called on each request.

If this returns None, the next application down the stack will be executed. If it returns a response then that response will be returned and execution will stop here.



class oslo_middleware.Debug(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
Helper class that returns debug information.

Can be inserted into any WSGI application chain to get information about the request and response.

static print_generator(app_iter: Iterable[bytes]) -> Iterator[bytes]
Prints the contents of a wrapper string iterator when iterated.


class oslo_middleware.HTTPProxyToWSGI(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
HTTP proxy to WSGI termination middleware.

This middleware overloads WSGI environment variables with the one provided by the remote HTTP reverse proxy.

process_request(req: webob.request.Request) -> webob.response.Response | None
Called on each request.

If this returns None, the next application down the stack will be executed. If it returns a response then that response will be returned and execution will stop here.



class oslo_middleware.Healthcheck(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
Healthcheck application used for monitoring.

It will respond 200 with "OK" as the body. Or a 503 with the reason as the body if one of the backends reports an application issue.

This is useful for the following reasons:

  • Load balancers can 'ping' this url to determine service availability.
  • Provides an endpoint that is similar to 'mod_status' in apache which can provide details (or no details, depending on if configured) about the activity of the server.
  • (and more)

NOTE:

This middleware indicates that the API is accessible but it does indicate that it is necessarily functional or that any other API request will actually work.


Example requests/responses (not detailed mode):

$ curl -i -X HEAD "http://0.0.0.0:8775/healthcheck"
HTTP/1.1 204 No Content
Content-Type: text/plain; charset=UTF-8
Content-Length: 0
Date: Fri, 11 Sep 2015 18:55:08 GMT
$ curl -i -X GET "http://0.0.0.0:8775/healthcheck"
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 2
Date: Fri, 11 Sep 2015 18:55:43 GMT
OK
$ curl -X GET -i -H "Accept: application/json" "http://0.0.0.0:8775/healthcheck"
HTTP/1.0 200 OK
Date: Wed, 24 Aug 2016 06:09:58 GMT
Content-Type: application/json
Content-Length: 63
{

"detailed": false,
"reasons": [
"OK"
] } $ curl -X GET -i -H "Accept: text/html" "http://0.0.0.0:8775/healthcheck" HTTP/1.0 200 OK Date: Wed, 24 Aug 2016 06:10:42 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 239 <HTML> <HEAD><TITLE>Healthcheck Status</TITLE></HEAD> <BODY> <H2>Result of 1 checks:</H2> <TABLE bgcolor="#ffffff" border="1"> <TBODY> <TR> <TH> Reason </TH> </TR> <TR>
<TD>OK</TD> </TR> </TBODY> </TABLE> <HR></HR> </BODY>


Example requests/responses (detailed mode):

$ curl -X GET -i -H "Accept: application/json" "http://0.0.0.0:8775/healthcheck"
HTTP/1.0 200 OK
Date: Wed, 24 Aug 2016 06:11:59 GMT
Content-Type: application/json
Content-Length: 3480
{

"detailed": true,
"gc": {
"counts": [
293,
10,
5
],
"threshold": [
700,
10,
10
]
},
"greenthreads": [
...
],
"now": "2016-08-24 06:11:59.419267",
"platform": "Linux-4.2.0-27-generic-x86_64-with-Ubuntu-14.04-trusty",
"python_version": "2.7.6 (default, Jun 22 2015, 17:58:13) \n[GCC 4.8.2]",
"reasons": [
{
"class": "HealthcheckResult",
"details": "Path '/tmp/dead' was not found",
"reason": "OK"
}
],
"threads": [
...
] } $ curl -X GET -i -H "Accept: text/html" "http://0.0.0.0:8775/healthcheck" HTTP/1.0 200 OK Date: Wed, 24 Aug 2016 06:36:07 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 6838 <HTML> <HEAD><TITLE>Healthcheck Status</TITLE></HEAD> <BODY> <H1>Server status</H1> <B>Server hostname:</B><PRE>...</PRE> <B>Current time:</B><PRE>2016-08-24 06:36:07.302559</PRE> <B>Python version:</B><PRE>2.7.6 (default, Jun 22 2015, 17:58:13) [GCC 4.8.2]</PRE> <B>Platform:</B><PRE>Linux-4.2.0-27-generic-x86_64-with-Ubuntu-14.04-trusty</PRE> <HR></HR> <H2>Garbage collector:</H2> <B>Counts:</B><PRE>(77, 1, 6)</PRE> <B>Thresholds:</B><PRE>(700, 10, 10)</PRE> <HR></HR> <H2>Result of 1 checks:</H2> <TABLE bgcolor="#ffffff" border="1"> <TBODY> <TR> <TH> Kind </TH> <TH> Reason </TH> <TH> Details </TH> </TR> <TR> <TD>HealthcheckResult</TD>
<TD>OK</TD> <TD>Path &#39;/tmp/dead&#39; was not found</TD> </TR> </TBODY> </TABLE> <HR></HR> <H2>1 greenthread(s) active:</H2> <TABLE bgcolor="#ffffff" border="1"> <TBODY> <TR>
<TD><PRE> File &#34;oslo_middleware/healthcheck/__main__.py&#34;, line 94, in &lt;module&gt;
main()
File &#34;oslo_middleware/healthcheck/__main__.py&#34;, line 90, in main
server.serve_forever()
... </PRE></TD> </TR> </TBODY> </TABLE> <HR></HR> <H2>1 thread(s) active:</H2> <TABLE bgcolor="#ffffff" border="1"> <TBODY> <TR>
<TD><PRE> File &#34;oslo_middleware/healthcheck/__main__.py&#34;, line 94, in &lt;module&gt;
main()
File &#34;oslo_middleware/healthcheck/__main__.py&#34;, line 90, in main
server.serve_forever()
.... </TR> </TBODY> </TABLE> </BODY> </HTML>


Example of paste configuration:

[app:healthcheck]
use = egg:oslo.middleware:healthcheck
backends = disable_by_file
disable_by_file_path = /var/run/nova/healthcheck_disable
[pipeline:public_api]
pipeline = healthcheck sizelimit [...] public_service


Multiple filter sections can be defined if it desired to have pipelines with different healthcheck configuration, example:

[composite:public_api]
use = egg:Paste#urlmap
/ = public_api_pipeline
/healthcheck = healthcheck_public
[composite:admin_api]
use = egg:Paste#urlmap
/ = admin_api_pipeline
/healthcheck = healthcheck_admin
[pipeline:public_api_pipeline]
pipeline = sizelimit [...] public_service
[pipeline:admin_api_pipeline]
pipeline = sizelimit [...] admin_service
[app:healthcheck_public]
use = egg:oslo.middleware:healthcheck
backends = disable_by_file
disable_by_file_path = /var/run/nova/healthcheck_public_disable
[filter:healthcheck_admin]
use = egg:oslo.middleware:healthcheck
backends = disable_by_file
disable_by_file_path = /var/run/nova/healthcheck_admin_disable


classmethod app_factory(global_conf: dict[str, ty.Any] | None, **local_conf: ty.Any) -> ty.Callable[[WSGIApplication], base.ConfigurableMiddleware]
Factory method for paste.deploy.
Parameters
  • global_conf -- dict of options for all middlewares (usually the [DEFAULT] section of the paste deploy configuration file)
  • local_conf -- options dedicated to this middleware (usually the option defined in the middleware section of the paste deploy configuration file)



classmethod factory(global_conf: dict[str, ty.Any] | None, **local_conf: ty.Any) -> ty.Callable[[WSGIApplication], base.ConfigurableMiddleware]
Factory method for paste.deploy.
Parameters
  • global_conf -- dict of options for all middlewares (usually the [DEFAULT] section of the paste deploy configuration file)
  • local_conf -- options dedicated to this middleware (usually the option defined in the middleware's section of the paste deploy configuration file)




class oslo_middleware.RequestBodySizeLimiter(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
Limit the size of incoming requests.

class oslo_middleware.RequestId(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
Middleware that ensures request ID.

It ensures to assign request ID for each API request and set it to request environment. The request ID is also added to API response.


Configuration Options

RequestBodySizeLimiter

oslo_middleware

max_request_body_size
Type
integer
Default
114688

The maximum body size for each request, in bytes.


SSLMiddleware

CORS Middleware

This middleware provides a comprehensive, configurable implementation of the CORS (Cross Origin Resource Sharing) specification as oslo-supported python wsgi middleware.

NOTE:

While this middleware supports the use of the * wildcard origin in the specification, this feature is not recommended for security reasons. It is provided to simplify basic use of CORS, practically meaning "I don't care how this is used." In an intranet setting, this could lead to leakage of data beyond the intranet and therefore should be avoided.


Quickstart

First, include the middleware in your application:

from oslo_middleware import cors
app = cors.CORS(your_wsgi_application)


Secondly, add as many allowed origins as you would like:

app.add_origin(allowed_origin='https://website.example.com:443',

allow_credentials=True,
max_age=3600,
allow_methods=['GET','PUT','POST','DELETE'],
allow_headers=['X-Custom-Header'],
expose_headers=['X-Custom-Header']) # ... add more origins here.


Configuration for oslo_config

A factory method has been provided to simplify configuration of your CORS domain, using oslo_config:

from oslo_middleware import cors
from oslo_config import cfg
app = cors.CORS(your_wsgi_application, cfg.CONF)


In your application's config file, then include a configuration block something like this:

[cors]
allowed_origin=https://website.example.com:443,https://website2.example.com:443
max_age=3600
allow_methods=GET,POST,PUT,DELETE
allow_headers=X-Custom-Header
expose_headers=X-Custom-Header


Configuration for pastedeploy

If your application is using pastedeploy, the following configuration block will add CORS support.:

[filter:cors]
use = egg:oslo.middleware#cors
allowed_origin=https://website.example.com:443,https://website2.example.com:443
max_age=3600
allow_methods=GET,POST,PUT,DELETE
allow_headers=X-Custom-Header
expose_headers=X-Custom-Header


If your application is using pastedeploy, but would also like to use the existing configuration from oslo_config in order to simplify the points of configuration, this may be done as follows.:

[filter:cors]
use = egg:oslo.middleware#cors
oslo_config_project = oslo_project_name
# Optional field, in case the program name is different from the project:
oslo_config_program = oslo_project_name-api


Configuration Options

cors

allowed_origin
Type
list
Default
<None>

Indicate whether this resource may be shared with the domain received in the requests "origin" header. Format: "<protocol>://<host>[:<port>]", no trailing slash. Example: https://horizon.example.com


allow_credentials
Type
boolean
Default
True

Indicate that the actual request can include user credentials


expose_headers
Type
list
Default
[]

Indicate which headers are safe to expose to the API. Defaults to HTTP Simple Headers.


max_age
Type
integer
Default
3600

Maximum cache age of CORS preflight requests.


allow_methods
Type
list
Default
['OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'PATCH']

Indicate which methods can be used during the actual request.


allow_headers
Type
list
Default
[]

Indicate which header field names may be used during the actual request.


Module Documentation

class oslo_middleware.cors.AllowedOrigin

class oslo_middleware.cors.CORS(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
CORS Middleware.

This middleware allows a WSGI app to serve CORS headers for multiple configured domains.

For more information, see http://www.w3.org/TR/cors/

add_origin(allowed_origin: str | list[str], allow_credentials: bool = True, expose_headers: list[str] | None = None, max_age: int | None = None, allow_methods: list[str] | None = None, allow_headers: list[str] | None = None) -> None
Add another origin to this filter.
Parameters
  • allowed_origin -- Protocol, host, and port for the allowed origin.
  • allow_credentials -- Whether to permit credentials.
  • expose_headers -- A list of headers to expose.
  • max_age -- Maximum cache duration.
  • allow_methods -- List of HTTP methods to permit.
  • allow_headers -- List of HTTP headers to permit from the client.

Returns



classmethod factory(global_conf: dict[str, ty.Any] | None, **local_conf: ty.Any) -> ty.Callable[[WSGIApplication], base.MiddlewareType]
factory method for paste.deploy

allowed_origin: Protocol, host, and port for the allowed origin. allow_credentials: Whether to permit credentials. expose_headers: A list of headers to expose. max_age: Maximum cache duration. allow_methods: List of HTTP methods to permit. allow_headers: List of HTTP headers to permit from the client.


process_response(response: Response, request: Request | None = None) -> Response
Check for CORS headers, and decorate if necessary.

Perform two checks. First, if an OPTIONS request was issued, let the application handle it, and (if necessary) decorate the response with preflight headers. In this case, if a 404 is thrown by the underlying application (i.e. if the underlying application does not handle OPTIONS requests, the response code is overridden.

In the case of all other requests, regular request headers are applied.



exception oslo_middleware.cors.InvalidOriginError(origin: str)
Exception raised when Origin is invalid.

oslo_middleware.cors.filter_factory(global_conf: dict[str, ty.Any] | None, **local_conf: ty.Any) -> ty.Callable[[WSGIApplication], base.MiddlewareType]
factory method for paste.deploy

allowed_origin: Protocol, host, and port for the allowed origin. allow_credentials: Whether to permit credentials. expose_headers: A list of headers to expose. max_age: Maximum cache duration. allow_methods: List of HTTP methods to permit. allow_headers: List of HTTP headers to permit from the client.


oslo_middleware.cors.set_defaults(**kwargs: Opt) -> None
Override the default values for configuration options.

This method permits a project to override the default CORS option values. For example, it may wish to offer a set of sane default headers which allow it to function with only minimal additional configuration.

Parameters
  • allow_credentials (bool) -- Whether to permit credentials.
  • expose_headers (List of Strings) -- A list of headers to expose.
  • max_age (Int) -- Maximum cache duration in seconds.
  • allow_methods (List of Strings) -- List of HTTP methods to permit.
  • allow_headers (List of Strings) -- List of HTTP headers to permit from the client.



Healthcheck middleware plugins

class oslo_middleware.healthcheck.Healthcheck(application: WSGIApplication, conf: dict[str, ty.Any] | cfg.ConfigOpts | None = None)
Healthcheck application used for monitoring.

It will respond 200 with "OK" as the body. Or a 503 with the reason as the body if one of the backends reports an application issue.

This is useful for the following reasons:

  • Load balancers can 'ping' this url to determine service availability.
  • Provides an endpoint that is similar to 'mod_status' in apache which can provide details (or no details, depending on if configured) about the activity of the server.
  • (and more)

NOTE:

This middleware indicates that the API is accessible but it does indicate that it is necessarily functional or that any other API request will actually work.


Example requests/responses (not detailed mode):

$ curl -i -X HEAD "http://0.0.0.0:8775/healthcheck"
HTTP/1.1 204 No Content
Content-Type: text/plain; charset=UTF-8
Content-Length: 0
Date: Fri, 11 Sep 2015 18:55:08 GMT
$ curl -i -X GET "http://0.0.0.0:8775/healthcheck"
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 2
Date: Fri, 11 Sep 2015 18:55:43 GMT
OK
$ curl -X GET -i -H "Accept: application/json" "http://0.0.0.0:8775/healthcheck"
HTTP/1.0 200 OK
Date: Wed, 24 Aug 2016 06:09:58 GMT
Content-Type: application/json
Content-Length: 63
{

"detailed": false,
"reasons": [
"OK"
] } $ curl -X GET -i -H "Accept: text/html" "http://0.0.0.0:8775/healthcheck" HTTP/1.0 200 OK Date: Wed, 24 Aug 2016 06:10:42 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 239 <HTML> <HEAD><TITLE>Healthcheck Status</TITLE></HEAD> <BODY> <H2>Result of 1 checks:</H2> <TABLE bgcolor="#ffffff" border="1"> <TBODY> <TR> <TH> Reason </TH> </TR> <TR>
<TD>OK</TD> </TR> </TBODY> </TABLE> <HR></HR> </BODY>


Example requests/responses (detailed mode):

$ curl -X GET -i -H "Accept: application/json" "http://0.0.0.0:8775/healthcheck"
HTTP/1.0 200 OK
Date: Wed, 24 Aug 2016 06:11:59 GMT
Content-Type: application/json
Content-Length: 3480
{

"detailed": true,
"gc": {
"counts": [
293,
10,
5
],
"threshold": [
700,
10,
10
]
},
"greenthreads": [
...
],
"now": "2016-08-24 06:11:59.419267",
"platform": "Linux-4.2.0-27-generic-x86_64-with-Ubuntu-14.04-trusty",
"python_version": "2.7.6 (default, Jun 22 2015, 17:58:13) \n[GCC 4.8.2]",
"reasons": [
{
"class": "HealthcheckResult",
"details": "Path '/tmp/dead' was not found",
"reason": "OK"
}
],
"threads": [
...
] } $ curl -X GET -i -H "Accept: text/html" "http://0.0.0.0:8775/healthcheck" HTTP/1.0 200 OK Date: Wed, 24 Aug 2016 06:36:07 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 6838 <HTML> <HEAD><TITLE>Healthcheck Status</TITLE></HEAD> <BODY> <H1>Server status</H1> <B>Server hostname:</B><PRE>...</PRE> <B>Current time:</B><PRE>2016-08-24 06:36:07.302559</PRE> <B>Python version:</B><PRE>2.7.6 (default, Jun 22 2015, 17:58:13) [GCC 4.8.2]</PRE> <B>Platform:</B><PRE>Linux-4.2.0-27-generic-x86_64-with-Ubuntu-14.04-trusty</PRE> <HR></HR> <H2>Garbage collector:</H2> <B>Counts:</B><PRE>(77, 1, 6)</PRE> <B>Thresholds:</B><PRE>(700, 10, 10)</PRE> <HR></HR> <H2>Result of 1 checks:</H2> <TABLE bgcolor="#ffffff" border="1"> <TBODY> <TR> <TH> Kind </TH> <TH> Reason </TH> <TH> Details </TH> </TR> <TR> <TD>HealthcheckResult</TD>
<TD>OK</TD> <TD>Path &#39;/tmp/dead&#39; was not found</TD> </TR> </TBODY> </TABLE> <HR></HR> <H2>1 greenthread(s) active:</H2> <TABLE bgcolor="#ffffff" border="1"> <TBODY> <TR>
<TD><PRE> File &#34;oslo_middleware/healthcheck/__main__.py&#34;, line 94, in &lt;module&gt;
main()
File &#34;oslo_middleware/healthcheck/__main__.py&#34;, line 90, in main
server.serve_forever()
... </PRE></TD> </TR> </TBODY> </TABLE> <HR></HR> <H2>1 thread(s) active:</H2> <TABLE bgcolor="#ffffff" border="1"> <TBODY> <TR>
<TD><PRE> File &#34;oslo_middleware/healthcheck/__main__.py&#34;, line 94, in &lt;module&gt;
main()
File &#34;oslo_middleware/healthcheck/__main__.py&#34;, line 90, in main
server.serve_forever()
.... </TR> </TBODY> </TABLE> </BODY> </HTML>


Example of paste configuration:

[app:healthcheck]
use = egg:oslo.middleware:healthcheck
backends = disable_by_file
disable_by_file_path = /var/run/nova/healthcheck_disable
[pipeline:public_api]
pipeline = healthcheck sizelimit [...] public_service


Multiple filter sections can be defined if it desired to have pipelines with different healthcheck configuration, example:

[composite:public_api]
use = egg:Paste#urlmap
/ = public_api_pipeline
/healthcheck = healthcheck_public
[composite:admin_api]
use = egg:Paste#urlmap
/ = admin_api_pipeline
/healthcheck = healthcheck_admin
[pipeline:public_api_pipeline]
pipeline = sizelimit [...] public_service
[pipeline:admin_api_pipeline]
pipeline = sizelimit [...] admin_service
[app:healthcheck_public]
use = egg:oslo.middleware:healthcheck
backends = disable_by_file
disable_by_file_path = /var/run/nova/healthcheck_public_disable
[filter:healthcheck_admin]
use = egg:oslo.middleware:healthcheck
backends = disable_by_file
disable_by_file_path = /var/run/nova/healthcheck_admin_disable


classmethod app_factory(global_conf: dict[str, ty.Any] | None, **local_conf: ty.Any) -> ty.Callable[[WSGIApplication], base.ConfigurableMiddleware]
Factory method for paste.deploy.
Parameters
  • global_conf -- dict of options for all middlewares (usually the [DEFAULT] section of the paste deploy configuration file)
  • local_conf -- options dedicated to this middleware (usually the option defined in the middleware section of the paste deploy configuration file)



classmethod factory(global_conf: dict[str, ty.Any] | None, **local_conf: ty.Any) -> ty.Callable[[WSGIApplication], base.ConfigurableMiddleware]
Factory method for paste.deploy.
Parameters
  • global_conf -- dict of options for all middlewares (usually the [DEFAULT] section of the paste deploy configuration file)
  • local_conf -- options dedicated to this middleware (usually the option defined in the middleware's section of the paste deploy configuration file)




class oslo_middleware.healthcheck.Reason

class oslo_middleware.healthcheck.disable_by_file.DisableByFileHealthcheck(oslo_conf: cfg.ConfigOpts, conf: dict[str, ty.Any])
DisableByFile healthcheck middleware plugin

This plugin checks presence of a file to report if the service is unavailable or not.

Example of middleware configuration:

[filter:healthcheck]
paste.filter_factory = oslo_middleware:Healthcheck.factory
path = /healthcheck
backends = disable_by_file
disable_by_file_path = /var/run/nova/healthcheck_disable
# set to True to enable detailed output, False is the default
detailed = False


healthcheck(server_port: int) -> HealthcheckResult
method called by the healthcheck middleware

return: HealthcheckResult object



class oslo_middleware.healthcheck.disable_by_file.DisableByFilesPortsHealthcheck(oslo_conf: cfg.ConfigOpts, conf: dict[str, ty.Any])
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:

[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
# set to True to enable detailed output, False is the default
detailed = False


healthcheck(server_port: int) -> HealthcheckResult
method called by the healthcheck middleware

return: HealthcheckResult object



class oslo_middleware.healthcheck.enable_by_files.EnableByFilesHealthcheck(oslo_conf: cfg.ConfigOpts, conf: dict[str, Any])
EnableByFilesHealthcheck healthcheck middleware plugin

This plugin checks presence of a file at a specified location.

Example of middleware configuration:

[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


healthcheck(server_port: int) -> HealthcheckResult
method called by the healthcheck middleware

return: HealthcheckResult object



Available Plugins

disable_by_file

DisableByFile healthcheck middleware plugin

This plugin checks presence of a file to report if the service is unavailable or not.

Example of middleware configuration:

[filter:healthcheck]
paste.filter_factory = oslo_middleware:Healthcheck.factory
path = /healthcheck
backends = disable_by_file
disable_by_file_path = /var/run/nova/healthcheck_disable
# set to True to enable detailed output, False is the default
detailed = False


disable_by_files_ports

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:

[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
# set to True to enable detailed output, False is the default
detailed = False


enable_by_files

EnableByFilesHealthcheck healthcheck middleware plugin

This plugin checks presence of a file at a specified location.

Example of middleware configuration:

[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


Glossary

This glossary offers a list of terms and definitions to define a vocabulary for OpenStack-related concepts.

C

Cross-Origin Resource Sharing (CORS)
A mechanism that allows many resources (for example, fonts, JavaScript) on a web page to be requested from another domain outside the domain from which the resource originated. In particular, JavaScript's AJAX calls can use the XMLHttpRequest mechanism.

RELEASE NOTES

Read also the oslo.middleware Release Notes.

AUTHOR

Author name not set

COPYRIGHT

2025, OpenStack Foundation

May 7, 2025 6.4.0