]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Rewriting method add_entry() to retry on a connection error.
authorFrank Brehm <frank.brehm@pixelpark.com>
Wed, 31 Jan 2024 13:12:24 +0000 (14:12 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Wed, 31 Jan 2024 13:12:24 +0000 (14:12 +0100)
lib/pp_admintools/app/ldap.py

index 9b9cd8b11efd881ccbb459d9afcd055075c4f52b..62c3b326d0269799b26fd2a9a284a92cd314d2fc 100644 (file)
@@ -54,13 +54,14 @@ from ..config.ldap import LdapConfiguration, LdapConnectionInfo
 from ..errors import DpxDeleteLdapItemError
 from ..errors import DpxFatalLdapError
 from ..errors import DpxLdapError
+from ..errors import DpxLdapExecError
 from ..errors import DpxLdapParseError
 from ..errors import DpxLdapSearchError
 from ..errors import DpxLdapSessionError
 from ..errors import DpxWriteLdapItemError
 from ..xlate import XLATOR, format_list
 
-__version__ = '1.3.2'
+__version__ = '1.3.3'
 LOG = logging.getLogger(__name__)
 
 _ = XLATOR.gettext
@@ -989,7 +990,9 @@ class BaseLdapApplication(BaseDPXApplication):
                 msg = _('Got a {cls} on searching in LDAP instance {i!r}:').format(
                     cls=e_cls, i=inst) + ' ' + str(e)
                 raise DpxLdapSearchError(msg)
-            LOG.debug(_('Waiting because of a {}:').format(e_cls) + ' ' + e_msg)
+            LOG.warn(_(
+                'Waiting #{nr} on searching in instance {i!r} because of a '
+                '{cls}:').format(nr=cur_try, i=inst, cls=e_cls) + ' ' + e_msg)
             time.sleep(wait_on_error)
             return None
 
@@ -1443,10 +1446,17 @@ class BaseLdapApplication(BaseDPXApplication):
         return attribs
 
     # -------------------------------------------------------------------------
-    def add_entry(self, inst, dn, object_classes, target_entry, ldap=None):
+    def add_entry(
+            self, inst, dn, object_classes, target_entry, ldap=None,
+            retries=None, wait_on_error=None):
         """Create a LDAP entry."""
         connect_info = self.cfg.ldap_connection[inst]
-        keep_ldap = False
+
+        if retries is None:
+            retries = self.retries_on_conn_error
+
+        if wait_on_error is None:
+            wait_on_error = self.wait_on_conn_error
 
         if self.verbose > 2:
             msg = _('Creating entry {dn!r} on {uri}:').format(
@@ -1458,6 +1468,57 @@ class BaseLdapApplication(BaseDPXApplication):
             LOG.info(_('Simulation mode - entry will not be created.'))
             return True
 
+        cur_try = 0
+        req_status = None
+        req_result = None
+        req_response = None
+        result = None
+
+        while True:
+
+            cur_try += 1
+            result = self._add_entry(
+                inst, dn=dn, object_classes=object_classes, attributes=target_entry,
+                cur_try=cur_try, retries=retries, wait_on_error=wait_on_error, ldap=ldap)
+
+            if result is not None:
+                break
+
+        req_status = result[0]
+        req_result = result[1]
+        req_response = result[2]
+
+        if self.verbose > 1:
+            LOG.debug(_('Creation status: {!r}.').format(req_status))
+        if self.verbose > 2:
+            LOG.debug(_('Result of creating:') + '\n' + pp(req_result))
+
+        if not req_status:
+            msg = _('Creation of entry {dn!r} was NOT successful: {desc} - {msg}').format(
+                dn=dn, desc=req_result['description'], msg=req_result['message'].strip())
+            if self.verbose > 3:
+                msg += '\nResponse: ' + pp(req_response)
+            msg += '\nobjectClasses:\n' + pp(object_classes)
+            msg += '\nAttributes:\n' + pp(target_entry)
+            raise DpxWriteLdapItemError(msg)
+
+        LOG.debug(_('Creation successful.'))
+        return True
+
+    # -------------------------------------------------------------------------
+    def _add_entry(
+            self, inst, dn, object_classes, attributes, cur_try, retries, wait_on_error, ldap):
+        """Execute the underlaying adding of an entry."""
+        keep_ldap = False
+        e_cls = None
+        e_msg = None
+        req_status = None
+        req_result = None
+        req_response = None
+
+        if self.verbose > 2:
+            LOG.debug(_('Try number {} for adding entry ...').format(cur_try))
+
         if ldap:
             keep_ldap = True
         else:
@@ -1467,17 +1528,38 @@ class BaseLdapApplication(BaseDPXApplication):
 
         try:
             req_status, req_result, req_response, req_whatever = ldap.add(
-                dn, object_class=object_classes, attributes=target_entry)
+                dn, object_class=object_classes, attributes=attributes)
+
+        except LDAPCommunicationError as e:
+            e_msg = str(e)
+            e_cls = e.__class__.__name__
+            if cur_try > retries:
+                msg = _('Got a {cls} on adding LDAP entry {dn!r} to instance {i!r}:').format(
+                    cls=e_cls, dn=dn, i=inst) + ' ' + e_msg
+                raise DpxLdapExecError(msg)
+            msg = _(
+                'Waiting #{nr} on inserting LDAP entry {dn!r} to instance {i!r} '
+                'because of a {cls}:').format(nr=cur_try, dn=dn, i=inst, cls=e_cls)
+            msg += ' ' + e_msg
+            LOG.warn(msg)
+            time.sleep(wait_on_error)
+            return None
+
         except LDAPException as e:
-            msg = _('Creation of entry {dn!r} was NOT successfull - {c}: {e}').format(
-                dn=dn, c=e.__class__.__name__, e=e)
+            e_msg = str(e)
+            e_cls = e.__class__.__name__
+            msg = _(
+                'Creation of entry {dn!r} in instance {i!r} was NOT successfull'
+                ' - {c}: {e}').format(dn=dn, i=inst, c=e_cls, e=e_msg)
             msg += '\nobjectClasses:\n' + pp(object_classes)
-            msg += '\nAttributes:\n' + pp(target_entry)
+            msg += '\nAttributes:\n' + pp(attributes)
             raise DpxWriteLdapItemError(msg)
         finally:
             if not self.single_session or not keep_ldap:
                 self.disconnect_instance(inst)
 
+        return (req_status, req_result, req_response)
+
         # Example result on a not successful modification:
         # {     'description': 'objectClassViolation',
         #       'dn': '',
@@ -1486,21 +1568,6 @@ class BaseLdapApplication(BaseDPXApplication):
         #       'result': 65,
         #       'type': 'modifyResponse'}
 
-        if self.verbose > 1:
-            LOG.debug(_('Creation status: {!r}.').format(req_status))
-        if self.verbose > 2:
-            LOG.debug(_('Result of creating:') + '\n' + pp(req_result))
-
-        if not req_status:
-            msg = _('Creation of entry {dn!r} was NOT successful: {desc} - {msg}').format(
-                dn=dn, desc=req_result['description'], msg=req_result['message'].strip())
-            msg += '\nobjectClasses:\n' + pp(object_classes)
-            msg += '\nAttributes:\n' + pp(target_entry)
-            raise DpxWriteLdapItemError(msg)
-
-        LOG.debug(_('Creation successful.'))
-        return True
-
     # -------------------------------------------------------------------------
     def modify_entry(self, inst, dn, changes, ldap=None):
         """Mofify an existing LDAP entry."""