]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Adding much debug stuff.
authorFrank Brehm <frank.brehm@pixelpark.com>
Thu, 25 Jan 2024 10:55:18 +0000 (11:55 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Thu, 25 Jan 2024 10:55:18 +0000 (11:55 +0100)
lib/pp_admintools/app/ldap.py
lib/pp_admintools/app/mirror_ldap.py

index 01ea148a2ebf4f39bf4f5979aeb1a1b1a28e2c34..328dd681ce09c96998401c53ee8264c84b4ebff8 100644 (file)
@@ -13,6 +13,7 @@ import argparse
 import logging
 import os
 import re
+import time
 try:
     from pathlib import Path
 except ImportError:
@@ -36,6 +37,8 @@ from ldap3 import Connection, DSA, IP_V4_PREFERRED, SAFE_SYNC, Server
 from ldap3 import MODIFY_ADD, MODIFY_DELETE, MODIFY_REPLACE
 from ldap3.core.exceptions import LDAPBindError
 from ldap3.core.exceptions import LDAPException
+from ldap3.core.exceptions import LDAPSocketOpenError
+from ldap3.core.exceptions import LDAPSocketReceiveError
 
 # Own modules
 from . import BaseDPXApplication, DPXAppError
@@ -67,6 +70,12 @@ class FatalLDAPError(LdapAppError):
     pass
 
 
+# =============================================================================
+class LdapReadError(LdapAppError):
+    """Exception during reading data from a LDAP instance."""
+    pass
+
+
 # =============================================================================
 class LDAPExecutionError(FatalLDAPError):
     """Error class in case, a LDAP operation was not successful."""
@@ -170,6 +179,7 @@ class BaseLdapApplication(BaseDPXApplication):
     show_cmdline_ldap_timeout = True
     apply_default_ldap_instance_if_not_given = True
     default_default_ldap_instance = 'default'
+    default_wait_on_read_error = 1
 
     # pattern_re_ldap_dn = (
     # '^([a-z][a-z0-9-]*)=(?![ #])(((?![\\="+,;<>]).)|(\\[ \\#="+,;<>])|(\\[a-f0-9][a-f0-9]))*'
@@ -256,12 +266,13 @@ class BaseLdapApplication(BaseDPXApplication):
         self, appname=None, verbose=0, version=GLOBAL_VERSION, base_dir=None,
             cfg_class=LdapConfiguration, initialized=False, usage=None, description=None,
             argparse_epilog=None, argparse_prefix_chars='-', env_prefix=None,
-            config_dir=DEFAULT_CONFIG_DIR):
+            config_dir=DEFAULT_CONFIG_DIR, wait_on_read_error=None):
         """Contrict the application object."""
         self._password_file = None
         self.ldap_instances = []
         self.ldap_server = {}
         self.ldap_connection = {}
+        self._wait_on_read_error = self.default_wait_on_read_error
 
         super(BaseLdapApplication, self).__init__(
             appname=appname, verbose=verbose, version=version, base_dir=base_dir,
@@ -270,6 +281,9 @@ class BaseLdapApplication(BaseDPXApplication):
             env_prefix=env_prefix, config_dir=config_dir
         )
 
+        if wait_on_read_error:
+            self.wait_on_read_error = wait_on_read_error
+
     # -----------------------------------------------------------
     @property
     def password_file(self):
@@ -298,6 +312,21 @@ class BaseLdapApplication(BaseDPXApplication):
 
         self._password_file = path
 
