From f6deffa73f244867b6a0cac6708f423d992700d9 Mon Sep 17 00:00:00 2001 From: Mitsuru Kanabuchi Date: Mon, 16 Jun 2014 21:40:36 +0900 Subject: [PATCH] Support x-openstack-request-id for Heat This patch aims to support "x-openstack-request-id" for Heat. Nova, Cinder and Neutron have realized "x-openstack-request-id" functionality by using oslo-incubator.middleware. This functionality will enable effective log tracing between Heat and Heat caller. Change-Id: Ida2f3d33b02557c2117aade27ccac7d9351886c9 Closes-bug: #1324065 --- etc/heat/api-paste.ini | 10 +++++++--- heat/common/context.py | 3 +++ heat/tests/test_common_context.py | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/etc/heat/api-paste.ini b/etc/heat/api-paste.ini index bd5af18a49..488c5293d9 100644 --- a/etc/heat/api-paste.ini +++ b/etc/heat/api-paste.ini @@ -1,7 +1,7 @@ # heat-api pipeline [pipeline:heat-api] -pipeline = faultwrap ssl versionnegotiation authurl authtoken context apiv1app +pipeline = request_id faultwrap ssl versionnegotiation authurl authtoken context apiv1app # heat-api pipeline for standalone heat # ie. uses alternative auth backend that authenticates users against keystone @@ -12,7 +12,7 @@ pipeline = faultwrap ssl versionnegotiation authurl authtoken context apiv1app # flavor = standalone # [pipeline:heat-api-standalone] -pipeline = faultwrap ssl versionnegotiation authurl authpassword context apiv1app +pipeline = request_id faultwrap ssl versionnegotiation authurl authpassword context apiv1app # heat-api pipeline for custom cloud backends # i.e. in heat.conf: @@ -20,7 +20,7 @@ pipeline = faultwrap ssl versionnegotiation authurl authpassword context apiv1ap # flavor = custombackend # [pipeline:heat-api-custombackend] -pipeline = faultwrap versionnegotiation context custombackendauth apiv1app +pipeline = request_id faultwrap versionnegotiation context custombackendauth apiv1app # heat-api-cfn pipeline [pipeline:heat-api-cfn] @@ -93,3 +93,7 @@ paste.filter_factory = heat.common.auth_password:filter_factory # Auth middleware that validates against custom backend [filter:custombackendauth] paste.filter_factory = heat.common.custom_backend_auth:filter_factory + +# Middleware to set x-openstack-request-id in http response header +[filter:request_id] +paste.filter_factory = heat.openstack.common.middleware.request_id:RequestIdMiddleware.factory diff --git a/heat/common/context.py b/heat/common/context.py index 7cd60dafa9..0cd620eff9 100644 --- a/heat/common/context.py +++ b/heat/common/context.py @@ -20,6 +20,7 @@ from heat.db import api as db_api from heat.openstack.common import context from heat.openstack.common import importutils from heat.openstack.common import local +from heat.openstack.common.middleware import request_id def generate_request_id(): @@ -152,6 +153,7 @@ class ContextMiddleware(wsgi.Middleware): if roles is not None: roles = roles.split(',') token_info = environ.get('keystone.token_info') + req_id = environ.get(request_id.ENV_REQUEST_ID) except Exception: raise exception.NotAuthenticated() @@ -164,6 +166,7 @@ class ContextMiddleware(wsgi.Middleware): password=password, auth_url=auth_url, roles=roles, + request_id=req_id, auth_token_info=token_info) diff --git a/heat/tests/test_common_context.py b/heat/tests/test_common_context.py index e6e710548e..572ce1f25e 100644 --- a/heat/tests/test_common_context.py +++ b/heat/tests/test_common_context.py @@ -18,6 +18,7 @@ import webob from heat.common import context from heat.common import exception +from heat.openstack.common.middleware import request_id from heat.openstack.common import policy as base_policy from heat.tests.common import HeatTestCase @@ -256,3 +257,23 @@ class RequestContextMiddlewareTest(HeatTestCase): ctx = request.context.to_dict() for k, v in self.context_dict.items(): self.assertEqual(v, ctx[k], 'Key %s values do not match' % k) + self.assertIsNotNone(ctx.get('request_id')) + + def test_context_middleware_with_requestid(self): + + middleware = context.ContextMiddleware(None, None) + request = webob.Request.blank('/stacks', headers=self.headers, + environ=self.environ) + req_id = 'req-5a63f0d7-1b69-447b-b621-4ea87cc7186d' + request.environ[request_id.ENV_REQUEST_ID] = req_id + if self.expected_exception: + self.assertRaises( + self.expected_exception, middleware.process_request, request) + else: + self.assertIsNone(middleware.process_request(request)) + ctx = request.context.to_dict() + for k, v in self.context_dict.items(): + self.assertEqual(v, ctx[k], 'Key %s values do not match' % k) + self.assertEqual( + ctx.get('request_id'), req_id, + 'Key request_id values do not match')