diff --git a/glance/api/middleware/context.py b/glance/api/middleware/context.py index aedf90478c..f7696f8db7 100644 --- a/glance/api/middleware/context.py +++ b/glance/api/middleware/context.py @@ -15,6 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. +import logging import webob.exc from glance.common import wsgi @@ -31,12 +32,21 @@ context_opts = [ CONF = cfg.CONF CONF.register_opts(context_opts) +LOG = logging.getLogger(__name__) -class ContextMiddleware(wsgi.Middleware): - def __init__(self, app): - super(ContextMiddleware, self).__init__(app) +class BaseContextMiddleware(wsgi.Middleware): + def process_response(self, resp): + try: + request_id = resp.request.context.request_id + except AttributeError: + LOG.error(_('Unable to retrieve request id from context')) + else: + resp.headers['x-openstack-request-id'] = 'req-%s' % request_id + return resp + +class ContextMiddleware(BaseContextMiddleware): def process_request(self, req): """Convert authentication information into a request context @@ -87,11 +97,7 @@ class ContextMiddleware(wsgi.Middleware): return glance.context.RequestContext(**kwargs) -class UnauthenticatedContextMiddleware(wsgi.Middleware): - - def __init__(self, app): - super(UnauthenticatedContextMiddleware, self).__init__(app) - +class UnauthenticatedContextMiddleware(BaseContextMiddleware): def process_request(self, req): """Create a context without an authorized user.""" kwargs = { diff --git a/glance/context.py b/glance/context.py index e18c863837..39839aa56e 100644 --- a/glance/context.py +++ b/glance/context.py @@ -15,6 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. +import glance.common.utils + class RequestContext(object): """ @@ -33,6 +35,7 @@ class RequestContext(object): self.read_only = read_only self._show_deleted = show_deleted self.owner_is_tenant = owner_is_tenant + self.request_id = glance.common.utils.generate_uuid() @property def owner(self): diff --git a/glance/tests/unit/test_context.py b/glance/tests/unit/test_context.py index 96cc50e52d..052d8c73ef 100644 --- a/glance/tests/unit/test_context.py +++ b/glance/tests/unit/test_context.py @@ -233,3 +233,8 @@ class TestContext(utils.BaseTestCase): """ self.do_sharable(True, 'pattieblack', _fake_membership(True), tenant='froggy') + + def test_request_id(self): + contexts = [context.RequestContext().request_id for _ in range(5)] + # Check for uniqueness -- set() will normalize its argument + self.assertEqual(5, len(set(contexts))) diff --git a/glance/tests/unit/test_context_middleware.py b/glance/tests/unit/test_context_middleware.py index 21b66d6441..9c6815a051 100644 --- a/glance/tests/unit/test_context_middleware.py +++ b/glance/tests/unit/test_context_middleware.py @@ -2,6 +2,7 @@ import webob from glance.api.middleware import context +import glance.context from glance.tests.unit import base @@ -99,3 +100,13 @@ class TestUnauthenticatedContextMiddleware(base.IsolatedUnitTest): self.assertEqual(req.context.tenant, None) self.assertEqual(req.context.roles, []) self.assertTrue(req.context.is_admin) + + def test_response(self): + middleware = context.UnauthenticatedContextMiddleware(None) + req = webob.Request.blank('/') + req.context = glance.context.RequestContext() + resp = webob.Response() + resp.request = req + middleware.process_response(resp) + self.assertEqual(resp.headers['x-openstack-request-id'], + 'req-%s' % req.context.request_id)