summaryrefslogtreecommitdiffstats
path: root/ipaserver/install/certs.py
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2015-01-08 09:06:46 +0000
committerJan Cholasta <jcholast@redhat.com>2015-01-13 18:34:59 +0000
commitb9ae7690489368ead9f4983d386fa210dc265dfa (patch)
tree25437961e983a3a239541f9482e69ff70941c32c /ipaserver/install/certs.py
parent6a1304324fe94b17e8dc4a418f90bea028160ace (diff)
downloadfreeipa-b9ae7690489368ead9f4983d386fa210dc265dfa.tar.gz
freeipa-b9ae7690489368ead9f4983d386fa210dc265dfa.tar.xz
freeipa-b9ae7690489368ead9f4983d386fa210dc265dfa.zip
Make certificate renewal process synchronized
Synchronization is achieved using a global renewal lock. https://fedorahosted.org/freeipa/ticket/4803 Reviewed-By: David Kupka <dkupka@redhat.com>
Diffstat (limited to 'ipaserver/install/certs.py')
-rw-r--r--ipaserver/install/certs.py104
1 files changed, 104 insertions, 0 deletions
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
index 7292cbbe3..bc7dccf80 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -26,6 +26,10 @@ import xml.dom.minidom
import pwd
import base64
from hashlib import sha1
+import fcntl
+import time
+import datetime
+import ConfigParser as configparser
from ipapython.ipa_log_manager import root_logger
from ipapython import dogtag
@@ -647,3 +651,103 @@ class CertDB(object):
def export_pem_cert(self, nickname, location):
return self.nssdb.export_pem_cert(nickname, location)
+
+
+class _CrossProcessLock(object):
+ _DATETIME_FORMAT = '%Y%m%d%H%M%S%f'
+
+ def __init__(self, filename):
+ self._filename = filename
+
+ def __enter__(self):
+ self.acquire()
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.release()
+
+ def acquire(self, owner=None):
+ self._do(self._acquire, owner)
+
+ def release(self, owner=None):
+ self._do(self._release, owner)
+
+ def _acquire(self, owner):
+ now = datetime.datetime.utcnow()
+
+ if self._locked and now >= self._expire:
+ self._locked = False
+
+ if self._locked:
+ return False
+
+ self._locked = True
+ self._owner = owner
+ self._expire = now + datetime.timedelta(hours=1)
+
+ return True
+
+ def _release(self, owner):
+ if not self._locked or self._owner != owner:
+ raise RuntimeError("lock not acquired by %s" % owner)
+
+ self._locked = False
+ self._owner = None
+ self._expire = None
+
+ return True
+
+ def _do(self, func, owner):
+ if owner is None:
+ owner = '%s[%s]' % (os.path.basename(sys.argv[0]), os.getpid())
+
+ while True:
+ with open(self._filename, 'a+') as f:
+ fcntl.flock(f, fcntl.LOCK_EX)
+
+ f.seek(0)
+ self._read(f)
+
+ if func(owner):
+ f.seek(0)
+ f.truncate()
+ self._write(f)
+ return
+
+ time.sleep(10)
+
+ def _read(self, fileobj):
+ p = configparser.RawConfigParser()
+ p.readfp(fileobj)
+
+ try:
+ self._locked = p.getboolean('lock', 'locked')
+
+ if self._locked:
+ self._owner = p.get('lock', 'owner')
+
+ expire = p.get('lock', 'expire')
+ try:
+ self._expire = datetime.datetime.strptime(
+ expire, self._DATETIME_FORMAT)
+ except ValueError:
+ raise configparser.Error
+ except configparser.Error:
+ self._locked = False
+ self._owner = None
+ self._expire = None
+
+ def _write(self, fileobj):
+ p = configparser.RawConfigParser()
+ p.add_section('lock')
+
+ locked = '1' if self._locked else '0'
+ p.set('lock', 'locked', locked)
+
+ if self._locked:
+ expire = self._expire.strftime(self._DATETIME_FORMAT)
+ p.set('lock', 'owner', self._owner)
+ p.set('lock', 'expire', expire)
+
+ p.write(fileobj)
+
+renewal_lock = _CrossProcessLock(paths.IPA_RENEWAL_LOCK)