diff options
-rw-r--r-- | oslo_middleware/base.py | 14 | ||||
-rw-r--r-- | oslo_middleware/cors.py | 10 | ||||
-rw-r--r-- | oslo_middleware/healthcheck/__main__.py | 69 | ||||
-rw-r--r-- | oslo_middleware/http_proxy_to_wsgi.py | 2 | ||||
-rw-r--r-- | oslo_middleware/opts.py | 29 | ||||
-rw-r--r-- | oslo_middleware/tests/test_base.py | 11 | ||||
-rw-r--r-- | oslo_middleware/tests/test_healthcheck.py | 24 | ||||
-rw-r--r-- | requirements.txt | 8 | ||||
-rw-r--r-- | setup.cfg | 1 | ||||
-rw-r--r-- | test-requirements.txt | 6 |
10 files changed, 156 insertions, 18 deletions
diff --git a/oslo_middleware/base.py b/oslo_middleware/base.py index a98a058..27689a1 100644 --- a/oslo_middleware/base.py +++ b/oslo_middleware/base.py @@ -17,10 +17,22 @@ from inspect import getargspec import webob.dec +import webob.request +import webob.response from oslo_config import cfg +class NoContentTypeResponse(webob.response.Response): + + default_content_type = None # prevents webob assigning content type + + +class NoContentTypeRequest(webob.request.Request): + + ResponseClass = NoContentTypeResponse + + class ConfigurableMiddleware(object): """Base WSGI middleware wrapper. @@ -106,7 +118,7 @@ class ConfigurableMiddleware(object): """Do whatever you'd like to the response.""" return response - @webob.dec.wsgify + @webob.dec.wsgify(RequestClass=NoContentTypeRequest) def __call__(self, req): response = self.process_request(req) if response: diff --git a/oslo_middleware/cors.py b/oslo_middleware/cors.py index 8857afc..8e8422d 100644 --- a/oslo_middleware/cors.py +++ b/oslo_middleware/cors.py @@ -19,9 +19,8 @@ import debtcollector from oslo_config import cfg from oslo_middleware import base import six -import webob.dec import webob.exc -import webob.response + LOG = logging.getLogger(__name__) @@ -99,11 +98,6 @@ class InvalidOriginError(Exception): 'CORS request from origin \'%s\' not permitted.' % origin) -class _NoContentTypeResponse(webob.response.Response): - - default_content_type = None # prevents webob assigning content type - - class CORS(base.ConfigurableMiddleware): """CORS Middleware. @@ -334,7 +328,7 @@ class CORS(base.ConfigurableMiddleware): # underlying middleware's response content needs to be persisted. # Otherwise, create a new response. if 200 > response.status_code or response.status_code >= 300: - response = _NoContentTypeResponse(status=webob.exc.HTTPOk.code) + response = base.NoContentTypeResponse(status=webob.exc.HTTPOk.code) # Does the request have an origin header? (Section 6.2.1) if 'Origin' not in request.headers: diff --git a/oslo_middleware/healthcheck/__main__.py b/oslo_middleware/healthcheck/__main__.py new file mode 100644 index 0000000..217fff6 --- /dev/null +++ b/oslo_middleware/healthcheck/__main__.py @@ -0,0 +1,69 @@ +# +# 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 argparse + +from six.moves import SimpleHTTPServer # noqa +from six.moves import socketserver +import webob + +from oslo_middleware import healthcheck + + +class HttpHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + def do_GET(self): + @webob.dec.wsgify + def dummy_application(req): + return 'test' + app = healthcheck.Healthcheck(dummy_application, {'detailed': True}) + req = webob.Request.blank("/healthcheck", accept='text/html', + method='GET') + res = req.get_response(app) + self.send_response(res.status_code) + for header_name, header_value in res.headerlist: + self.send_header(header_name, header_value) + self.end_headers() + self.wfile.write(res.body) + self.wfile.close() + + +def positive_int(blob): + value = int(blob) + if value < 0: + msg = "%r is not a positive integer" % blob + raise argparse.ArgumentTypeError(msg) + return value + + +def create_server(port=0): + handler = HttpHandler + server = socketserver.TCPServer(("", port), handler) + return server + + +def main(args=None): + """Runs a basic http server to show healthcheck functionality.""" + parser = argparse.ArgumentParser() + parser.add_argument("-p", "--port", + help="Unused port to run the tiny" + " http server on (or zero to select a" + " random unused port)", + type=positive_int, required=True) + args = parser.parse_args(args=args) + server = create_server(args.port) + print("Serving at port: %s" % server.server_address[1]) + server.serve_forever() + + +if __name__ == '__main__': + main() diff --git a/oslo_middleware/http_proxy_to_wsgi.py b/oslo_middleware/http_proxy_to_wsgi.py index ad61401..84bc32b 100644 --- a/oslo_middleware/http_proxy_to_wsgi.py +++ b/oslo_middleware/http_proxy_to_wsgi.py @@ -19,7 +19,7 @@ from oslo_middleware import base OPTS = [ cfg.BoolOpt('enable_proxy_headers_parsing', default=False, - help="Wether the application is behind a proxy or not. " + help="Whether the application is behind a proxy or not. " "This determines if the middleware should parse the " "headers or not.") ] diff --git a/oslo_middleware/opts.py b/oslo_middleware/opts.py index 1fe8c89..e66e723 100644 --- a/oslo_middleware/opts.py +++ b/oslo_middleware/opts.py @@ -17,7 +17,8 @@ __all__ = [ 'list_opts', 'list_opts_sizelimit', 'list_opts_ssl', - 'list_opts_cors' + 'list_opts_cors', + 'list_opts_http_proxy_to_wsgi', ] @@ -25,6 +26,7 @@ import copy import itertools from oslo_middleware import cors +from oslo_middleware import http_proxy_to_wsgi from oslo_middleware import sizelimit from oslo_middleware import ssl @@ -53,6 +55,7 @@ def list_opts(): list_opts_sizelimit(), list_opts_ssl(), list_opts_cors(), + list_opts_http_proxy_to_wsgi(), ) ) @@ -128,3 +131,27 @@ def list_opts_cors(): ('cors', copy.deepcopy(cors.CORS_OPTS)), ('cors.subdomain', copy.deepcopy(cors.CORS_OPTS)) ] + + +def list_opts_http_proxy_to_wsgi(): + """Return a list of oslo.config options for http_proxy_to_wsgi. + + 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 + """ + return [ + ('oslo_middleware', copy.deepcopy(http_proxy_to_wsgi.OPTS)), + ] diff --git a/oslo_middleware/tests/test_base.py b/oslo_middleware/tests/test_base.py index ad48da5..425ff9a 100644 --- a/oslo_middleware/tests/test_base.py +++ b/oslo_middleware/tests/test_base.py @@ -58,6 +58,17 @@ class TestBase(BaseTestCase): self.assertTrue(self.application.called_without_request) + def test_no_content_type_added(self): + class TestMiddleware(Middleware): + @staticmethod + def process_request(req): + return "foobar" + + m = TestMiddleware(None) + request = webob.Request({}, method='GET') + response = request.get_response(m) + self.assertNotIn('Content-Type', response.headers) + def test_paste_deploy_legacy(self): app = LegacyMiddlewareTest.factory( {'global': True}, local=True)(application) diff --git a/oslo_middleware/tests/test_healthcheck.py b/oslo_middleware/tests/test_healthcheck.py index 3ffb03f..19fc63a 100644 --- a/oslo_middleware/tests/test_healthcheck.py +++ b/oslo_middleware/tests/test_healthcheck.py @@ -13,12 +13,36 @@ # License for the specific language governing permissions and limitations # under the License. +import threading +import time + import mock from oslotest import base as test_base +import requests import webob.dec import webob.exc from oslo_middleware import healthcheck +from oslo_middleware.healthcheck import __main__ + + +class HealthcheckMainTests(test_base.BaseTestCase): + + def test_startup_response(self): + server = __main__.create_server(0) + th = threading.Thread(target=server.serve_forever) + th.start() + self.addCleanup(server.shutdown) + while True: + try: + r = requests.get("http://%s:%s" % (server.server_address[0], + server.server_address[1])) + except requests.ConnectionError: + # Server hasn't started up yet, try again in a few. + time.sleep(1) + else: + self.assertEqual(200, r.status_code) + break class HealthcheckTests(test_base.BaseTestCase): diff --git a/requirements.txt b/requirements.txt index f03122f..b80e5c6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,11 +4,11 @@ pbr>=1.6 # Apache-2.0 Jinja2>=2.8 # BSD License (3 clause) -oslo.config>=3.9.0 # Apache-2.0 -oslo.context>=2.2.0 # Apache-2.0 +oslo.config>=3.12.0 # Apache-2.0 +oslo.context>=2.4.0 # Apache-2.0 oslo.i18n>=2.1.0 # Apache-2.0 -oslo.utils>=3.5.0 # Apache-2.0 +oslo.utils>=3.15.0 # Apache-2.0 six>=1.9.0 # MIT -stevedore>=1.9.0 # Apache-2.0 +stevedore>=1.10.0 # Apache-2.0 WebOb>=1.2.3 # MIT debtcollector>=1.2.0 # Apache-2.0 @@ -28,6 +28,7 @@ oslo.config.opts = oslo.middleware.cors = oslo_middleware.opts:list_opts_cors 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 = disable_by_file = oslo_middleware.healthcheck.disable_by_file:DisableByFileHealthcheck diff --git a/test-requirements.txt b/test-requirements.txt index fc60e42..5f53419 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,11 +2,11 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -fixtures<2.0,>=1.3.1 # Apache-2.0/BSD +fixtures>=3.0.0 # Apache-2.0/BSD hacking<0.11,>=0.10.0 -mock>=1.2 # BSD +mock>=2.0 # BSD oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 oslotest>=1.10.0 # Apache-2.0 -sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD +sphinx!=1.3b1,<1.3,>=1.2.1 # BSD testtools>=1.4.0 # MIT coverage>=3.6 # Apache-2.0 |