]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Reading configuration for modifying entries during mirorring LDAP instances
authorFrank Brehm <frank.brehm@pixelpark.com>
Thu, 25 Jan 2024 15:51:38 +0000 (16:51 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Thu, 25 Jan 2024 15:51:38 +0000 (16:51 +0100)
etc/mirror-ldap.yaml
lib/pp_admintools/app/mirror_ldap.py
lib/pp_admintools/config/mirror_ldap.py

index 8661c07f8dfa2f0a2cc31c1ca34dacb5817d3ba4..2827d2ae69865416bdda2e5753277827ac4d49e6 100644 (file)
@@ -1,6 +1,7 @@
 ---
 
 mirror-ldap:
+
   keep-entries:
     dpx-dev:
       - 'cn=Replication monitor,o=isp'
@@ -17,4 +18,38 @@ mirror-ldap:
       - 'dnaHostname=stage-ds01-spk.spk.pixelpark.net,cn=Group GIDs,ou=Ranges,dc=spk,dc=pixelpark,dc=net'
       - 'dnaHostname=stage-ds02-spk.spk.pixelpark.net,cn=Group GIDs,ou=Ranges,dc=spk,dc=pixelpark,dc=net'
 
+  modify-entries:
+    dpx-dev:
+      'dc=dpx-int.de,ou=Domains,o=Pixelpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+      'dc=mail.pixelpark.net,ou=Domains,o=Pixelpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+      'dc=pixelpark.com,ou=Domains,o=Pixelpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+      'dc=pixelpark.de,ou=Domains,o=Pixelpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+      'dc=wildpark.de,ou=Domains,o=Wildpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+    dpx-dev-new:
+      'dc=dpx-int.de,ou=Domains,o=Pixelpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+      'dc=mail.pixelpark.net,ou=Domains,o=Pixelpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+      'dc=pixelpark.com,ou=Domains,o=Pixelpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+      'dc=pixelpark.de,ou=Domains,o=Pixelpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+      'dc=wildpark.de,ou=Domains,o=Wildpark,o=isp':
+        replace:
+          preferredMailHost: 'dev-imap01.pixelpark.com'
+
 # vim: filetype=yaml
index c76300f98c27d477aad8ecf0ba2fabef805d2a65..36714983a163dd8dc49400b576dc5cd72b3d5a01 100644 (file)
@@ -282,6 +282,8 @@ class MirrorLdapApplication(BaseLdapApplication):
         msg = _("The timeout on LDAP operations is {} seconds.").format(self.cfg.ldap_timeout)
         LOG.debug(msg)
 
+        self.exit(0)
+
         try:
             self.get_current_src_entries()
             self.get_current_tgt_entries()
index 539b075afbaa36d9240a0d08dfaa52542f38dc90..f07baa59356cfc1a5d24773e20b07f630b47e167 100644 (file)
@@ -18,6 +18,7 @@ from collections.abc import Mapping
 # Third party modules
 from fb_tools.common import is_sequence
 from fb_tools.multi_config import DEFAULT_ENCODING
+from fb_tools.xlate import format_list
 
 # Own modules
 from .ldap import LdapConfigError, LdapConfiguration
@@ -48,6 +49,11 @@ class MirrorLdapConfiguration(LdapConfiguration):
     pat_keep_entries_key = r'^\s*keep[_-]?entries\s*$'
     re_keep_entries_key = re.compile(pat_keep_entries_key, re.IGNORECASE)
 
+    pat_modify_entries_key = r'^\s*modify[_-]?entries\s*$'
+    re_modify_entries_key = re.compile(pat_modify_entries_key, re.IGNORECASE)
+
+    valid_modify_actions = ('add', 'replace', 'delete')
+
     # -------------------------------------------------------------------------
     def __init__(
         self, appname=None, verbose=0, version=__version__, base_dir=None,
@@ -57,6 +63,9 @@ class MirrorLdapConfiguration(LdapConfiguration):
         """Initialize the MirrorLdapConfiguration object."""
         self.entries_keep = {}
         self.transform = {}
+        self.entries_mofify = {}
+
+        self.action_list = format_list(self.valid_modify_actions, do_repr=True)
 
         add_stems = []
         if additional_stems:
@@ -107,12 +116,18 @@ class MirrorLdapConfiguration(LdapConfiguration):
 
         for sub_section_name in section.keys():
 
+            if self.verbose > 2:
+                LOG.debug(_('Evaluating sub section {sn!r} ...').format(sn=sub_section_name))
+
             sub_section = section[sub_section_name]
 
             if self.re_keep_entries_key.match(sub_section_name):
                 self._eval_entries_keep(section_name, sub_section_name, sub_section)
                 continue
 
+            if self.re_modify_entries_key.match(sub_section_name):
+                self._eval_entries_modify(section_name, sub_section_name, sub_section)
+
     # -------------------------------------------------------------------------
     def _eval_entries_keep(self, section_name, sub_section_name, sub_section):
 
@@ -120,7 +135,7 @@ class MirrorLdapConfiguration(LdapConfiguration):
         sub_section = section[sub_section_name]
         sn = str(section_name) + '/' + str(sub_section_name)
 
-        if self.verbose > 2:
+        if self.verbose > 1:
             LOG.debug(_('Evaluating configuration section {sn!r} ...').format(sn=sn))
 
         if self.verbose > 2:
@@ -144,6 +159,119 @@ class MirrorLdapConfiguration(LdapConfiguration):
                     self.entries_keep[inst_name].append(inst_entries)
         return
 
+    # -------------------------------------------------------------------------
+    def _eval_entries_modify(self, section_name, sub_section_name, sub_section):
+
+        section = self.cfg[section_name]
+        sub_section = section[sub_section_name]
+        sn = str(section_name) + '/' + str(sub_section_name)
+
+        if self.verbose > 1:
+            LOG.debug(_('Evaluating configuration section {sn!r} ...').format(sn=sn))
+
+        if self.verbose > 2:
+            LOG.debug('Section:\n' + pp(sub_section))
+
+        if not isinstance(sub_section, Mapping):
+            LOG.warning(_('Section {sn!r} is not a {what}.').format(
+                sn=sn, what='Mapping (dict)'))
+            return
+
+        for inst_name in sub_section.keys():
+            inst_section = sub_section[inst_name]
+            inst_section_name = sn + '/' + str(inst_name)
+
+            self._eval_modify_inst(inst_name, inst_section_name, inst_section)
+
+    # -------------------------------------------------------------------------
+    def _eval_modify_inst(self, inst_name, inst_section_name, inst_section):
+
+        if self.verbose > 1:
+            LOG.debug(_('Evaluating configuration section {sn!r} ...').format(sn=inst_section_name))
+
+        if not isinstance(inst_section, Mapping):
+            LOG.warning(_('Section {sn!r} is not a {what}.').format(
+                sn=inst_section_name, what='Mapping (dict)'))
+            return
+
+        for dn_pattern in inst_section.keys():
+
+            dn_section = inst_section[dn_pattern]
+            dn_section_name = inst_section_name + '/' + dn_pattern
+
+            self._eval_modify_dn_pattern(dn_section_name, dn_pattern, dn_section, inst_name)
+
+    # -------------------------------------------------------------------------
+    def _eval_modify_dn_pattern(self, dn_section_name, dn_pattern, dn_section, inst_name):
+
+        if self.verbose > 2:
+            LOG.debug(_('Evaluating configuration section {sn!r} ...').format(sn=dn_section_name))
+
+        if not isinstance(dn_section, Mapping):
+            LOG.warning(_('Section {sn!r} is not a {what}.').format(
+                sn=dn_section_name, what='Mapping (dict)'))
+            return
+
+        for action in dn_section.keys():
+
+            action_lc = action.lower()
+            if action_lc not in self.valid_modify_actions:
+                msg = _(
+                    'Invalid action {a!r} in section {sn!r} found. An action must be '
+                    'one of {lst}.').format(
+                        a=action, sn=dn_section_name, lst=self.action_list)
+                LOG.warning(msg)
+                return
+
+            action_section_name = dn_section_name + '/' + action
+            action_section = dn_section[action]
+
+            self._eval_mofify_action(
+                action_section_name, action_lc, action_section, inst_name, dn_pattern)
+
+    # -------------------------------------------------------------------------
+    def _eval_mofify_action(
+            self, action_section_name, action_lc, action_section, inst_name, dn_pattern):
+
+        if self.verbose > 2:
+            LOG.debug(_('Evaluating configuration section {sn!r} ...').format(sn=action_section_name))
+
+        if not isinstance(action_section, Mapping):
+            LOG.warning(_('Section {sn!r} is not a {what}.').format(
+                sn=action_section_name, what='Mapping (dict)'))
+            return
+
+        for entry in action_section.keys():
+            val = action_section[entry]
+            if val in (None, '', []):
+                if action_lc == 'delete':
+                    self._set_modify_action(inst_name, dn_pattern, action_lc, entry, None)
+                    continue
+                msg = _('Empty value for section {sn!r} found.').format(action_section_name)
+                continue
+            if is_sequence(val):
+                for value in val:
+                    self._set_modify_action(inst_name, dn_pattern, action_lc, entry, str(value))
+            else:
+                self._set_modify_action(inst_name, dn_pattern, action_lc, entry, str(val))
+
+    # -------------------------------------------------------------------------
+    def _set_modify_action(self, inst_name, dn_pattern, action_lc, entry, value):
+
+        if inst_name not in self.entries_mofify:
+            self.entries_mofify[inst_name] = {}
+        if dn_pattern not in self.entries_mofify[inst_name]:
+            self.entries_mofify[inst_name][dn_pattern] = {}
+        if action_lc not in self.entries_mofify[inst_name][dn_pattern]:
+            self.entries_mofify[inst_name][dn_pattern][action_lc] = {}
+        if entry not in self.entries_mofify[inst_name][dn_pattern][action_lc]:
+            self.entries_mofify[inst_name][dn_pattern][action_lc][entry] = None
+        if value is not None:
+            if self.entries_mofify[inst_name][dn_pattern][action_lc][entry] is None:
+                self.entries_mofify[inst_name][dn_pattern][action_lc][entry] = []
+            if value not in self.entries_mofify[inst_name][dn_pattern][action_lc][entry]:
+                self.entries_mofify[inst_name][dn_pattern][action_lc][entry].append(value)
+
 
 # =============================================================================
 if __name__ == '__main__':