]> Frank Brehm's Git Trees - pixelpark/ldap-migration.git/commitdiff
Collecting a list of all entries
authorFrank Brehm <frank.brehm@pixelpark.com>
Fri, 13 Nov 2020 13:05:48 +0000 (14:05 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Fri, 13 Nov 2020 13:05:48 +0000 (14:05 +0100)
lib/ldap_migration/__init__.py
migrate-ldap

index b24da97957811e16311f3dd26573668b5a876d87..a7906147bf2cbf3b93c04f6b3b33e7b3670ec2f4 100644 (file)
@@ -14,10 +14,14 @@ import copy
 import sys
 import os
 import time
+import re
 
 # 3rd party modules
 
 from ldap3 import Server, Connection, ALL, DSA, IP_V4_PREFERRED, SAFE_SYNC
+from ldap3 import BASE, LEVEL, SUBTREE, DEREF_NEVER, DEREF_SEARCH, DEREF_BASE, DEREF_ALWAYS
+from ldap3 import ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES
+
 from ldap3.core.exceptions import LDAPException
 
 # Own modules
@@ -30,7 +34,7 @@ from fb_tools.errors import FbAppError
 
 from .config import LDAPMigrationConfiguration
 
-__version__ = '0.4.0'
+__version__ = '0.5.0'
 
 LOG = logging.getLogger(__name__)
 CFG_BASENAME = 'ldap-migration.ini'
@@ -53,6 +57,9 @@ class LDAPMigrationApplication(BaseApplication):
     Class for the application objects.
     """
 
+    re_dn_split = re.compile(r'\s*,\s*')
+    re_token_split = re.compile(r'^\s*([a-z0-9]+)\s*=\s*(\S(?:.*\S)?)\s*$', re.IGNORECASE)
+
     # -------------------------------------------------------------------------
     def __init__(
             self, appname=None, verbose=0, version=__version__, base_dir=None):
@@ -69,6 +76,8 @@ class LDAPMigrationApplication(BaseApplication):
         self.source = None
         self.tgt_server = None
         self.target = None
+        self.tmp_dir = None
+        self.all_dns_file = None
 
         self.object_classes = {}
         self.attribute_types = {}
@@ -78,6 +87,8 @@ class LDAPMigrationApplication(BaseApplication):
             description=description, initialized=False,
         )
 
+        self.tmp_dir = self.base_dir / 'tmp'
+        self.all_dns_file = self.tmp_dir / 'all-dns.txt'
         self.initialized = True
 
     # -------------------------------------------------------------------------
@@ -482,6 +493,110 @@ class LDAPMigrationApplication(BaseApplication):
                     tmp_dict[name_lc] = self.attribute_types[name_lc]['single_name']
                 LOG.debug("Discovered AttributeTypes:\n" + pp(tmp_dict))
 
+    # -------------------------------------------------------------------------
+    def check_tmp_dir(self):
+        """Checking existence of temp-dir and creating it, if necessary."""
+
+        LOG.debug("Checking temporary directory {!r} ...".format(str(self.tmp_dir)))
+
+        if self.tmp_dir.exists():
+            if self.tmp_dir.is_dir():
+                LOG.debug("Temporary directory {!r} is already existing.".format(
+                    str(self.tmp_dir)))
+            else:
+                msg = "Path {!r} is already existing, but is not a directory.".format(
+                    str(self.tmp_dir))
+                raise CommonLDAPMigrationError(msg)
+        else:
+            LOG.info("Creating temporary directory {!r} ...".format(str(self.tmp_dir)))
+            self.tmp_dir.mkdir(mode=0o755, exist_ok=True)
+
+        mod2check =  os.R_OK | os.W_OK | os.X_OK
+        euid = False
+        if os.access in os.supports_effective_ids:
+            euid = True
+        if not os.access(str(self.tmp_dir), mod2check, effective_ids=euid):
+            msg = "Insufficient access rights to temporary directory {!r}.".format(
+                str(self.tmp_dir))
+            raise CommonLDAPMigrationError(msg)
+
+        if self.verbose > 1:
+            LOG.debug("Access to {!r} is okay.".format(str(self.tmp_dir)))
+
+    # -------------------------------------------------------------------------
+    def lookup_for_attrtype(self, attrtype, silent=True):
+
+        at_lc = attrtype.lower()
+        if at_lc not in self.attribute_types:
+            msg = "AttributeType {!r} not found.".format(attrtype)
+            if silent:
+                if self.verbose > 2:
+                    LOG.debug(msg)
+            else:
+                LOG.error(msg)
+            return None
+
+        new_at = self.attribute_types[at_lc]['single_name']
+        return new_at
+
+    # -------------------------------------------------------------------------
+    def mangle_dn_token(self, old_token):
+
+        match = self.re_token_split.search(old_token)
+        if not match:
+            return old_token
+
+        key = match.group(1)
+        new_key = self.lookup_for_attrtype(key, silent=False)
+        if not new_key:
+            msg = "F***, Whats that?"
+            raise CommonLDAPMigrationError(msg)
+        value = match.group(2)
+
+        return "{key}={val}".format(key=new_key, val=value)
+
+    # -------------------------------------------------------------------------
+    def mangle_dn(self, old_dn):
+
+        parts = self.re_dn_split.split(old_dn)
+        new_parts = []
+        for old_token in parts:
+            new_token = self.mangle_dn_token(old_token)
+            new_parts.append(new_token)
+
+        return ','.join(parts)
+
+    # -------------------------------------------------------------------------
+    def get_all_dns(self):
+
+        LOG.info("Collecting all source SNs and writing them into {!r} ...".format(
+            str(self.all_dns_file)))
+
+        open_args = {
+            'encoding': 'utf-8',
+            'errors': 'surrogateescape',
+            'mode': 'w',
+        }
+        sfilter = '(objectClass=*)'
+
+        item_count = 0
+
+        with self.all_dns_file.open(**open_args) as fh:
+
+            status, result, response, _ = self.source.search(
+                search_base=self.config.suffix, search_scope=SUBTREE, search_filter=sfilter,
+                attributes=['objectClass'], time_limit=self.config.timeout)
+            for entry in response:
+                item_count += 1
+                old_dn = entry['dn']
+                new_dn = self.mangle_dn(old_dn)
+                if self.verbose > 2:
+                    LOG.debug("Found DN {!r}.".format(old_dn))
+                fh.write("{old} => {new}\n".format(old=old_dn, new=new_dn))
+
+        LOG.info("Found {nr} items in subtree of {sfx!r}.".format(
+            nr=item_count, sfx=self.config.suffix))
+
     # -------------------------------------------------------------------------
     def _run(self):
 
@@ -492,6 +607,8 @@ class LDAPMigrationApplication(BaseApplication):
             self.connect_source()
             self.connect_target()
             self.discover_target_schema()
+            self.check_tmp_dir()
+            self.get_all_dns()
             LOG.info("Sleeping ...")
             time.sleep(2)
         finally:
index 92684c9cb962f62201cfa4d2a6bfe805422c14d6..d67bd6752b164298ff101dcd10af74dd48413543 100755 (executable)
@@ -48,7 +48,7 @@ locale.setlocale(locale.LC_ALL, '')
 app = LDAPMigrationApplication(appname=appname, base_dir=base_dir)
 app.initialized = True
 
-if app.verbose > 2:
+if app.verbose > 1:
     print("{c}-Object:\n{a}".format(c=app.__class__.__name__, a=app))
 
 app()