diff --git a/keystoneauth1/identity/base.py b/keystoneauth1/identity/base.py index 416ba876..36c62f52 100644 --- a/keystoneauth1/identity/base.py +++ b/keystoneauth1/identity/base.py @@ -11,6 +11,7 @@ # under the License. import abc +import threading import six @@ -38,6 +39,7 @@ class BaseIdentityPlugin(plugin.BaseAuthPlugin): self.reauthenticate = reauthenticate self._endpoint_cache = {} + self._lock = threading.Lock() @abc.abstractmethod def get_auth_ref(self, session, **kwargs): @@ -119,8 +121,14 @@ class BaseIdentityPlugin(plugin.BaseAuthPlugin): :returns: Valid AccessInfo :rtype: :py:class:`keystonauth.access.AccessInfo` """ - if self._needs_reauthenticate(): - self.auth_ref = self.get_auth_ref(session) + # Hey Kids! Thread safety is important particularly in the case where + # a service is creating an admin style plugin that will then proceed + # to make calls from many threads. As a token expires all the threads + # will try and fetch a new token at once, so we want to ensure that + # only one thread tries to actually fetch from keystone at once. + with self._lock: + if self._needs_reauthenticate(): + self.auth_ref = self.get_auth_ref(session) return self.auth_ref