]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Rewriting method delete_entry() to retry on a connection error.
authorFrank Brehm <frank.brehm@pixelpark.com>
Thu, 1 Feb 2024 11:00:56 +0000 (12:00 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Thu, 1 Feb 2024 11:00:56 +0000 (12:00 +0100)
lib/pp_admintools/app/ldap.py

index 969df930d647094916fedc2f524cab3bfcd10dce..23c8c9389e373bf55a4488b7efcb77a641afec54 100644 (file)
@@ -61,7 +61,7 @@ from ..errors import DpxLdapSessionError
 from ..errors import DpxWriteLdapItemError
 from ..xlate import XLATOR, format_list
 
-__version__ = '1.3.4'
+__version__ = '1.3.5'
 LOG = logging.getLogger(__name__)
 
 _ = XLATOR.gettext
@@ -1687,10 +1687,15 @@ class BaseLdapApplication(BaseDPXApplication):
         #       'type': 'modifyResponse'}
 
     # -------------------------------------------------------------------------
-    def delete_entry(self, inst, dn, ldap=None):
+    def delete_entry(self, inst, dn, ldap=None, retries=None, wait_on_error=None):
         """Delete 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
 
         msg = _('Deleting LDAP entry {dn!r} on {uri} ...').format(
             uri=connect_info.url, dn=dn)
@@ -1700,22 +1705,25 @@ class BaseLdapApplication(BaseDPXApplication):
             LOG.info(_('Simulation mode - deletion will not be executed.'))
             return True
 
-        if ldap:
-            keep_ldap = True
-        else:
-            if inst not in self.ldap_connection:
-                self.connect_instance(inst)
-            ldap = self.ldap_connection[inst]
+        cur_try = 0
+        req_status = None
+        req_result = None
+        req_response = None
+        result = None
 
-        try:
-            req_status, req_result, req_response, req_whatever = ldap.delete(dn)
-        except LDAPException as e:
-            msg = _('Deletion of {dn!r} was NOT successfull - {c}: {e}').format(
-                c=e.__class__.__name__, e=e)
-            raise DpxDeleteLdapItemError(msg)
-        finally:
-            if not self.single_session or not keep_ldap:
-                self.disconnect_instance(inst)
+        while True:
+
+            cur_try += 1
+            result = self._delete_entry(
+                inst, dn=dn, 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(_('Deletion status: {!r}.').format(req_status))
@@ -1725,12 +1733,66 @@ class BaseLdapApplication(BaseDPXApplication):
         if not req_status:
             msg = _('Deletion of {dn!r} was NOT successful: {desc} - {msg}').format(
                 dn=dn, desc=req_result['description'], msg=req_result['message'].strip())
+            if self.verbose > 4:
+                msg += '\nResponse: ' + pp(req_response)
             raise DpxDeleteLdapItemError(msg)
 
         LOG.debug(_('Deletion successful.'))
 
         return True
 
+    # -------------------------------------------------------------------------
+    def _delete_entry(self, inst, dn, 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 {i} for deleting entry {dn!r} ...').format(i=cur_try, dn=dn))
+
+        if ldap:
+            keep_ldap = True
+        else:
+            if inst not in self.ldap_connection:
+                self.connect_instance(inst)
+            ldap = self.ldap_connection[inst]
+
+        try:
+            req_status, req_result, req_response, req_whatever = ldap.delete(dn)
+
+        except LDAPCommunicationError as e:
+            e_msg = str(e)
+            e_cls = e.__class__.__name__
+            if cur_try > retries:
+                msg = _('Got a {cls} on deleting 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 deleting 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:
+            e_msg = str(e)
+            e_cls = e.__class__.__name__
+            msg = _(
+                'Deleting of entry {dn!r} on instance {i!r} was NOT successfull'
+                ' - {c}: {e}').format(dn=dn, i=inst, c=e_cls, e=e_msg)
+            raise DpxWriteLdapItemError(msg)
+
+        finally:
+            if not self.single_session or not keep_ldap:
+                self.disconnect_instance(inst)
+
+        return (req_status, req_result, req_response)
+
     # -------------------------------------------------------------------------
     def get_group_memberships(self, inst, dn, base_dn=None):
         """Return a list with DNs of all groups containing the given DN as a member."""