Move to the oslo.middleware library

This patch moves Cinder to using olso.middleware, updates us so
we are using the oslo_middleware namespace and syncs the latest
middleware code from oslo-incubator to support grenade jobs.

The details for the middleware sync from oslo-incubator are as follows:

Current HEAD in OSLO:
---------------------
commit e589dde0721a0a67e4030813e582afec6e70d042
Date:  Wed Feb 18 03:08:12 2015 +0000
Merge "Have a little fun with release notes"

Changes merged with this patch:
---------------------
__init__.py
  4ffc4c87 - Add middleware.request_id shim for Kilo
  4504e4f4 - Remove middleware

catch_errors.py
  a01a8527 - Use oslo_middleware instead of deprecated oslo.middleware
  ce8f8fa4 - Add middleware.catch_errors shim for Kilo
  4504e4f4 - Remove middleware
  5d40e143 - Remove code that moved to oslo.i18n
  76183592 - add deprecation note to middleware
  463e6916 - remove oslo log from middleware
  fcf517d7 - Update oslo log messages with translation domains

request_id.py
  a01a8527 - Use oslo_middleware instead of deprecated oslo.middleware
  66d8d613 - Fix oslo.middleware deprecation error
  4ffc4c87 - Add middleware.request_id shim for Kilo
  4504e4f4 - Remove middleware
  76183592 - add deprecation note to middleware
  d7bd9dc3 - Don't store the request ID value in middleware as class variable

Some notes on this change.  It is based on the change made in Nova:
https://review.openstack.org/#/c/130771 and is the recommended method
for cleaning up the unused portions of middleware from oslo-incubator,
moving to the oslo.middleware library and not breaking grenade in the
gate.

Change-Id: Ia99ab479cb8ef63a0db1a1208cc2501abba6132c
This commit is contained in:
Jay S. Bryant 2015-03-10 20:15:00 -05:00
parent 99c0701ae1
commit c489747177
10 changed files with 19 additions and 218 deletions

View File

@ -22,6 +22,7 @@ import os
from oslo_config import cfg
from oslo_log import log as logging
from oslo_middleware import request_id
from oslo_serialization import jsonutils
import webob.dec
import webob.exc
@ -29,7 +30,6 @@ import webob.exc
from cinder.api.openstack import wsgi
from cinder import context
from cinder.i18n import _
from cinder.openstack.common.middleware import request_id
from cinder import wsgi as base_wsgi

View File

@ -13,17 +13,14 @@
# under the License.
"""
Request Body limiting middleware.
Compatibility shim for Kilo, while operators migrate to oslo.middleware.
"""
from oslo_config import cfg
from oslo_log import log as logging
import webob.dec
import webob.exc
from oslo_middleware import sizelimit
from cinder.i18n import _
from cinder import wsgi
from cinder.openstack.common import versionutils
# Default request size is 112k
@ -34,52 +31,9 @@ max_request_body_size_opt = cfg.IntOpt('osapi_max_request_body_size',
CONF = cfg.CONF
CONF.register_opt(max_request_body_size_opt)
LOG = logging.getLogger(__name__)
class LimitingReader(object):
"""Reader to limit the size of an incoming request."""
def __init__(self, data, limit):
"""Initialize LimitingReader.
:param data: Underlying data object
:param limit: maximum number of bytes the reader should allow
"""
self.data = data
self.limit = limit
self.bytes_read = 0
def __iter__(self):
for chunk in self.data:
self.bytes_read += len(chunk)
if self.bytes_read > self.limit:
msg = _("Request is too large.")
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
else:
yield chunk
def read(self, i=None):
result = self.data.read(i)
self.bytes_read += len(result)
if self.bytes_read > self.limit:
msg = _("Request is too large.")
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
return result
class RequestBodySizeLimiter(wsgi.Middleware):
@versionutils.deprecated(as_of=versionutils.deprecated.KILO,
in_favor_of='oslo_middleware.RequestBodySizeLimiter')
class RequestBodySizeLimiter(sizelimit.RequestBodySizeLimiter):
"""Add a 'cinder.context' to WSGI environ."""
def __init__(self, *args, **kwargs):
super(RequestBodySizeLimiter, self).__init__(*args, **kwargs)
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
if req.content_length > CONF.osapi_max_request_body_size:
msg = _("Request is too large.")
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
if req.content_length is None and req.is_body_readable:
limiter = LimitingReader(req.body_file,
CONF.osapi_max_request_body_size)
req.body_file = limiter
return self.application
pass

View File

@ -1,56 +0,0 @@
# Copyright 2011 OpenStack Foundation.
# 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.
"""Base class(es) for WSGI Middleware."""
import webob.dec
class Middleware(object):
"""Base WSGI middleware wrapper.
These classes require an application to be initialized that will be called
next. By default the middleware will simply call its wrapped app, or you
can override __call__ to customize its behavior.
"""
@classmethod
def factory(cls, global_conf, **local_conf):
"""Factory method for paste.deploy."""
return cls
def __init__(self, application):
self.application = application
def process_request(self, req):
"""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.
"""
return None
def process_response(self, response):
"""Do whatever you'd like to the response."""
return response
@webob.dec.wsgify
def __call__(self, req):
response = self.process_request(req)
if response:
return response
response = req.get_response(self.application)
return self.process_response(response)

View File

@ -12,12 +12,12 @@
"""Compatibility shim for Kilo, while operators migrate to oslo.middleware."""
from oslo.middleware import catch_errors
from oslo_middleware import catch_errors
from cinder.openstack.common import versionutils
@versionutils.deprecated(as_of=versionutils.deprecated.KILO,
in_favor_of='oslo.middleware.CatchErrors')
in_favor_of='oslo_middleware.CatchErrors')
class CatchErrorsMiddleware(catch_errors.CatchErrors):
pass

