NSXv3: More locking for certificate provider

Under stress connections are failing due to race condition. Fix this
by locking the entire certificate file creation/deletion block.

Change-Id: I8be1c9570e0b73660e997193eddb46705c71c6b6
This commit is contained in:
Anna Khmelnitsky 2017-05-29 11:56:52 -07:00 committed by Adit Sarfaty
parent cec4c0e438
commit d97bd534b6

View File

@ -55,18 +55,6 @@ class DbCertProvider(client_cert.ClientCertProvider):
random.seed()
self.refcount = 0
def _increase_and_test_first(self):
with self.lock:
self.refcount += 1
return (self.refcount == 1)
def _decrease_and_test_last(self):
with self.lock:
self.refcount -= 1
return (self.refcount == 0)
def _check_expiration(self, expires_in_days):
if expires_in_days > self.EXPIRATION_ALERT_DAYS:
return
@ -80,15 +68,21 @@ class DbCertProvider(client_cert.ClientCertProvider):
expires_in_days)
def __enter__(self):
if not self._increase_and_test_first():
with self.lock:
self.refcount += 1
if self.refcount > 1:
# The file was already created and not yet deleted, use it
return self
# Choose a random filename to contain cert for the current connection
# No certificate file available - need to create one
# Choose a random filename to contain the certificate
self._filename = '/tmp/.' + str(random.randint(1, 10000000))
try:
context = q_context.get_admin_context()
db_storage_driver = cert_utils.DbCertificateStorageDriver(context)
db_storage_driver = cert_utils.DbCertificateStorageDriver(
context)
with client_cert.ClientCertificateManager(
cert_utils.NSX_OPENSTACK_IDENTITY,
None,
@ -105,6 +99,7 @@ class DbCertProvider(client_cert.ClientCertProvider):
expires_in_days = cert_manager.expires_in_days()
self._check_expiration(expires_in_days)
except Exception as e:
# refcount has to be 1 here
self._on_exit()
raise e
@ -112,8 +107,10 @@ class DbCertProvider(client_cert.ClientCertProvider):
return self
def _on_exit(self):
self.refcount -= 1
if self.refcount == 0:
# I am the last user of this file
if self._decrease_and_test_last():
if os.path.isfile(self._filename):
os.remove(self._filename)
LOG.debug("Deleted client certificate file")
@ -121,6 +118,7 @@ class DbCertProvider(client_cert.ClientCertProvider):
self._filename = None
def __exit__(self, type, value, traceback):
with self.lock:
self._on_exit()
def filename(self):