summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Dague <sean@dague.net>2017-05-23 07:37:10 -0400
committerSean Dague <sean@dague.net>2017-05-23 12:48:41 -0400
commit0e3dbba0d9d373fbfa9e28897cd33377e2491d32 (patch)
tree82ba63d04c9522b04516a822ef01ff6048446dde
parent9b94bae73c1cf5549a69e7798d175119cc1aaa2e (diff)
downloadoslo-middleware-0e3dbba0d9d373fbfa9e28897cd33377e2491d32.tar.gz
Set global_request_id if passed in as X-OpenStack-Request-ID.
If an inbound header that validates against the regex ``req-$uuid`` is passed in, we'll set it where oslo.context could later read it. This creates a mechanism for parents to pass their request-id to children. Change-Id: I5c5268e8680392395fbe04efe0124575ad8db468
-rw-r--r--oslo_middleware/request_id.py16
-rw-r--r--oslo_middleware/tests/test_request_id.py41
-rw-r--r--releasenotes/notes/global_request_id-a8ec7260fbd76444.yaml8
3 files changed, 65 insertions, 0 deletions
diff --git a/oslo_middleware/request_id.py b/oslo_middleware/request_id.py
index 5716c82..9003fa5 100644
--- a/oslo_middleware/request_id.py
+++ b/oslo_middleware/request_id.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import re
+
from oslo_context import context
import webob.dec
@@ -20,7 +22,11 @@ from oslo_middleware import base
ENV_REQUEST_ID = 'openstack.request_id'
+GLOBAL_REQ_ID = 'openstack.global_request_id'
HTTP_RESP_HEADER_REQUEST_ID = 'x-openstack-request-id'
+INBOUND_HEADER = 'X-Openstack-Request-Id'
+ID_FORMAT = (r'^req-[a-f0-9]{8}-[a-f0-9]{4}-'
+ r'[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$')
class RequestId(base.ConfigurableMiddleware):
@@ -35,8 +41,18 @@ class RequestId(base.ConfigurableMiddleware):
# oslo.middleware without impacting existing users.
compat_headers = []
+ def set_global_req_id(self, req):
+ gr_id = req.headers.get(INBOUND_HEADER, "")
+ if re.match(ID_FORMAT, gr_id):
+ req.environ[GLOBAL_REQ_ID] = gr_id
+ # TODO(sdague): it would be nice to warn if we dropped a bogus
+ # request_id, but the infrastructure for doing that isn't yet
+ # setup at this stage.
+
@webob.dec.wsgify
def __call__(self, req):
+ self.set_global_req_id(req)
+
req_id = context.generate_request_id()
req.environ[ENV_REQUEST_ID] = req_id
response = req.get_response(self.application)
diff --git a/oslo_middleware/tests/test_request_id.py b/oslo_middleware/tests/test_request_id.py
index 5c79c21..5374fa2 100644
--- a/oslo_middleware/tests/test_request_id.py
+++ b/oslo_middleware/tests/test_request_id.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import uuid
from oslotest import base as test_base
from testtools import matchers
@@ -63,3 +64,43 @@ class RequestIdTest(test_base.BaseTestCase):
self.assertEqual(res.headers.get("x-compute-req-id"), res_req_id)
self.assertEqual(res.headers.get("x-silly-id"), res_req_id)
+
+ def test_global_request_id_set(self):
+ """Test that global request_id is set."""
+ @webob.dec.wsgify
+ def application(req):
+ return req.environ[request_id.GLOBAL_REQ_ID]
+
+ global_req = "req-%s" % uuid.uuid4()
+ app = request_id.RequestId(application)
+ req = webob.Request.blank(
+ '/test',
+ headers={"X-OpenStack-Request-ID": global_req})
+ res = req.get_response(app)
+ res_req_id = res.headers.get(request_id.HTTP_RESP_HEADER_REQUEST_ID)
+ if isinstance(res_req_id, bytes):
+ res_req_id = res_req_id.decode('utf-8')
+ # global-request-id in request environ is returned as response body
+ self.assertEqual(res.body.decode('utf-8'), global_req)
+ self.assertNotEqual(res.body.decode('utf-8'), res_req_id)
+
+ def test_global_request_id_drop(self):
+ """Test that bad format ids are dropped.
+
+ This ensures that badly formatted ids are dropped entirely.
+ """
+ @webob.dec.wsgify
+ def application(req):
+ return req.environ.get(request_id.GLOBAL_REQ_ID)
+
+ global_req = "req-%s-bad" % uuid.uuid4()
+ app = request_id.RequestId(application)
+ req = webob.Request.blank(
+ '/test',
+ headers={"X-OpenStack-Request-ID": global_req})
+ res = req.get_response(app)
+ res_req_id = res.headers.get(request_id.HTTP_RESP_HEADER_REQUEST_ID)
+ if isinstance(res_req_id, bytes):
+ res_req_id = res_req_id.decode('utf-8')
+ # global-request-id in request environ is returned as response body
+ self.assertEqual(res.body.decode('utf-8'), '')
diff --git a/releasenotes/notes/global_request_id-a8ec7260fbd76444.yaml b/releasenotes/notes/global_request_id-a8ec7260fbd76444.yaml
new file mode 100644
index 0000000..335a76d
--- /dev/null
+++ b/releasenotes/notes/global_request_id-a8ec7260fbd76444.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ This adds support for ``global_request_id`` to the ``RequestId``
+ middleware. An inbound header of ``X-OpenStack-Request-ID`` is
+ accepted as long as it is of the format ``req-$uuid``, and made
+ available to oslo.context. This will allow for cross project
+ request id tracking.