Add support for global_request_id
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. Change-Id: I70964cdd79741703c0b9b911b3b2f27c248130f0
This commit is contained in:
@@ -14,7 +14,7 @@ jmespath==0.9.0
|
|||||||
jsonpatch==1.16
|
jsonpatch==1.16
|
||||||
jsonpointer==1.13
|
jsonpointer==1.13
|
||||||
jsonschema==2.6.0
|
jsonschema==2.6.0
|
||||||
keystoneauth1==3.14.0
|
keystoneauth1==3.15.0
|
||||||
linecache2==1.0.0
|
linecache2==1.0.0
|
||||||
mock==2.0.0
|
mock==2.0.0
|
||||||
mox3==0.20.0
|
mox3==0.20.0
|
||||||
|
@@ -33,6 +33,7 @@ from openstack.cloud import _object_store
|
|||||||
from openstack.cloud import meta
|
from openstack.cloud import meta
|
||||||
from openstack.cloud import _utils
|
from openstack.cloud import _utils
|
||||||
import openstack.config
|
import openstack.config
|
||||||
|
from openstack.config import cloud_region as cloud_region_mod
|
||||||
from openstack import proxy
|
from openstack import proxy
|
||||||
|
|
||||||
DEFAULT_SERVER_AGE = 5
|
DEFAULT_SERVER_AGE = 5
|
||||||
@@ -226,16 +227,16 @@ class _OpenStackCloudMixin(object):
|
|||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
params['auth'][key] = value
|
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
|
# Attach the discovery cache from the old session so we won't
|
||||||
# double discover.
|
# 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
|
# Override the cloud name so that logging/location work right
|
||||||
cloud_config._name = self.name
|
cloud_region._name = self.name
|
||||||
cloud_config.config['profile'] = self.name
|
cloud_region.config['profile'] = self.name
|
||||||
# Use self.__class__ so that we return whatever this if, like if it's
|
# Use self.__class__ so that we return whatever this if, like if it's
|
||||||
# a subclass in the case of shade wrapping sdk.
|
# 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):
|
def connect_as_project(self, project):
|
||||||
"""Make a new OpenStackCloud object with a new project.
|
"""Make a new OpenStackCloud object with a new project.
|
||||||
@@ -267,6 +268,53 @@ class _OpenStackCloudMixin(object):
|
|||||||
auth['project_name'] = project
|
auth['project_name'] = project
|
||||||
return self.connect_as(**auth)
|
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):
|
def _make_cache(self, cache_class, expiration_time, arguments):
|
||||||
return dogpile.cache.make_region(
|
return dogpile.cache.make_region(
|
||||||
function_key_generator=self._make_cache_key
|
function_key_generator=self._make_cache_key
|
||||||
|
@@ -272,6 +272,7 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta,
|
|||||||
rate_limit=None,
|
rate_limit=None,
|
||||||
oslo_conf=None,
|
oslo_conf=None,
|
||||||
service_types=None,
|
service_types=None,
|
||||||
|
global_request_id=None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""Create a connection to a cloud.
|
"""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).
|
other service types will be disabled (will error if used).
|
||||||
**Currently only supported in conjunction with the ``oslo_conf``
|
**Currently only supported in conjunction with the ``oslo_conf``
|
||||||
kwarg.**
|
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
|
:param kwargs: If a config is not provided, the rest of the parameters
|
||||||
provided are assumed to be arguments to be passed to the
|
provided are assumed to be arguments to be passed to the
|
||||||
CloudRegion constructor.
|
CloudRegion constructor.
|
||||||
@@ -363,6 +365,7 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta,
|
|||||||
self._session = None
|
self._session = None
|
||||||
self._proxies = {}
|
self._proxies = {}
|
||||||
self.__pool_executor = None
|
self.__pool_executor = None
|
||||||
|
self._global_request_id = global_request_id
|
||||||
self.use_direct_get = use_direct_get
|
self.use_direct_get = use_direct_get
|
||||||
self.strict_mode = strict
|
self.strict_mode = strict
|
||||||
# Call the _*CloudMixin constructors while we work on
|
# Call the _*CloudMixin constructors while we work on
|
||||||
@@ -479,6 +482,9 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta,
|
|||||||
if self.__pool_executor:
|
if self.__pool_executor:
|
||||||
self.__pool_executor.shutdown()
|
self.__pool_executor.shutdown()
|
||||||
|
|
||||||
|
def set_global_request_id(self, global_request_id):
|
||||||
|
self._global_request_id = global_request_id
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@@ -144,10 +144,17 @@ class Proxy(adapter.Adapter):
|
|||||||
|
|
||||||
def request(
|
def request(
|
||||||
self, url, method, error_message=None,
|
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(
|
response = super(Proxy, self).request(
|
||||||
url, method,
|
url, method,
|
||||||
connect_retries=connect_retries, raise_exc=False,
|
connect_retries=connect_retries, raise_exc=False,
|
||||||
|
global_request_id=global_request_id,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
for h in response.history:
|
for h in response.history:
|
||||||
self._report_stats(h)
|
self._report_stats(h)
|
||||||
|
@@ -106,6 +106,44 @@ class TestShade(base.TestCase):
|
|||||||
r = self.cloud.get_image('doesNotExist')
|
r = self.cloud.get_image('doesNotExist')
|
||||||
self.assertIsNone(r)
|
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):
|
def test_get_server(self):
|
||||||
server1 = fakes.make_fake_server('123', 'mickey')
|
server1 = fakes.make_fake_server('123', 'mickey')
|
||||||
server2 = fakes.make_fake_server('345', 'mouse')
|
server2 = fakes.make_fake_server('345', 'mouse')
|
||||||
|
11
releasenotes/notes/global-request-id-d7c0736f43929165.yaml
Normal file
11
releasenotes/notes/global-request-id-d7c0736f43929165.yaml
Normal 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.
|
@@ -8,7 +8,7 @@ requestsexceptions>=1.2.0 # Apache-2.0
|
|||||||
jsonpatch!=1.20,>=1.16 # BSD
|
jsonpatch!=1.20,>=1.16 # BSD
|
||||||
six>=1.10.0 # MIT
|
six>=1.10.0 # MIT
|
||||||
os-service-types>=1.7.0 # Apache-2.0
|
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
|
munch>=2.1.0 # MIT
|
||||||
decorator>=3.4.0 # BSD
|
decorator>=3.4.0 # BSD
|
||||||
|
Reference in New Issue
Block a user