Merge "Add support for global_request_id"

This commit is contained in:
Zuul 2019-08-13 18:35:21 +00:00 committed by Gerrit Code Review
commit d41a972d4b
7 changed files with 118 additions and 8 deletions

View File

@ -14,7 +14,7 @@ jmespath==0.9.0
jsonpatch==1.16
jsonpointer==1.13
jsonschema==2.6.0
keystoneauth1==3.14.0
keystoneauth1==3.15.0
linecache2==1.0.0
mock==2.0.0
mox3==0.20.0

View File

@ -33,6 +33,7 @@ from openstack.cloud import _object_store
from openstack.cloud import meta
from openstack.cloud import _utils
import openstack.config
from openstack.config import cloud_region as cloud_region_mod
from openstack import proxy
DEFAULT_SERVER_AGE = 5
@ -226,16 +227,16 @@ class _OpenStackCloudMixin(object):
for key, value in kwargs.items():
params['auth'][key] = value
cloud_config = config.get_one(**params)
cloud_region = config.get_one(**params)
# Attach the discovery cache from the old session so we won't
# double discover.
cloud_config._discovery_cache = self.session._discovery_cache
cloud_region._discovery_cache = self.session._discovery_cache
# Override the cloud name so that logging/location work right
cloud_config._name = self.name
cloud_config.config['profile'] = self.name
cloud_region._name = self.name
cloud_region.config['profile'] = self.name
# Use self.__class__ so that we return whatever this if, like if it's
# a subclass in the case of shade wrapping sdk.
return self.__class__(config=cloud_config)
return self.__class__(config=cloud_region)
def connect_as_project(self, project):
"""Make a new OpenStackCloud object with a new project.
@ -267,6 +268,53 @@ class _OpenStackCloudMixin(object):
auth['project_name'] = project
return self.connect_as(**auth)
def global_request(self, global_request_id):
"""Make a new Connection object with a global request id set.
Take the existing settings from the current Connection and construct a
new Connection object with the global_request_id overridden.
.. code-block:: python
from oslo_context import context
cloud = openstack.connect(cloud='example')
# Work normally
servers = cloud.list_servers()
cloud2 = cloud.global_request(context.generate_request_id())
# cloud2 sends all requests with global_request_id set
servers = cloud2.list_servers()
Additionally, this can be used as a context manager:
.. code-block:: python
from oslo_context import context
c = openstack.connect(cloud='example')
# Work normally
servers = c.list_servers()
with c.global_request(context.generate_request_id()) as c2:
# c2 sends all requests with global_request_id set
servers = c2.list_servers()
:param global_request_id: The `global_request_id` to send.
"""
params = copy.deepcopy(self.config.config)
cloud_region = cloud_region_mod.from_session(
session=self.session,
app_name=self.config._app_name,
app_version=self.config._app_version,
discovery_cache=self.session._discovery_cache,
**params)
# Override the cloud name so that logging/location work right
cloud_region._name = self.name
cloud_region.config['profile'] = self.name
# Use self.__class__ so that we return whatever this is, like if it's
# a subclass in the case of shade wrapping sdk.
new_conn = self.__class__(config=cloud_region)
new_conn.set_global_request_id(global_request_id)
return new_conn
def _make_cache(self, cache_class, expiration_time, arguments):
return dogpile.cache.make_region(
function_key_generator=self._make_cache_key

View File

@ -272,6 +272,7 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta,
rate_limit=None,
oslo_conf=None,
service_types=None,
global_request_id=None,
**kwargs):
"""Create a connection to a cloud.
@ -328,6 +329,7 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta,
other service types will be disabled (will error if used).
**Currently only supported in conjunction with the ``oslo_conf``
kwarg.**
:param global_request_id: A Request-id to send with all interactions.
:param kwargs: If a config is not provided, the rest of the parameters
provided are assumed to be arguments to be passed to the
CloudRegion constructor.
@ -363,6 +365,7 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta,
self._session = None
self._proxies = {}
self.__pool_executor = None
self._global_request_id = global_request_id
self.use_direct_get = use_direct_get
self.strict_mode = strict
# Call the _*CloudMixin constructors while we work on
@ -479,6 +482,9 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta,
if self.__pool_executor:
self.__pool_executor.shutdown()
def set_global_request_id(self, global_request_id):
self._global_request_id = global_request_id
def __enter__(self):
return self

View File

@ -144,10 +144,17 @@ class Proxy(adapter.Adapter):
def request(
self, url, method, error_message=None,
raise_exc=False, connect_retries=1, *args, **kwargs):
raise_exc=False, connect_retries=1,
global_request_id=None, *args, **kwargs):
if not global_request_id:
conn = self._get_connection()
if conn:
# Per-request setting should take precedence
global_request_id = conn._global_request_id
response = super(Proxy, self).request(
url, method,
connect_retries=connect_retries, raise_exc=False,
global_request_id=global_request_id,
**kwargs)
for h in response.history:
self._report_stats(h)

View File

@ -106,6 +106,44 @@ class TestShade(base.TestCase):
r = self.cloud.get_image('doesNotExist')
self.assertIsNone(r)
def test_global_request_id(self):
request_id = uuid.uuid4().hex
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(
method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
json={'servers': []},
validate=dict(
headers={'X-Openstack-Request-Id': request_id}),
),
])
cloud2 = self.cloud.global_request(request_id)
self.assertEqual([], cloud2.list_servers())
self.assert_calls()
def test_global_request_id_context(self):
request_id = uuid.uuid4().hex
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(
method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
json={'servers': []},
validate=dict(
headers={'X-Openstack-Request-Id': request_id}),
),
])
with self.cloud.global_request(request_id) as c2:
self.assertEqual([], c2.list_servers())
self.assert_calls()
def test_get_server(self):
server1 = fakes.make_fake_server('123', 'mickey')
server2 = fakes.make_fake_server('345', 'mouse')

View File

@ -0,0 +1,11 @@
---
features:
- |
Added support for setting ``global_request_id`` on a ``Connection``.
If done, this will cause all requests sent to send the request id
header to the OpenStack services. Since ``Connection`` can otherwise
be used multi-threaded, add a method ``global_request`` that returns
a new ``Connection`` based on the old ``Connection`` but on which
the new ``global_request_id`` has been set. Since a ``Connection``
can be used as a context manager, this also means the ``global_request``
method can be used in ``with`` statements.

View File

@ -8,7 +8,7 @@ requestsexceptions>=1.2.0 # Apache-2.0
jsonpatch!=1.20,>=1.16 # BSD
six>=1.10.0 # MIT
os-service-types>=1.7.0 # Apache-2.0
keystoneauth1>=3.14.0 # Apache-2.0
keystoneauth1>=3.15.0 # Apache-2.0
munch>=2.1.0 # MIT
decorator>=3.4.0 # BSD