Send global_request_id for tracing calls
This patch adds global_request_id to the constructor for nova client, keystone client, neutron client and placement client which will pass the global_request_id to these respective services on all API calls. Supporting global_request_id makes debugging easier when requests reach many different OpenStack services. The blazar global_request_id will be sent to these services in the request header like below and it will be available with context.global_request_id: -H "X-OpenStack-Request-ID: req-1a9b7b24-02ed-4400-bcc3-cc1bcbb59147" Sample log output of neutron service for ``POST v1/floatingips`` API which logs global request ID `req-e19f8f4f-40e7-441e-b776-7b43ed15c7dd` is shown at: http://paste.openstack.org/show/753807 Oslo spec I65de8261746b25d45e105394f4eeb95b9cb3bd42 Change-Id: I5bb3631c4fb178293ee8eefbe1aa8b819a196a9f
This commit is contained in:
parent
bd8185e694
commit
563e4a8da2
25
api-ref/source/v1/global-request-id.inc
Normal file
25
api-ref/source/v1/global-request-id.inc
Normal file
@ -0,0 +1,25 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
==================
|
||||
Global Request ID
|
||||
==================
|
||||
|
||||
Users can specify a global request ID as a request header.
|
||||
|
||||
**Request**
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- X-Openstack-Request-Id: x-openstack-request-id_req
|
||||
|
||||
**Request Header**
|
||||
|
||||
In each REST API request, you can specify a global request ID
|
||||
in the ``X-Openstack-Request-Id`` header.
|
||||
The format must be ``req-`` + UUID (UUID4).
|
||||
If not in accordance with the format, the global request ID is
|
||||
ignored by Blazar.
|
||||
|
||||
Request header example::
|
||||
|
||||
X-Openstack-Request-Id: req-e19f8f4f-40e7-441e-b776-7b43ed15c7dd
|
@ -11,3 +11,4 @@ Blazar project.
|
||||
.. include:: hosts.inc
|
||||
.. include:: floatingips.inc
|
||||
.. include:: request-ids.inc
|
||||
.. include:: global-request-id.inc
|
||||
|
@ -1,4 +1,17 @@
|
||||
# variables in headers
|
||||
x-openstack-request-id_req:
|
||||
description: |
|
||||
The global request ID, which is a unique common ID
|
||||
for tracking each request in OpenStack services.
|
||||
The format of the global request ID must be ``req-`` + UUID (UUID4).
|
||||
If not in accordance with the format, it is ignored.
|
||||
It is associated with the request and appears in the log lines
|
||||
for that request.
|
||||
The global request ID appears in the Blazar logs and all cross
|
||||
services it interacts with.
|
||||
in: header
|
||||
required: false
|
||||
type: string
|
||||
x-openstack-request-id_resp:
|
||||
description: |
|
||||
The local request ID, which is a unique ID generated automatically
|
||||
|
@ -40,4 +40,6 @@ def ctx_from_headers(headers):
|
||||
# For v1 only, request_id and global_request_id will be available.
|
||||
if headers.environ['PATH_INFO'].startswith('/v1'):
|
||||
kwargs['request_id'] = headers.environ['openstack.request_id']
|
||||
kwargs['global_request_id'] = headers.environ.get(
|
||||
'openstack.global_request_id')
|
||||
return context.BlazarContext(**kwargs)
|
||||
|
@ -58,7 +58,8 @@ class ContextTestCaseV1(ContextTestCase):
|
||||
def test_ctx_from_headers(self):
|
||||
self.fake_headers[u'X-Service-Catalog'] = self.catalog
|
||||
environ_base = {
|
||||
'openstack.request_id': 'req-' + uuidsentinel.reqid}
|
||||
'openstack.request_id': 'req-' + uuidsentinel.reqid,
|
||||
'openstack.global_request_id': 'req-' + uuidsentinel.globalreqid}
|
||||
req = wrappers.Request.from_values(
|
||||
'/v1/leases',
|
||||
headers=self.fake_headers,
|
||||
@ -74,7 +75,8 @@ class ContextTestCaseV1(ContextTestCase):
|
||||
service_catalog={u'nova': u'catalog'},
|
||||
project_id=uuidsentinel.project_id,
|
||||
user_name=u'user_name',
|
||||
request_id='req-' + uuidsentinel.reqid)
|
||||
request_id='req-' + uuidsentinel.reqid,
|
||||
global_request_id='req-' + uuidsentinel.globalreqid)
|
||||
|
||||
|
||||
class ContextTestCaseV2(ContextTestCase):
|
||||
|
@ -74,7 +74,10 @@ class TestCKClient(tests.TestCase):
|
||||
endpoint='http://fake.com/',
|
||||
username=self.username,
|
||||
password=self.password,
|
||||
auth_url=self.auth_url)
|
||||
auth_url=self.auth_url,
|
||||
global_request_id=self.
|
||||
context.current().
|
||||
global_request_id)
|
||||
|
||||
def test_client_from_ctx(self):
|
||||
|
||||
@ -86,7 +89,8 @@ class TestCKClient(tests.TestCase):
|
||||
token=self.ctx().auth_token,
|
||||
tenant_name=self.ctx().project_name,
|
||||
auth_url='http://fake.com/',
|
||||
endpoint='http://fake.com/')
|
||||
endpoint='http://fake.com/',
|
||||
global_request_id=self.context.current().global_request_id)
|
||||
|
||||
def test_complement_auth_url_supported_api_version(self):
|
||||
bkc = self.keystone.BlazarKeystoneClient()
|
||||
|
@ -19,6 +19,7 @@ from neutronclient.common import exceptions as neutron_exceptions
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture
|
||||
|
||||
from blazar import context
|
||||
from blazar import tests
|
||||
from blazar.utils.openstack import exceptions
|
||||
from blazar.utils.openstack import neutron
|
||||
@ -30,16 +31,21 @@ class TestBlazarNeutronClient(tests.TestCase):
|
||||
def setUp(self):
|
||||
super(TestBlazarNeutronClient, self).setUp()
|
||||
self.cfg = self.useFixture(fixture.Config(CONF))
|
||||
self.context = context
|
||||
self.ctx = self.patch(self.context, 'current')
|
||||
|
||||
def test_client_from_kwargs(self):
|
||||
kwargs = {
|
||||
'auth_url': 'http://foo:8080/identity/v3',
|
||||
'region_name': 'RegionTwo'
|
||||
'region_name': 'RegionTwo',
|
||||
'global_request_id': 'req-e19f8f4f-40e7-441e-b776-7b43ed15c7dd'
|
||||
}
|
||||
client = neutron.BlazarNeutronClient(**kwargs)
|
||||
self.assertEqual("http://foo:8080/identity/v3",
|
||||
client.neutron.httpclient.session.auth.auth_url)
|
||||
self.assertEqual("RegionTwo", client.neutron.httpclient.region_name)
|
||||
self.assertEqual("req-e19f8f4f-40e7-441e-b776-7b43ed15c7dd",
|
||||
client.neutron.httpclient.global_request_id)
|
||||
|
||||
|
||||
class TestFloatingIPPool(tests.TestCase):
|
||||
|
@ -94,7 +94,8 @@ class TestCNClient(tests.TestCase):
|
||||
self.session.assert_called_once_with(auth=self.auth.return_value)
|
||||
self.client.assert_called_once_with(version=self.version,
|
||||
endpoint_override=self.url,
|
||||
session=self.session.return_value)
|
||||
session=self.session.return_value,
|
||||
global_request_id=mock.ANY)
|
||||
|
||||
def test_getattr(self):
|
||||
# TODO(n.s.): Will be done as soon as pypi package will be updated
|
||||
|
@ -62,6 +62,7 @@ class TestTrusts(tests.TestCase):
|
||||
fake_ctx_dict = {
|
||||
'auth_token': self.client().auth_token,
|
||||
'domain': None,
|
||||
'global_request_id': self.context.current().global_request_id,
|
||||
'is_admin': False,
|
||||
'is_admin_project': True,
|
||||
'project': self.client().tenant_id,
|
||||
|
@ -102,6 +102,7 @@ class BlazarKeystoneClient(object):
|
||||
if ctx is not None:
|
||||
kwargs.setdefault('username', ctx.user_name)
|
||||
kwargs.setdefault('tenant_name', ctx.project_name)
|
||||
kwargs.setdefault('global_request_id', ctx.global_request_id)
|
||||
if not kwargs.get('auth_url'):
|
||||
kwargs['auth_url'] = base.url_for(
|
||||
ctx.service_catalog, CONF.identity_service,
|
||||
|
@ -22,6 +22,7 @@ from neutronclient.v2_0 import client as neutron_client
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from blazar import context
|
||||
from blazar.utils.openstack import exceptions
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -32,6 +33,7 @@ class BlazarNeutronClient(object):
|
||||
"""Client class for Neutron service."""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
ctx = kwargs.pop('ctx', None)
|
||||
username = kwargs.pop('username',
|
||||
CONF.os_admin_username)
|
||||
password = kwargs.pop('password',
|
||||
@ -44,6 +46,13 @@ class BlazarNeutronClient(object):
|
||||
CONF.os_admin_project_domain_name)
|
||||
auth_url = kwargs.pop('auth_url', None)
|
||||
region_name = kwargs.pop('region_name', CONF.os_region_name)
|
||||
if ctx is None:
|
||||
try:
|
||||
ctx = context.current()
|
||||
except RuntimeError:
|
||||
pass
|
||||
if ctx is not None:
|
||||
kwargs.setdefault('global_request_id', ctx.global_request_id)
|
||||
|
||||
if auth_url is None:
|
||||
auth_url = "%s://%s:%s/%s/%s" % (CONF.os_auth_protocol,
|
||||
@ -59,8 +68,9 @@ class BlazarNeutronClient(object):
|
||||
user_domain_name=user_domain_name,
|
||||
project_domain_name=project_domain_name)
|
||||
sess = session.Session(auth=auth)
|
||||
self.neutron = neutron_client.Client(
|
||||
session=sess, region_name=region_name)
|
||||
kwargs.setdefault('session', sess)
|
||||
kwargs.setdefault('region_name', region_name)
|
||||
self.neutron = neutron_client.Client(**kwargs)
|
||||
|
||||
|
||||
class FloatingIPPool(BlazarNeutronClient):
|
||||
|
@ -127,6 +127,7 @@ class BlazarNovaClient(object):
|
||||
os_region_name=CONF.os_region_name)
|
||||
auth_url = base.url_for(ctx.service_catalog, CONF.identity_service,
|
||||
os_region_name=CONF.os_region_name)
|
||||
kwargs.setdefault('global_request_id', ctx.global_request_id)
|
||||
|
||||
if auth_url is None:
|
||||
auth_url = "%s://%s:%s/%s" % (CONF.os_auth_protocol,
|
||||
|
@ -20,6 +20,7 @@ from keystoneauth1 import session
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from blazar import context
|
||||
from blazar.utils.openstack import exceptions
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -33,6 +34,7 @@ class BlazarPlacementClient(object):
|
||||
|
||||
def _create_client(self, **kwargs):
|
||||
"""Create the HTTP session accessing the placement service."""
|
||||
ctx = kwargs.pop('ctx', None)
|
||||
username = kwargs.pop('username',
|
||||
CONF.os_admin_username)
|
||||
user_domain_name = kwargs.pop('user_domain_name',
|
||||
@ -47,6 +49,14 @@ class BlazarPlacementClient(object):
|
||||
auth_url = kwargs.pop('auth_url', None)
|
||||
region_name = kwargs.pop('region_name', CONF.os_region_name)
|
||||
|
||||
if ctx is None:
|
||||
try:
|
||||
ctx = context.current()
|
||||
except RuntimeError:
|
||||
pass
|
||||
if ctx is not None:
|
||||
kwargs.setdefault('global_request_id', ctx.global_request_id)
|
||||
|
||||
if auth_url is None:
|
||||
auth_url = "%s://%s:%s/%s/%s" % (CONF.os_auth_protocol,
|
||||
CONF.os_auth_host,
|
||||
@ -64,11 +74,11 @@ class BlazarPlacementClient(object):
|
||||
# Set accept header on every request to ensure we notify placement
|
||||
# service of our response body media type preferences.
|
||||
headers = {'accept': 'application/json'}
|
||||
client = adapter.Adapter(session=sess,
|
||||
service_type='placement',
|
||||
interface='public',
|
||||
region_name=region_name,
|
||||
additional_headers=headers)
|
||||
kwargs.setdefault('service_type', 'placement')
|
||||
kwargs.setdefault('interface', 'public')
|
||||
kwargs.setdefault('additional_headers', headers)
|
||||
kwargs.setdefault('region_name', region_name)
|
||||
client = adapter.Adapter(sess, **kwargs)
|
||||
return client
|
||||
|
||||
def get(self, url, microversion=PLACEMENT_MICROVERSION):
|
||||
|
@ -55,7 +55,8 @@ def create_ctx_from_trust(trust_id):
|
||||
ctx = context.BlazarContext(
|
||||
user_name=CONF.os_admin_username,
|
||||
project_name=CONF.os_admin_project_name,
|
||||
request_id=ctx.request_id
|
||||
request_id=ctx.request_id,
|
||||
global_request_id=ctx.global_request_id
|
||||
)
|
||||
auth_url = "%s://%s:%s/%s" % (CONF.os_auth_protocol,
|
||||
CONF.os_auth_host,
|
||||
@ -75,7 +76,8 @@ def create_ctx_from_trust(trust_id):
|
||||
auth_token=client.auth_token,
|
||||
service_catalog=client.service_catalog.catalog['catalog'],
|
||||
project_id=client.tenant_id,
|
||||
request_id=ctx.request_id
|
||||
request_id=ctx.request_id,
|
||||
global_request_id=ctx.global_request_id
|
||||
)
|
||||
|
||||
|
||||
|
13
releasenotes/notes/global_request_id-f30e900f20752c2b.yaml
Normal file
13
releasenotes/notes/global_request_id-f30e900f20752c2b.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
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
|
||||
allows for cross-project request ID tracking. By default, global request
|
||||
IDs will not appear in the Blazar service logs. Operators need to add
|
||||
global_request_id in the `logging_context_format_string`_ configuration
|
||||
option.
|
||||
|
||||
.. _`global_request_id`: https://developer.openstack.org/api-ref/reservation/v1/index.html#global-request-id
|
||||
.. _`logging_context_format_string`: https://docs.openstack.org/oslo.log/latest/configuration/index.html#DEFAULT.logging_context_format_string
|
Loading…
x
Reference in New Issue
Block a user