From 09b890d7186d0a48e30eed76c4485263f9ce7ca5 Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Mon, 9 Jan 2023 16:41:22 +0100 Subject: [PATCH] Allowing export of errors int a yaml file. --- .../app/check_ldap_dn_attributes.py | 63 +++++++++++++------ 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/lib/pp_admintools/app/check_ldap_dn_attributes.py b/lib/pp_admintools/app/check_ldap_dn_attributes.py index 2cfe0d0..11c36c0 100644 --- a/lib/pp_admintools/app/check_ldap_dn_attributes.py +++ b/lib/pp_admintools/app/check_ldap_dn_attributes.py @@ -9,13 +9,11 @@ from __future__ import absolute_import # Standard modules -import sys +import re import logging -import copy -import time # Third party modules -from ldap3 import ALL_ATTRIBUTES +import yaml # Own modules # from fb_tools.common import to_bool, is_sequence @@ -33,10 +31,7 @@ from ..config.ldap import LdapConfiguration from .ldap import LdapAppError from .ldap import BaseLdapApplication -from ..argparse_actions import NonNegativeItegerOptionAction -from ..argparse_actions import LimitedFloatOptionAction - -__version__ = '0.2.2' +__version__ = '0.3.1' LOG = logging.getLogger(__name__) _ = XLATOR.gettext @@ -63,6 +58,8 @@ class CheckLdapDnAttributesApplication(BaseLdapApplication): show_force_option = False show_assume_options = False + re_yaml_extension = re.compile(r'\.ya?ml$', re.IGNORECASE) + check_attributes = ['member', 'uniqueMember', 'owner', 'seeAlso'] # ------------------------------------------------------------------------- @@ -78,6 +75,8 @@ class CheckLdapDnAttributesApplication(BaseLdapApplication): self.all_check_dns = CIStringSet() self.failed_entries = CIDict() + self.export_file = None + attr_list = format_list(self.check_attributes, do_repr=True) desc = _( @@ -86,8 +85,8 @@ class CheckLdapDnAttributesApplication(BaseLdapApplication): "to existing entries in LDAP.").format(alist=attr_list) super(CheckLdapDnAttributesApplication, self).__init__( - appname=appname, description=desc, base_dir=base_dir, - cfg_class=LdapConfiguration, initialized=False) + appname=appname, description=desc, base_dir=base_dir, + cfg_class=LdapConfiguration, initialized=False) self.initialized = True @@ -96,12 +95,31 @@ class CheckLdapDnAttributesApplication(BaseLdapApplication): super(CheckLdapDnAttributesApplication, self)._verify_instances(is_admin=True) + # ------------------------------------------------------------------------- + def init_arg_parser(self): + + app_group = self.arg_parser.add_argument_group(_("Script options")) + + app_group.add_argument( + '-E', '--export', dest='export', metavar=_('FILE'), + help=_( + "Exportig the faulty entries and attributes into a YAML file, " + "if there were found some of them."), + ) + + super(CheckLdapDnAttributesApplication, self).init_arg_parser() + # ------------------------------------------------------------------------- def post_init(self): """Execute some actions after initialising.""" super(CheckLdapDnAttributesApplication, self).post_init() + self.export_file = getattr(self.args, 'export', None) + if self.export_file: + if not self.re_yaml_extension.search(self.export_file): + self.export_file += '.yaml' + self.instance = self.ldap_instances[0] self.connect_info = self.cfg.ldap_connection[self.instance] @@ -110,6 +128,11 @@ class CheckLdapDnAttributesApplication(BaseLdapApplication): ldap_url = self.cfg.ldap_connection[self.instance].url + if self.export_file: + with open(self.export_file, 'wt', encoding='utf-8', errors='surrogateescape') as fh: + fh.write('---\n\n') + LOG.debug(_("Created export file {!r}.").format(self.export_file)) + msg = _( "Start checking all DN-like attributes in in LDAP instance {inst!r} " "({url}) ...").format(inst=self.instance, url=ldap_url) @@ -147,6 +170,7 @@ class CheckLdapDnAttributesApplication(BaseLdapApplication): self.check_entry(dn) if self.failed_entries: + print(pp(self.failed_entries.as_dict(pure=True))) nr = len(self.failed_entries) nr_attr = 0 for e_dn in self.failed_entries: @@ -160,7 +184,13 @@ class CheckLdapDnAttributesApplication(BaseLdapApplication): "There is one inconsistent attribute.", "There are {} inconsistent attributes.", nr_attr).format(nr_attr) LOG.warn(msg) - print(pp(self.failed_entries.as_dict(pure=True))) + if self.export_file: + LOG.debug(_("Writing export file {!r} ...").format(self.export_file)) + with open( + self.export_file, 'wt', encoding='utf-8', errors='surrogateescape') as fh: + yaml.dump( + self.failed_entries.as_dict(pure=True), fh, explicit_start=True, + default_flow_style=False, indent=2) self.exit(5) msg = _("Did not found any inconsistent entries.") @@ -186,20 +216,14 @@ class CheckLdapDnAttributesApplication(BaseLdapApplication): self.failed_entries[dn] = {} if attrib not in self.failed_entries[dn]: self.failed_entries[dn][attrib] = [] - self.failed_entries[dn][attrib].append({ - 'value': ref, - 'what': 'syntax', - }) + self.failed_entries[dn][attrib].append(ref) continue if not self.check_ref_existence(ref, self.instance): if dn not in self.failed_entries: self.failed_entries[dn] = {} if attrib not in self.failed_entries[dn]: self.failed_entries[dn][attrib] = [] - self.failed_entries[dn][attrib].append({ - 'value': ref, - 'what': 'existence', - }) + self.failed_entries[dn][attrib].append(ref) # ------------------------------------------------------------------------- def check_ref_syntax(self, dn): @@ -225,6 +249,7 @@ class CheckLdapDnAttributesApplication(BaseLdapApplication): self.checked_ref_dn[dn] = False return False + # ============================================================================= if __name__ == "__main__": -- 2.39.5