Identity plugin thread safety

A common case is for Nova (or other service) to create an admin
authentication from a CONF file and then have many greenlet threads that
want to reuse that authentication. If a token expires then many threads
all try and fetch a new token to use and can step over each other.

I was hoping for a way to put a lock in so that all plugins were thread
safe however fixing it for identity plugins solves almost all real world
situations and anyone doing non-identity plugins will have to manage
threads themselves.

Closes-Bug: #1493835
Change-Id: Ie478499a086a4b0db4fb9e5b820f6f5cd4074763
This commit is contained in:
Jamie Lennox 2015-09-09 10:03:52 +10:00
parent 88a69ea9da
commit c8d7506ce6
1 changed files with 10 additions and 2 deletions

View File

@ -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