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

index 62c3b326d0269799b26fd2a9a284a92cd314d2fc..969df930d647094916fedc2f524cab3bfcd10dce 100644 (file)
@@ -61,7 +61,7 @@ from ..errors import DpxLdapSessionError
 from ..errors import DpxWriteLdapItemError
 from ..xlate import XLATOR, format_list
 
-__version__ = '1.3.3'
+__version__ = '1.3.4'
 LOG = logging.getLogger(__name__)
 
 _ = XLATOR.gettext
@@ -1554,6 +1554,7 @@ class BaseLdapApplication(BaseDPXApplication):
             msg += '\nobjectClasses:\n' + pp(object_classes)
             msg += '\nAttributes:\n' + pp(attributes)
             raise DpxWriteLdapItemError(msg)
+
         finally:
             if not self.single_session or not keep_ldap:
                 self.disconnect_instance(inst)
@@ -1569,10 +1570,15 @@ class BaseLdapApplication(BaseDPXApplication):
         #       'type': 'modifyResponse'}
 
     # -------------------------------------------------------------------------
-    def modify_entry(self, inst, dn, changes, ldap=None):
+    def modify_entry(self, inst, dn, changes, ldap=None, retries=None, wait_on_error=None):
         """Mofify an existing 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 > 1:
             msg = _('Applying changes on {uri} to DN {dn!r}:').format(
@@ -1583,6 +1589,55 @@ class BaseLdapApplication(BaseDPXApplication):
             LOG.info(_('Simulation mode - changes are not applied.'))
             return True
 
+        cur_try = 0
+        req_status = None
+        req_result = None
+        req_response = None
+        result = None
+
+        while True:
+
+            cur_try += 1
+            result = self._modify_entry(
+                inst, dn=dn, changes=changes, 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(_('Modification status: {!r}.').format(req_status))
+        if self.verbose > 2:
+            LOG.debug(_('Result of modifying:') + '\n' + pp(req_result))
+
+        if not req_status:
+            msg = _('Modification of {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 += '\n' + _('Changes:') + '\n' + pp(changes)
+            raise DpxWriteLdapItemError(msg)
+
+        LOG.debug(_('Modification successful.'))
+        return True
+
+    # -------------------------------------------------------------------------
+    def _modify_entry(self, inst, dn, changes, cur_try, retries, wait_on_error, ldap=None):
+        """Execute the underlaying modifying an antry."""
+        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 modifying an entry ...').format(cur_try))
+
         if ldap:
             keep_ldap = True
         else:
@@ -1592,15 +1647,37 @@ class BaseLdapApplication(BaseDPXApplication):
 
         try:
             req_status, req_result, req_response, req_whatever = ldap.modify(dn, changes)
+
+        except LDAPCommunicationError as e:
+            e_msg = str(e)
+            e_cls = e.__class__.__name__
+            if cur_try > retries:
+                msg = _('Got a {cls} on modifying LDAP entry {dn!r} on instance {i!r}:').format(
+                    cls=e_cls, dn=dn, i=inst) + ' ' + e_msg
+                raise DpxLdapExecError(msg)
+            msg = _(
+                'Waiting #{nr} on modifying LDAP entry {dn!r} on 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 = _('Modification of {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 = _(
+                'Modification of entry {dn!r} on instance {i!r} was NOT successfull'
+                ' - {c}: {e}').format(dn=dn, i=inst, c=e_cls, e=e_msg)
             msg += '\n' + _('Changes:') + '\n' + pp(changes)
             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': '',
@@ -1609,20 +1686,6 @@ class BaseLdapApplication(BaseDPXApplication):
         #       'result': 65,
         #       'type': 'modifyResponse'}
 
-        if self.verbose > 1:
-            LOG.debug(_('Modification status: {!r}.').format(req_status))
-        if self.verbose > 2:
-            LOG.debug(_('Result of modifying:') + '\n' + pp(req_result))
-
-        if not req_status:
-            msg = _('Modification of {dn!r} was NOT successful: {desc} - {msg}').format(
-                dn=dn, desc=req_result['description'], msg=req_result['message'].strip())
-            msg += '\n' + _('Changes:') + '\n' + pp(changes)
-            raise DpxWriteLdapItemError(msg)
-
-        LOG.debug(_('Modification successful.'))
-        return True
-
     # -------------------------------------------------------------------------
     def delete_entry(self, inst, dn, ldap=None):
         """Delete a LDAP entry."""