Add a per-request global_request_id
Adapter.__init__ takes a global_request_id which causes the X-Openstack-Request-Id header to be set on each request. This is fine if the Adapter is used for only one "request" (in the sense of e.g. "a server create" -- see [1]), but is too broad if the Adapter is reused for multiple requests. For example, Nova's SchedulerReportClient (used to communicate with Placement) creates a single instance of Adapter for the life of the process [2][3][4]. Openstack SDK's Proxy objects [5] endure for the life of a Connection. So what is needed is a way to manage the X-Openstack-Request-Id header on a per-request basis. This commit adds a global_request_id kwarg to keystoneauth1.session.Session.request, which is the funnel point for all requests coming through Adapter as well as Session itself. (All the methods feeding into that one already accept and pass through arbitrary **kwargs.) If present, the value in the X-Openstack-Request-Id header is set accordingly. Note that this will *override* Adapter.global_request_id, which is exactly what we want, as described above. [1] http://specs.openstack.org/openstack/oslo-specs/specs/pike/global-req-id.html [2]bea9058f02/nova/scheduler/client/report.py (L200)
[3]bea9058f02/nova/scheduler/client/report.py (L243)
[4]bea9058f02/nova/utils.py (L1219-L1221)
[5]bf6651f149/openstack/proxy.py (L114)
Change-Id: Ied73320fcd813ae796e40cbdb30717900486b92c
This commit is contained in:
parent
92ec14c66b
commit
df57e0ec3b
@ -52,6 +52,10 @@ _LOG_CONTENT_TYPES = set(['application/json'])
|
|||||||
|
|
||||||
_MAX_RETRY_INTERVAL = 60.0
|
_MAX_RETRY_INTERVAL = 60.0
|
||||||
|
|
||||||
|
# NOTE(efried): This is defined in oslo_middleware.request_id.INBOUND_HEADER,
|
||||||
|
# but it didn't seem worth adding oslo_middleware to requirements just for that
|
||||||
|
_REQUEST_ID_HEADER = 'X-Openstack-Request-Id'
|
||||||
|
|
||||||
|
|
||||||
def _construct_session(session_obj=None):
|
def _construct_session(session_obj=None):
|
||||||
# NOTE(morganfainberg): if the logic in this function changes be sure to
|
# NOTE(morganfainberg): if the logic in this function changes be sure to
|
||||||
@ -579,7 +583,7 @@ class Session(object):
|
|||||||
allow=None, client_name=None, client_version=None,
|
allow=None, client_name=None, client_version=None,
|
||||||
microversion=None, microversion_service_type=None,
|
microversion=None, microversion_service_type=None,
|
||||||
status_code_retries=0, retriable_status_codes=None,
|
status_code_retries=0, retriable_status_codes=None,
|
||||||
rate_semaphore=None, **kwargs):
|
rate_semaphore=None, global_request_id=None, **kwargs):
|
||||||
"""Send an HTTP request with the specified characteristics.
|
"""Send an HTTP request with the specified characteristics.
|
||||||
|
|
||||||
Wrapper around `requests.Session.request` to handle tasks such as
|
Wrapper around `requests.Session.request` to handle tasks such as
|
||||||
@ -668,6 +672,7 @@ class Session(object):
|
|||||||
:param rate_semaphore: Semaphore to be used to control concurrency
|
:param rate_semaphore: Semaphore to be used to control concurrency
|
||||||
and rate limiting of requests. (optional,
|
and rate limiting of requests. (optional,
|
||||||
defaults to no concurrency or rate control)
|
defaults to no concurrency or rate control)
|
||||||
|
:param global_request_id: Value for the X-Openstack-Request-Id header.
|
||||||
:param kwargs: any other parameter that can be passed to
|
:param kwargs: any other parameter that can be passed to
|
||||||
:meth:`requests.Session.request` (such as `headers`).
|
:meth:`requests.Session.request` (such as `headers`).
|
||||||
Except:
|
Except:
|
||||||
@ -785,6 +790,12 @@ class Session(object):
|
|||||||
headers.setdefault('Content-Type', 'application/json')
|
headers.setdefault('Content-Type', 'application/json')
|
||||||
kwargs['data'] = self._json.encode(json)
|
kwargs['data'] = self._json.encode(json)
|
||||||
|
|
||||||
|
if global_request_id is not None:
|
||||||
|
# NOTE(efried): This does *not* setdefault. If a global_request_id
|
||||||
|
# kwarg was explicitly specified, it should override any value
|
||||||
|
# previously configured (e.g. in Adapter.global_request_id).
|
||||||
|
headers[_REQUEST_ID_HEADER] = global_request_id
|
||||||
|
|
||||||
for k, v in self.additional_headers.items():
|
for k, v in self.additional_headers.items():
|
||||||
headers.setdefault(k, v)
|
headers.setdefault(k, v)
|
||||||
|
|
||||||
|
@ -1296,10 +1296,13 @@ class AdapterTest(utils.TestCase):
|
|||||||
self.assertRequestHeaderEqual('User-Agent', self.USER_AGENT)
|
self.assertRequestHeaderEqual('User-Agent', self.USER_AGENT)
|
||||||
|
|
||||||
def test_setting_global_id_on_request(self):
|
def test_setting_global_id_on_request(self):
|
||||||
global_id = "req-%s" % uuid.uuid4()
|
global_id_adpt = "req-%s" % uuid.uuid4()
|
||||||
|
global_id_req = "req-%s" % uuid.uuid4()
|
||||||
response = uuid.uuid4().hex
|
response = uuid.uuid4().hex
|
||||||
self.stub_url('GET', text=response)
|
self.stub_url('GET', text=response)
|
||||||
adpt = adapter.Adapter(client_session.Session(),
|
|
||||||
|
def mk_adpt(**kwargs):
|
||||||
|
return adapter.Adapter(client_session.Session(),
|
||||||
auth=CalledAuthPlugin(),
|
auth=CalledAuthPlugin(),
|
||||||
service_type=self.SERVICE_TYPE,
|
service_type=self.SERVICE_TYPE,
|
||||||
service_name=self.SERVICE_NAME,
|
service_name=self.SERVICE_NAME,
|
||||||
@ -1308,7 +1311,10 @@ class AdapterTest(utils.TestCase):
|
|||||||
user_agent=self.USER_AGENT,
|
user_agent=self.USER_AGENT,
|
||||||
version=self.VERSION,
|
version=self.VERSION,
|
||||||
allow=self.ALLOW,
|
allow=self.ALLOW,
|
||||||
global_request_id=global_id)
|
**kwargs)
|
||||||
|
|
||||||
|
# No global_request_id
|
||||||
|
adpt = mk_adpt()
|
||||||
resp = adpt.get('/')
|
resp = adpt.get('/')
|
||||||
self.assertEqual(resp.text, response)
|
self.assertEqual(resp.text, response)
|
||||||
|
|
||||||
@ -1316,7 +1322,21 @@ class AdapterTest(utils.TestCase):
|
|||||||
self.assertEqual(self.ALLOW,
|
self.assertEqual(self.ALLOW,
|
||||||
adpt.auth.endpoint_arguments['allow'])
|
adpt.auth.endpoint_arguments['allow'])
|
||||||
self.assertTrue(adpt.auth.get_token_called)
|
self.assertTrue(adpt.auth.get_token_called)
|
||||||
self.assertRequestHeaderEqual('X-OpenStack-Request-ID', global_id)
|
self.assertRequestHeaderEqual('X-OpenStack-Request-ID', None)
|
||||||
|
|
||||||
|
# global_request_id only on the request
|
||||||
|
adpt.get('/', global_request_id=global_id_req)
|
||||||
|
self.assertRequestHeaderEqual('X-OpenStack-Request-ID', global_id_req)
|
||||||
|
|
||||||
|
# global_request_id only on the adapter
|
||||||
|
adpt = mk_adpt(global_request_id=global_id_adpt)
|
||||||
|
adpt.get('/')
|
||||||
|
self.assertRequestHeaderEqual('X-OpenStack-Request-ID', global_id_adpt)
|
||||||
|
|
||||||
|
# global_request_id on the adapter *and* the request (the request takes
|
||||||
|
# precedence)
|
||||||
|
adpt.get('/', global_request_id=global_id_req)
|
||||||
|
self.assertRequestHeaderEqual('X-OpenStack-Request-ID', global_id_req)
|
||||||
|
|
||||||
def test_setting_variables_on_get_endpoint(self):
|
def test_setting_variables_on_get_endpoint(self):
|
||||||
adpt = self._create_loaded_adapter()
|
adpt = self._create_loaded_adapter()
|
||||||
|
Loading…
Reference in New Issue
Block a user