|
|
95ea96 |
From b17a85bded822c4078a9b817720652807a939bc8 Mon Sep 17 00:00:00 2001
|
|
|
2737e7 |
From: Christian Heimes <cheimes@redhat.com>
|
|
|
2737e7 |
Date: Fri, 22 Jun 2018 09:39:26 +0200
|
|
|
2737e7 |
Subject: [PATCH] Improve and fix timeout bug in wait_for_entry()
|
|
|
2737e7 |
|
|
|
2737e7 |
replication.wait_for_entry() now can wait for an attribute value to
|
|
|
2737e7 |
appear on a replica.
|
|
|
2737e7 |
|
|
|
2737e7 |
Fixed timeout handling caused by bad rounding and comparison. For small
|
|
|
2737e7 |
timeouts, the actual time was rounded down. For example for 60 seconds
|
|
|
2737e7 |
timeout and fast replica, the query accumulated to about 0.45 seconds
|
|
|
2737e7 |
plus 60 seconds sleep. 60.45 is large enough to terminate the loop
|
|
|
2737e7 |
"while int(time.time()) < timeout", but not large enough to trigger the
|
|
|
2737e7 |
exception in "if int(time.time()) > timeout", because int(60.65) == 60.
|
|
|
2737e7 |
|
|
|
2737e7 |
See: https://pagure.io/freeipa/issue/7593
|
|
|
2737e7 |
Fixes: https://pagure.io/freeipa/issue/7595
|
|
|
2737e7 |
Signed-off-by: Christian Heimes <cheimes@redhat.com>
|
|
|
2737e7 |
Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
|
|
|
2737e7 |
---
|
|
|
95ea96 |
ipaserver/install/replication.py | 54 +++++++++++++++++++++-------------------
|
|
|
95ea96 |
1 file changed, 29 insertions(+), 25 deletions(-)
|
|
|
2737e7 |
|
|
|
2737e7 |
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
|
|
|
95ea96 |
index 2e7ce53fef89093a7f661d846aa138ee330961e6..6d9878e16faab1b88a5ab79649571de6802c8536 100644
|
|
|
2737e7 |
--- a/ipaserver/install/replication.py
|
|
|
2737e7 |
+++ b/ipaserver/install/replication.py
|
|
|
95ea96 |
@@ -20,6 +20,7 @@
|
|
|
95ea96 |
from __future__ import print_function, absolute_import
|
|
|
2737e7 |
|
|
|
95ea96 |
import logging
|
|
|
2737e7 |
+import itertools
|
|
|
2737e7 |
|
|
|
2737e7 |
import six
|
|
|
2737e7 |
import time
|
|
|
95ea96 |
@@ -160,40 +161,43 @@ def wait_for_task(conn, dn):
|
|
|
2737e7 |
return exit_code
|
|
|
2737e7 |
|
|
|
2737e7 |
|
|
|
2737e7 |
-def wait_for_entry(connection, dn, timeout=7200, attr='', quiet=True):
|
|
|
2737e7 |
- """Wait for entry and/or attr to show up"""
|
|
|
2737e7 |
-
|
|
|
2737e7 |
- filter = "(objectclass=*)"
|
|
|
2737e7 |
+def wait_for_entry(connection, dn, timeout=7200, attr=None, attrvalue='*',
|
|
|
2737e7 |
+ quiet=True):
|
|
|
2737e7 |
+ """Wait for entry and/or attr to show up
|
|
|
2737e7 |
+ """
|
|
|
95ea96 |
+ log = logger.debug if quiet else logger.info
|
|
|
2737e7 |
attrlist = []
|
|
|
2737e7 |
- if attr:
|
|
|
2737e7 |
- filter = "(%s=*)" % attr
|
|
|
2737e7 |
+ if attr is not None:
|
|
|
2737e7 |
+ filterstr = ipaldap.LDAPClient.make_filter_from_attr(attr, attrvalue)
|
|
|
2737e7 |
attrlist.append(attr)
|
|
|
2737e7 |
- timeout += int(time.time())
|
|
|
2737e7 |
-
|
|
|
2737e7 |
- if not quiet:
|
|
|
2737e7 |
- sys.stdout.write("Waiting for %s %s:%s " % (connection, dn, attr))
|
|
|
2737e7 |
- sys.stdout.flush()
|
|
|
2737e7 |
- entry = None
|
|
|
2737e7 |
- while not entry and int(time.time()) < timeout:
|
|
|
2737e7 |
+ else:
|
|
|
2737e7 |
+ filterstr = "(objectclass=*)"
|
|
|
2737e7 |
+ log("Waiting for replication (%s) %s %s", connection, dn, filterstr)
|
|
|
2737e7 |
+ entry = []
|
|
|
2737e7 |
+ deadline = time.time() + timeout
|
|
|
2737e7 |
+ for i in itertools.count(start=1):
|
|
|
2737e7 |
try:
|
|
|
2737e7 |
- [entry] = connection.get_entries(
|
|
|
2737e7 |
- dn, ldap.SCOPE_BASE, filter, attrlist)
|
|
|
2737e7 |
+ entry = connection.get_entries(
|
|
|
2737e7 |
+ dn, ldap.SCOPE_BASE, filterstr, attrlist)
|
|
|
2737e7 |
except errors.NotFound:
|
|
|
2737e7 |
pass # no entry yet
|
|
|
2737e7 |
except Exception as e: # badness
|
|
|
95ea96 |
logger.error("Error reading entry %s: %s", dn, e)
|
|
|
2737e7 |
raise
|
|
|
2737e7 |
- if not entry:
|
|
|
2737e7 |
- if not quiet:
|
|
|
2737e7 |
- sys.stdout.write(".")
|
|
|
2737e7 |
- sys.stdout.flush()
|
|
|
2737e7 |
- time.sleep(1)
|
|
|
2737e7 |
|
|
|
2737e7 |
- if not entry and int(time.time()) > timeout:
|
|
|
2737e7 |
- raise errors.NotFound(
|
|
|
2737e7 |
- reason="wait_for_entry timeout for %s for %s" % (connection, dn))
|
|
|
2737e7 |
- elif entry and not quiet:
|
|
|
95ea96 |
- logger.error("The waited for entry is: %s", entry)
|
|
|
2737e7 |
+ if entry:
|
|
|
2737e7 |
+ log("Entry found %r", entry)
|
|
|
2737e7 |
+ return
|
|
|
2737e7 |
+ elif time.time() > deadline:
|
|
|
2737e7 |
+ raise errors.NotFound(
|
|
|
2737e7 |
+ reason="wait_for_entry timeout on {} for {}".format(
|
|
|
2737e7 |
+ connection, dn
|
|
|
2737e7 |
+ )
|
|
|
2737e7 |
+ )
|
|
|
2737e7 |
+ else:
|
|
|
2737e7 |
+ if i % 10 == 0:
|
|
|
95ea96 |
+ logger.debug("Still waiting for replication of %s", dn)
|
|
|
2737e7 |
+ time.sleep(1)
|
|
|
2737e7 |
|
|
|
2737e7 |
|
|
|
2737e7 |
class ReplicationManager(object):
|
|
|
2737e7 |
--
|
|
|
95ea96 |
2.14.4
|
|
|
2737e7 |
|