Merge "Add x-openstack-request-id to nova v3 responses"

This commit is contained in:
Jenkins
2014-05-07 01:10:23 +00:00
committed by Gerrit Code Review
9 changed files with 126 additions and 32 deletions
+11 -5
View File
@@ -65,14 +65,20 @@ use = call:nova.api.openstack.urlmap:urlmap_factory
[composite:openstack_compute_api_v2]
use = call:nova.api.auth:pipeline_factory
noauth = faultwrap sizelimit noauth ratelimit osapi_compute_app_v2
keystone = faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2
noauth = compute_req_id faultwrap sizelimit noauth ratelimit osapi_compute_app_v2
keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2
[composite:openstack_compute_api_v3]
use = call:nova.api.auth:pipeline_factory_v3
noauth = faultwrap sizelimit noauth_v3 osapi_compute_app_v3
keystone = faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v3
noauth = request_id faultwrap sizelimit noauth_v3 osapi_compute_app_v3
keystone = request_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v3
[filter:request_id]
paste.filter_factory = nova.openstack.common.middleware.request_id:RequestIdMiddleware.factory
[filter:compute_req_id]
paste.filter_factory = nova.api.compute_req_id:ComputeReqIdMiddleware.factory
[filter:faultwrap]
paste.filter_factory = nova.api.openstack:FaultWrapper.factory
+5 -1
View File
@@ -24,6 +24,7 @@ from nova import context
from nova.openstack.common.gettextutils import _
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
from nova.openstack.common.middleware import request_id
from nova import wsgi
@@ -113,6 +114,8 @@ class NovaKeystoneContext(wsgi.Middleware):
project_name = req.headers.get('X_TENANT_NAME')
user_name = req.headers.get('X_USER_NAME')
req_id = req.environ.get(request_id.ENV_REQUEST_ID)
# Get the auth token
auth_token = req.headers.get('X_AUTH_TOKEN',
req.headers.get('X_STORAGE_TOKEN'))
@@ -138,7 +141,8 @@ class NovaKeystoneContext(wsgi.Middleware):
roles=roles,
auth_token=auth_token,
remote_address=remote_address,
service_catalog=service_catalog)
service_catalog=service_catalog,
request_id=req_id)
req.environ['nova.context'] = ctx
return self.application
+45
View File
@@ -0,0 +1,45 @@
# Copyright (c) 2014 IBM Corp.
# 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.
"""Middleware that ensures x-compute-request-id
Using this middleware provides a convenient way to attach the
x-compute-request-id to only v2 responses. Previously, this header was set in
api/openstack/wsgi.py
Responses for APIv3 are taken care of by the request_id middleware provided
in oslo.
"""
import webob.dec
from nova.openstack.common import context
from nova.openstack.common.middleware import base
ENV_REQUEST_ID = 'openstack.request_id'
HTTP_RESP_HEADER_REQUEST_ID = 'x-compute-request-id'
class ComputeReqIdMiddleware(base.Middleware):
@webob.dec.wsgify
def __call__(self, req):
req_id = context.generate_request_id()
req.environ[ENV_REQUEST_ID] = req_id
response = req.get_response(self.application)
if HTTP_RESP_HEADER_REQUEST_ID not in response.headers:
response.headers.add(HTTP_RESP_HEADER_REQUEST_ID, req_id)
return response
-10
View File
@@ -1013,9 +1013,6 @@ class Resource(wsgi.Application):
self.default_serializers)
if hasattr(response, 'headers'):
if context:
response.headers.add('x-compute-request-id',
context.request_id)
for hdr, val in response.headers.items():
# Headers must be utf-8 strings
@@ -1238,7 +1235,6 @@ class Fault(webob.exc.HTTPException):
self.wrapped_exc.body = serializer.serialize(fault_data)
self.wrapped_exc.content_type = content_type
_set_request_id_header(req, self.wrapped_exc.headers)
return self.wrapped_exc
@@ -1298,9 +1294,3 @@ class RateLimitFault(webob.exc.HTTPException):
self.wrapped_exc.content_type = content_type
return self.wrapped_exc
def _set_request_id_header(req, headers):
context = req.environ.get('nova.context')
if context:
headers['x-compute-request-id'] = context.request_id
@@ -20,7 +20,6 @@ import webob.exc
from nova.api import openstack as openstack_api
from nova.api.openstack import wsgi
import nova.context
from nova import exception
from nova.openstack.common import jsonutils
from nova import test
@@ -187,13 +186,3 @@ class APITest(test.NoDBTestCase):
api = self._wsgi_app(fail)
resp = webob.Request.blank('/').get_response(api)
self.assertEqual(500, resp.status_int)
def test_request_id_in_response(self):
req = webob.Request.blank('/')
req.method = 'GET'
context = nova.context.RequestContext('bob', 1)
context.request_id = 'test-req-id'
req.environ['nova.context'] = context
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.headers['x-compute-request-id'], 'test-req-id')
+10 -5
View File
@@ -335,6 +335,14 @@ class XMLDeserializerTest(test.NoDBTestCase):
class ResourceTest(test.NoDBTestCase):
def get_req_id_header_name(self, request):
header_name = 'x-openstack-request-id'
if utils.get_api_version(request) < 3:
header_name = 'x-compute-request-id'
return header_name
def test_resource_call_with_method_get(self):
class Controller(object):
def index(self, req):
@@ -639,8 +647,6 @@ class ResourceTest(test.NoDBTestCase):
context = req.environ['nova.context']
app = fakes.TestRouter(Controller())
response = req.get_response(app)
self.assertEqual(response.headers['x-compute-request-id'],
context.request_id)
self.assertEqual(response.body, '{"foo": "bar"}')
self.assertEqual(response.status_int, 200)
@@ -655,7 +661,8 @@ class ResourceTest(test.NoDBTestCase):
# NOTE(alaski): This test is really to ensure that a str response
# doesn't error. Not having a request_id header is a side effect of
# our wsgi setup, ideally it would be there.
self.assertFalse(hasattr(response.headers, 'x-compute-request-id'))
expected_header = self.get_req_id_header_name(req)
self.assertFalse(hasattr(response.headers, expected_header))
self.assertEqual(response.body, 'foo')
self.assertEqual(response.status_int, 200)
@@ -668,8 +675,6 @@ class ResourceTest(test.NoDBTestCase):
context = req.environ['nova.context']
app = fakes.TestRouter(Controller())
response = req.get_response(app)
self.assertEqual(response.headers['x-compute-request-id'],
context.request_id)
self.assertEqual(response.body, '')
self.assertEqual(response.status_int, 200)
+9
View File
@@ -19,6 +19,7 @@ import webob.exc
import nova.api.auth
from nova.openstack.common.gettextutils import _
from nova.openstack.common.middleware import request_id
from nova import test
CONF = cfg.CONF
@@ -70,6 +71,14 @@ class TestNovaKeystoneContextMiddleware(test.NoDBTestCase):
response = self.request.get_response(self.middleware)
self.assertEqual(response.status, '500 Internal Server Error')
def test_request_id_extracted_from_env(self):
req_id = 'dummy-request-id'
self.request.headers['X_PROJECT_ID'] = 'testtenantid'
self.request.headers['X_USER_ID'] = 'testuserid'
self.request.environ[request_id.ENV_REQUEST_ID] = req_id
self.request.get_response(self.middleware)
self.assertEqual(req_id, self.context.request_id)
class TestKeystoneMiddlewareRoles(test.NoDBTestCase):
+40
View File
@@ -0,0 +1,40 @@
# Copyright (c) 2014 IBM Corp.
# 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.
from testtools import matchers
import webob
import webob.dec
from nova.api import compute_req_id
from nova.openstack.common import context
from nova import test
class RequestIdTest(test.TestCase):
def test_generate_request_id(self):
@webob.dec.wsgify
def application(req):
return req.environ[compute_req_id.ENV_REQUEST_ID]
app = compute_req_id.ComputeReqIdMiddleware(application)
req = webob.Request.blank('/test')
req_id = context.generate_request_id()
req.environ[compute_req_id.ENV_REQUEST_ID] = req_id
res = req.get_response(app)
res_id = res.headers.get(compute_req_id.HTTP_RESP_HEADER_REQUEST_ID)
self.assertThat(res_id, matchers.StartsWith('req-'))
self.assertEqual(res_id, res.body)
+6
View File
@@ -206,3 +206,9 @@ def is_ipv6_supported():
has_ipv6_support = False
return has_ipv6_support
def get_api_version(request):
api_version = 2
if request.path[2:3].isdigit():
return int(request.path[2:3])