]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Sync request_id, request_utils for cinder
authorChris Buccella <buccella@linux.vnet.ibm.com>
Sat, 15 Feb 2014 02:29:43 +0000 (02:29 +0000)
committerChris Buccella <buccella@linux.vnet.ibm.com>
Tue, 18 Feb 2014 17:05:09 +0000 (17:05 +0000)
This is in preparation for work being done on request ID tracing across
OpenStack services.

Per discussion in blueprint cross-service-request-id , the standard header
name for the request ID across OpenStack projects should be
x-openstack-request-id. The request_id middleware was created for just this
purpose, as oslo change Ic7967cd62e7b743343d70f751b9238339171e013 . Using the
same middleware allows for consistency across projects.

There is an additional oslo module, request_utils, introduced as
change Id085c4444fee2bb68b80738bfe77ccb0ba1908ec to allow uniform logging of
request IDs. Bring that in as well so we have it when necessary.

Implements: blueprint add-standard-req-id-header
Change-Id: If080df2a323347924c93a912538dab5ffeffe982

cinder/openstack/common/middleware/__init__.py [new file with mode: 0644]
cinder/openstack/common/middleware/base.py [new file with mode: 0644]
cinder/openstack/common/middleware/request_id.py [new file with mode: 0644]
cinder/openstack/common/request_utils.py [new file with mode: 0644]
openstack-common.conf

diff --git a/cinder/openstack/common/middleware/__init__.py b/cinder/openstack/common/middleware/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/cinder/openstack/common/middleware/base.py b/cinder/openstack/common/middleware/base.py
new file mode 100644 (file)
index 0000000..464a1cc
--- /dev/null
@@ -0,0 +1,56 @@
+# 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)
diff --git a/cinder/openstack/common/middleware/request_id.py b/cinder/openstack/common/middleware/request_id.py
new file mode 100644 (file)
index 0000000..53d9813
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (c) 2013 NEC Corporation
+# 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 request ID.
+
+It ensures to assign request ID for each API request and set it to
+request environment. The request ID is also added to API response.
+"""
+
+from cinder.openstack.common import context
+from cinder.openstack.common.middleware import base
+
+
+ENV_REQUEST_ID = 'openstack.request_id'
+HTTP_RESP_HEADER_REQUEST_ID = 'x-openstack-request-id'
+
+
+class RequestIdMiddleware(base.Middleware):
+
+    def process_request(self, req):
+        self.req_id = context.generate_request_id()
+        req.environ[ENV_REQUEST_ID] = self.req_id
+
+    def process_response(self, response):
+        response.headers.add(HTTP_RESP_HEADER_REQUEST_ID, self.req_id)
+        return response
diff --git a/cinder/openstack/common/request_utils.py b/cinder/openstack/common/request_utils.py
new file mode 100644 (file)
index 0000000..105a628
--- /dev/null
@@ -0,0 +1,88 @@
+# Copyright 2014 Rackspace Hosting
+# 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.
+
+"""
+Utilities for linking request ID's across service calls.
+"""
+
+import logging
+
+from openstack.common.gettextutils import _  # noqa
+
+
+LOG = logging.getLogger(__name__)
+
+
+def link_request_ids(context, source_id, target_id=None, stage=None,
+                     target_name=None, notifier=None):
+    """Links the Request ID from the Source service to
+       the Request ID returned from the Target service.
+
+       Linkages are logged and emitted as INFO notifications.
+
+       :params context: context object
+       :params source_id: the Request ID of the source
+       :params target_id: the Request ID of the target
+       :params stage: optional event name extension to
+                      indicate which part of the linkage
+                      this is.
+       :params target_name: human readable name of the
+                            target system you are talking to.
+       :params notifier: notifier object
+
+       A typical use case is: System A asking System B
+       to perform some action. The linkages might look
+       like this:
+
+       link_request_ids(sys_A.request_ID, stage="start")
+       # send request to System B and get request ID
+       link_request_ids(sys_A.request_ID, target_id=sys_B.request.ID)
+       # optionally wait for System B to complete
+       link_request_ids(sys_A.request_ID, target_id=sys_B.request.ID,
+                        stage="end")
+
+       But, it could be as simple as:
+       link_request_ids(sys_A.request_ID, target_id=sys_B.request.ID)
+       """
+
+    event_name = "request.link"
+    if stage:
+        event_name += ".%s" % stage
+
+    rtarget_id = ""
+    if target_id:
+        rtarget_id = _("TargetId=%(id)s ") % {'id': target_id}
+
+    rtarget_name = ""
+    if target_name:
+        rtarget_name = _("Target='%(name)s' ") % {'name': target_name}
+
+    arrow = ""
+    if target_name or target_id:
+        arrow = " -> "
+
+    LOG.info(_("Request ID Link: %(event_name)s '%(source_id)s'%(arrow)s"
+               "%(target_name)s%(target_id)s") % {"event_name": event_name,
+                                                  "source_id": source_id,
+                                                  "target_name": rtarget_name,
+                                                  "arrow": arrow,
+                                                  "target_id": rtarget_id})
+
+    if notifier:
+        payload = {"source_request_id": source_id,
+                   "target_request_id": target_id,
+                   "target_name": target_name,
+                   "stage": stage}
+        notifier.info(context, event_name, payload)
index d5ed6e43c59b946cde092570542dac01abc9a106..44e5a96e2c3e4384eb3b877edabb61d1e7cada2e 100644 (file)
@@ -17,11 +17,13 @@ module=local
 module=lockutils
 module=log
 module=log_handler
+module=middleware
 module=network_utils
 module=notifier
 module=periodic_task
 module=policy
 module=processutils
+module=request_utils
 module=rootwrap
 module=rpc
 module=scheduler