+    # -----------------------------------------------------------
+    @property
+    def wait_on_read_error(self):
+        """The time in seconds to wait after a unseccessful read for the next try."""
+        return self._wait_on_read_error
+
+    @wait_on_read_error.setter
+    def wait_on_read_error(self, value):
+        val = float(value)
+        if self._wait_on_read_error <= 0:
+            msg = _("The value {v} for {n} must be greater than zero.").format(
+                v=val, n='wait_on_read_error')
+            raise ValueError(msg)
+        self._wait_on_read_error = val
+
     # -------------------------------------------------------------------------
     def as_dict(self, short=True):
         """
@@ -317,6 +346,7 @@ class BaseLdapApplication(BaseDPXApplication):
         res['show_cmdline_ldap_timeout'] = self.show_cmdline_ldap_timeout
         res['use_default_ldap_connection'] = self.use_default_ldap_connection
         res['use_multiple_ldap_connections'] = self.use_multiple_ldap_connections
+        res['wait_on_read_error'] = self.wait_on_read_error
 
         return res
 
@@ -1252,7 +1282,7 @@ class BaseLdapApplication(BaseDPXApplication):
         return [found_dn]
 
     # -------------------------------------------------------------------------
-    def get_entry(self, dn, inst, attributes=None, operational_attributes=False):
+    def get_entry(self, dn, inst, attributes=None, operational_attributes=False, tries=3):
         """Get an complete LDAP entry by the given DN in the given instance."""
         connect_info = self.cfg.ldap_connection[inst]
         ldap = self.ldap_connection[inst]
@@ -1268,10 +1298,27 @@ class BaseLdapApplication(BaseDPXApplication):
             msg = _('Searching DN {dn!r} in {uri}.').format(dn=dn, uri=connect_info.url)
             LOG.debug(msg)
 
-        req_status, req_result, req_response, req_whatever = ldap.search(
-            search_base=dn, search_scope=BASE, attributes=attributes,
-            get_operational_attributes=operational_attributes, search_filter=sfilter,
-            time_limit=self.cfg.ldap_timeout)
+        cur_try = 0
+        e_msg = None
+        while cur_try < tries:
+            e_msg = None
+            cur_try += 1
+            try:
+                req_status, req_result, req_response, req_whatever = ldap.search(
+                    search_base=dn, search_scope=BASE, attributes=attributes,
+                    get_operational_attributes=operational_attributes, search_filter=sfilter,
+                    time_limit=self.cfg.ldap_timeout)
+            except (LDAPSocketReceiveError, LDAPSocketOpenError) as e:
+                e_msg = str(e)
+                if cur_try >= tries:
+                    break
+                LOG.debug(_("Waiting because of a failing read operation."))
+                time.sleep(self.wait_on_read_error)
+
+        if e_msg:
+            msg = _("Error on reading entry {dn!r} from instance {inst!r}:").format(
+                dn=dn, inst=inst) + ' ' + e_msg
+            raise LdapReadError(msg)
 
         if req_status:
             if self.verbose > 4:
index dbd400842ecc33c9631ab358c5c6466747d22891..cd0d074f4b8cbfd81c6fe495812dcce7b05323f1 100644 (file)
@@ -23,18 +23,20 @@ from fb_tools.xlate import format_list
 
 # from ldap3 import MODIFY_REPLACE, MODIFY_ADD, MODIFY_DELETE
 from ldap3 import ALL_ATTRIBUTES
+from ldap3.core.exceptions import LDAPSocketReceiveError
 
 # Own modules
 # from .ldap import LdapAppError, FatalLDAPError
 from .ldap import BaseLdapApplication
 from .ldap import LdapAppError
+from .ldap import LdapReadError
 from .. import pp
 from ..argparse_actions import LimitedFloatOptionAction
 from ..argparse_actions import NonNegativeIntegerOptionAction
 from ..config.mirror_ldap import MirrorLdapConfiguration
 from ..xlate import XLATOR
 
-__version__ = '0.9.2'
+__version__ = '1.0.0'
 LOG = logging.getLogger(__name__)
 
 _ = XLATOR.gettext
@@ -165,7 +167,7 @@ class MirrorLdapApplication(BaseLdapApplication):
                 self.arg_parser.print_usage(sys.stdout)
                 self.exit(1)
 
-        self.wait = getattr(self.args, 'wait', self.default_wait_after_write)
+        self.wait_after_write = getattr(self.args, 'wait', self.default_wait_after_write)
 
         self._check_source_instance()
         self._eval_keep_dns()
@@ -255,6 +257,20 @@ class MirrorLdapApplication(BaseLdapApplication):
         self.empty_line()
         self.line(linechar='=', color='CYAN')
         LOG.info("I'm walking, yes indeed I'm walking ...")
+        self.empty_line()
+        if self.wait_after_write and not self.simulate:
+            msg = ngettext(
+                "Waiting one second after write actions.",
+                "Waiting {} seconds after write actions.",
+                self.wait_after_write).format(self.wait_after_write)
+        elif self.simulate:
+            msg = _("Don't waiting after simulated write actions.")
+        else:
+            msg = _("Don't waiting after write actions, because {} was set to zero.").format(
+                'wait_after_write')
+        LOG.info(msg)
+        msg = _("The timeout on LDAP operations is {} seconds.").format(self.cfg.ldap_timeout)
+        LOG.debug(msg)
 
         try:
             self.get_current_src_entries()
@@ -302,6 +318,11 @@ class MirrorLdapApplication(BaseLdapApplication):
 
                 self.empty_line()
 
+        except LdapReadError as e:
+            msg = _('Got a {}:').format('LdapReadError') + ' ' + str(e)
+            LOG.error(msg)
+            self.exit(11)
+
         except KeyboardInterrupt:
             msg = _('Got a {}:').format('KeyboardInterrupt') + ' ' + _('Interrupted on demand.')
             LOG.error(msg)
@@ -616,7 +637,12 @@ class MirrorLdapApplication(BaseLdapApplication):
             if self.verbose > 1:
                 LOG.debug(_('Mirroring entry {!r} ...').format(dn))
 
-            src_entry = self.get_entry(dn, self.src_instance, attributes)
+            try:
+                src_entry = self.get_entry(dn, self.src_instance, attributes)
+            except LDAPSocketReceiveError as e:
+                msg = _("Error on reading entry {!r} from source:").format(dn) + ' ' + str(e)
+                raise LdapReadError(msg)
+
             if not src_entry:
                 msg = _('Did not found {!r} in the source LDAP.').format(dn)
                 LOG.warn(msg)
@@ -630,7 +656,11 @@ class MirrorLdapApplication(BaseLdapApplication):
             if self.verbose > 2:
                 LOG.debug('Got source entry:\n' + pp(src_attribs_dict))
 
-            tgt_entry = self.get_entry(dn, self.tgt_instance, attributes)
+            try:
+                tgt_entry = self.get_entry(dn, self.tgt_instance, attributes, tries=1)
+            except LDAPSocketReceiveError as e:
+                msg = _("Error on reading entry {!r} from target:").format(dn) + ' ' + str(e)
+                raise LdapReadError(msg)
             if tgt_entry:
                 tgt_attribs = self.normalized_attributes(
                     tgt_entry, omit_members=True, omit_memberof=True)
@@ -720,7 +750,11 @@ class MirrorLdapApplication(BaseLdapApplication):
             if self.verbose > 1:
                 LOG.debug(_('Mirroring entry {!r} ...').format(dn))
 
-            src_entry = self.get_entry(dn, self.src_instance, attributes)
+            try:
+                src_entry = self.get_entry(dn, self.src_instance, attributes)
+            except LDAPSocketReceiveError as e:
+                msg = _("Error on reading entry {!r} from source:").format(dn) + ' ' + str(e)
+                raise LdapReadError(msg)
             if not src_entry:
                 msg = _('Did not found {!r} in the source LDAP.').format(dn)
                 LOG.warn(msg)
@@ -734,7 +768,11 @@ class MirrorLdapApplication(BaseLdapApplication):
             if self.verbose > 2:
                 LOG.debug('Got source entry:\n' + pp(src_attribs_dict))
 
-            tgt_entry = self.get_entry(dn, self.tgt_instance, attributes)
+            try:
+                tgt_entry = self.get_entry(dn, self.tgt_instance, attributes, tries=1)
+            except LDAPSocketReceiveError as e:
+                msg = _("Error on reading entry {!r} from target:").format(dn) + ' ' + str(e)
+                raise LdapReadError(msg)
             if tgt_entry:
                 tgt_attribs = self.normalized_attributes(
                     tgt_entry, omit_members=True, omit_memberof=True)
@@ -821,7 +859,11 @@ class MirrorLdapApplication(BaseLdapApplication):
             if self.verbose > 1:
                 LOG.debug(_('Mirroring entry {!r} ...').format(dn))
 
-            src_entry = self.get_entry(dn, self.src_instance, attributes)
+            try:
+                src_entry = self.get_entry(dn, self.src_instance, attributes)
+            except LDAPSocketReceiveError as e:
+                msg = _("Error on reading entry {!r} from source:").format(dn) + ' ' + str(e)
+                raise LdapReadError(msg)
             if not src_entry:
                 msg = _('Did not found {!r} in the source LDAP.').format(dn)
                 LOG.warn(msg)
@@ -831,7 +873,11 @@ class MirrorLdapApplication(BaseLdapApplication):
             if self.verbose > 2:
                 LOG.debug('Got source entry:\n' + pp(src_attribs_dict))
 
-            tgt_entry = self.get_entry(dn, self.tgt_instance, attributes)
+            try:
+                tgt_entry = self.get_entry(dn, self.tgt_instance, attributes, tries=1)
+            except LDAPSocketReceiveError as e:
+                msg = _("Error on reading entry {!r} from target:").format(dn) + ' ' + str(e)
+                raise LdapReadError(msg)
             if not tgt_entry:
                 LOG.warn(_('Target entry {!r} not found.').format(dn))
                 continue