View File

@ -12,7 +12,7 @@
"""Compatibility shim for Kilo, while operators migrate to oslo.middleware."""
from oslo.middleware import request_id
from oslo_middleware import request_id
from cinder.openstack.common import versionutils
@ -22,6 +22,6 @@ HTTP_RESP_HEADER_REQUEST_ID = 'x-openstack-request-id'
@versionutils.deprecated(as_of=versionutils.deprecated.KILO,
in_favor_of='oslo.middleware.RequestId')
in_favor_of='oslo_middleware.RequestId')
class RequestIdMiddleware(request_id.RequestId):
pass

View File

@ -12,10 +12,10 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_middleware import request_id
import webob
import cinder.api.middleware.auth
from cinder.openstack.common.middleware import request_id
from cinder import test

View File

@ -1,102 +0,0 @@
# Copyright (c) 2012 OpenStack Foundation
#
# 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
import six
import webob
from cinder.api.middleware import sizelimit
from cinder import test
CONF = cfg.CONF
MAX_REQUEST_BODY_SIZE = CONF.osapi_max_request_body_size
class TestLimitingReader(test.TestCase):
def test_limiting_reader(self):
BYTES = 1024
bytes_read = 0
data = six.StringIO("*" * BYTES)
for chunk in sizelimit.LimitingReader(data, BYTES):
bytes_read += len(chunk)
self.assertEqual(bytes_read, BYTES)
bytes_read = 0
data = six.StringIO("*" * BYTES)
reader = sizelimit.LimitingReader(data, BYTES)
byte = reader.read(1)
while len(byte) != 0:
bytes_read += 1
byte = reader.read(1)
self.assertEqual(bytes_read, BYTES)
def test_limiting_reader_fails(self):
BYTES = 1024
def _consume_all_iter():
bytes_read = 0
data = six.StringIO("*" * BYTES)
for chunk in sizelimit.LimitingReader(data, BYTES - 1):
bytes_read += len(chunk)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
_consume_all_iter)
def _consume_all_read():
bytes_read = 0
data = six.StringIO("*" * BYTES)
reader = sizelimit.LimitingReader(data, BYTES - 1)
byte = reader.read(1)
while len(byte) != 0:
bytes_read += 1
byte = reader.read(1)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
_consume_all_read)
class TestRequestBodySizeLimiter(test.TestCase):
def setUp(self):
super(TestRequestBodySizeLimiter, self).setUp()
@webob.dec.wsgify()
def fake_app(req):
return webob.Response(req.body)
self.middleware = sizelimit.RequestBodySizeLimiter(fake_app)
self.request = webob.Request.blank('/', method='POST')
def test_content_length_acceptable(self):
self.request.headers['Content-Length'] = MAX_REQUEST_BODY_SIZE
self.request.body = "0" * MAX_REQUEST_BODY_SIZE
response = self.request.get_response(self.middleware)
self.assertEqual(response.status_int, 200)
def test_content_length_too_large(self):
self.request.headers['Content-Length'] = MAX_REQUEST_BODY_SIZE + 1
self.request.body = "0" * (MAX_REQUEST_BODY_SIZE + 1)
response = self.request.get_response(self.middleware)
self.assertEqual(response.status_int, 413)
def test_request_too_large_no_content_length(self):
self.request.body = "0" * (MAX_REQUEST_BODY_SIZE + 1)
self.request.headers['Content-Length'] = None
response = self.request.get_response(self.middleware)
self.assertEqual(response.status_int, 413)

View File

@ -21,7 +21,7 @@ keystone = request_id faultwrap sizelimit osprofiler authtoken keystonecontext a
keystone_nolimit = request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2
[filter:request_id]
paste.filter_factory = cinder.openstack.common.middleware.request_id:RequestIdMiddleware.factory
paste.filter_factory = oslo_middleware.request_id:RequestId.factory
[filter:faultwrap]
paste.filter_factory = cinder.api.middleware.fault:FaultWrapper.factory

View File

@ -18,6 +18,7 @@ oslo.context>=0.1.0
oslo.db>=1.4.1 # Apache-2.0
oslo.log>=0.4.0 # Apache-2.0
oslo.messaging>=1.6.0 # Apache-2.0
oslo.middleware>=0.3.0 # Apache-2.0
oslo.rootwrap>=1.5.0 # Apache-2.0
oslo.serialization>=1.2.0 # Apache-2.0
oslo.utils>=1.2.0 # Apache-2.0

View File

@ -59,6 +59,10 @@ oslo_messaging.notify.drivers =
cinder.openstack.common.notifier.rpc_notifier2 = oslo_messaging.notify._impl_messaging:MessagingV2Driver
cinder.openstack.common.notifier.rpc_notifier = oslo_messaging.notify._impl_messaging:MessagingDriver
cinder.openstack.common.notifier.test_notifier = oslo_messaging.notify._impl_test:TestDriver
# These are for backwards compatibility with Juno middleware configurations
oslo_middleware =
cinder.api.middleware.sizelimit = oslo_middleware.sizelimit
cinder.openstack.common.middleware.request_id = oslo_middleware.request_id
cinder.database.migration_backend =
sqlalchemy = oslo_db.sqlalchemy.migration