]> Frank Brehm's Git Trees - pixelpark/ldap-migration.git/commitdiff
Zwischenstand Gruppenmigration
authorFrank Brehm <frank.brehm@pixelpark.com>
Fri, 8 Jan 2021 14:06:25 +0000 (15:06 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Fri, 8 Jan 2021 14:06:25 +0000 (15:06 +0100)
lib/ldap_migration/__init__.py

index 67c0fdcb600c4618166c07314e0bf8d00eb57534..c5589f2651c9a84ce58f6b9f1a9fa26368b1bd69 100644 (file)
@@ -68,6 +68,12 @@ class ReadLDAPItemError(CommonLDAPMigrationError):
     pass
 
 
+# =============================================================================
+class GroupEntryNotMigratableError(CommonLDAPMigrationError):
+    """Exception, that happens, if a group entry could not migrated."""
+    pass
+
+
 # =============================================================================
 class FatalLDAPMigrationError(CommonLDAPMigrationError):
     """Fatal errors leading to interrupt the migration process."""
@@ -1447,7 +1453,7 @@ class LDAPMigrationApplication(BaseApplication):
                             msg += "on target LDAP server."
                             msg = msg.format(oc=src_oc_name, dn=src_dn)
                             LOG.debug(msg)
-                            self.unknown_objectclasses.add(src_oc_name)
+                        self.unknown_objectclasses.add(src_oc_name)
                         continue
                     tgt_oc_name = self.object_classes.real_key(src_oc_name)
                     used_classes.add(tgt_oc_name)
@@ -1910,8 +1916,192 @@ class LDAPMigrationApplication(BaseApplication):
         src_dn = self.group_entries[tgt_dn]['src_dn']
         object_classes = self.group_entries[tgt_dn]['object_classes']
 
-        msg = "Trying to migrate group entry {src!r} -> {tgt!r} ...".format(src=src_dn, tgt=tgt_dn)
-        LOG.debug(msg)
+        msg = "Migrating group entry {src!r} -> {tgt!r} ...".format(src=src_dn, tgt=tgt_dn)
+        LOG.info(msg)
+
+        src_entry = self.get_source_item(src_dn, tgt_dn, with_acl=False)
+        tgt_entry = self.get_target_item(tgt_dn, with_acl=False)
+
+        try:
+            if tgt_entry:
+                return self.migrate_existing_group_entry(src_dn, tgt_dn, src_entry, tgt_entry)
+            return self.migrate_new_group_entry(src_dn, tgt_dn, src_entry)
+        except GroupEntryNotMigratableError as e:
+            LOG.debug("Group entry {dn!r} could not migrated: {e}".format(dn=tgt_dn, e=e))
+            return False
+
+    # -------------------------------------------------------------------------
+    def migrate_new_group_entry(self, src_dn, tgt_dn, src_entry):
+
+        (tgt_obj_classes, tgt_entry) = self.generate_target_group_entry(src_entry, src_dn, tgt_dn)
+
+        if self.verbose:
+            LOG.info("Creating target entry {!r} ...".format(tgt_dn))
+        if self.verbose > 2:
+            msg = "Generated entry for target DN {dn!r}:\n"
+            msg += "object classes: {oc}\n"
+            msg += "entry: {en}"
+            msg = msg.format(dn=tgt_dn, oc=tgt_obj_classes, en=tgt_entry)
+            LOG.debug(msg)
+        self.count_added += 1
+        if not self.simulate:
+            try:
+                cr_status, cr_result, cr_response, _ = self.target.add(
+                    tgt_dn, object_class=tgt_obj_classes, attributes=tgt_entry)
+            except LDAPException as e:
+                msg = "Modifying NOT successfull - {c}: {e}\n"
+                msg += "Source attributes:\n{sattr}\n"
+                msg += "Target-DN: {dn!r}\n"
+                msg += "Target Object classes:\n{ocs}\n"
+                msg += "Target attributes:\n{tattr}"
+                msg = msg.format(
+                    c=e.__class__.__name__, e=e, sattr=pp(src_entry['attributes']),
+                    dn=tgt_dn, ocs=pp(tgt_obj_classes), tattr=pp(tgt_entry))
+                raise WriteLDAPItemError(msg)
+            if cr_status:
+                LOG.debug("Creation successfull.")
+                if self.verbose > 2:
+                    LOG.debug("Result of creation:\n{}".format(pp(cr_result)))
+            else:
+                msg = "Creation NOT successfull:\n{res}\n"
+                msg += "Source attributes:\n{sattr}\n"
+                msg += "Target-DN: {dn!r}\n"
+                msg += "Target Object classes:\n{ocs}\n"
+                msg += "Target attributes:\n{tattr}"
+                msg = msg.format(
+                    res=pp(cr_result), sattr=pp(src_entry['attributes']),
+                    dn=tgt_dn, ocs=pp(tgt_obj_classes), tattr=pp(tgt_entry))
+                raise WriteLDAPItemError(msg)
+
+        return True
+
+    # -------------------------------------------------------------------------
+    def generate_target_group_entry(self, src_entry, src_dn, tgt_dn):
+
+        object_classes = []
+        target_entry = {}
+        used_classes = CIStringSet()
+        name_group_classes = CIStringSet('groupOfNames', 'groupOfUniqueNames')
+
+        src_data = self.get_src_entry_data(src_entry, as_group=True)
+        for src_oc_name in src_data['classes']:
+            if src_oc_name.lower() not in ('groupofurls', 'groupofnames', 'groupofuniquenames'):
+                tgt_oc_name = self.object_classes.real_key(src_oc_name)
+                used_classes.add(tgt_oc_name)
+
+        members = src_data['members']
+
+        if 'groupOfURLs' in src_data['classes']:
+            if name_group_classes.isdisjoint(src_data['classes']):
+                members.clear()
+                tgt_oc_name = self.object_classes.real_key('groupOfURLs')
+                used_classes.add(tgt_oc_name)
+                if len(src_data['member_url']):
+                    tgt_at_name = self.attribute_types.real_key('memberURL')
+                    target_entry[tgt_at_name] = src_data['member_url']
+            else:
+                tgt_oc_name = self.object_classes.real_key('groupOfUniqueNames')
+                used_classes.add(tgt_oc_name)
+                if len(src_data['member_url']):
+                    dyn_members = self.get_dyn_members(self, src_data['member_url'])
+                    for member in dyn_members:
+                        members.add(member)
+        else:
+            tgt_oc_name = self.object_classes.real_key('groupOfUniqueNames')
+            used_classes.add(tgt_oc_name)
+
+        if len(members):
+            tgt_at_name = self.attribute_types.real_key('uniqueMember')
+            target_entry[tgt_at_name] = []
+            for member in members:
+                target_entry[tgt_at_name].append(member)
+
+        for oc in used_classes:
+            object_classes.append(oc)
+
+        return (object_classes, target_entry)
+
+    # -------------------------------------------------------------------------
+    def get_dyn_members(self, member_urls):
+
+        members = CIStringSet()
+
+
+        return members
+
+    # -------------------------------------------------------------------------
+    def get_src_entry_data(self, src_entry, as_group=False):
+
+        src_classes = CIStringSet()
+        src_attributes = CIDict()
+        src_members = CIStringSet()
+        src_member_url = CIStringSet()
+
+        for src_aname in src_entry['attributes']:
+
+            src_attr = src_entry['attributes'][src_aname]
+
+            if src_aname.lower() == 'objectclass':
+                for src_oc_name in src_attr:
+                    if src_oc_name not in self.object_classes:
+                        if self.verbose > 3:
+                            msg = "ObjectClass {oc!r} of sorce entry {dn!r} not found "
+                            msg += "on target LDAP server."
+                            msg = msg.format(oc=src_oc_name, dn=src_dn)
+                            LOG.debug(msg)
+                        self.unknown_objectclasses.add(src_oc_name)
+                        continue
+                    src_classes.add(src_oc_name)
+
+            elif src_aname.lower() in ('member', 'uniquemember') and as_group:
+                if is_sequence(src_attr):
+                    for attr in src_attr:
+                        member = self.mangle_dn(attr)
+                        src_members.add(member)
+                else:
+                    member = self.mangle_dn(src_attr)
+                    src_members.add(member)
+            elif src_aname.lower() == 'memberurl' and as_group:
+                if is_sequence(src_attr):
+                    for attr in src_attr:
+                        src_member_url.add(attr)
+                else:
+                    src_member_url.add(src_attr)
+            else:
+                if is_sequence(src_attr):
+                    for attr in src_attr:
+                        if attr == '':
+                            continue
+                        if src_aname not in src_attributes:
+                            src_attributes[src_aname] = []
+                        if src_aname in self.boolean_attr_types:
+                            if to_bool(attr):
+                                attr = 'TRUE'
+                            else:
+                                attr = 'FALSE'
+                        src_attributes[src_aname].append(attr)
+                elif src_attr != '':
+                    if src_aname not in src_attributes:
+                        src_attributes[src_aname] = []
+                    if src_aname in self.boolean_attr_types:
+                        if to_bool(src_attr):
+                            src_attr = 'TRUE'
+                        else:
+                            src_attr = 'FALSE'
+                    src_attributes[src_aname].append(src_attr)
+
+        ret = {
+            'classes': src_classes,
+            'attributes': src_attributes,
+        }
+        if as_group:
+            ret['members'] = src_members
+            ret['member_url'] = src_member_url
+
+        return ret
+
+    # -------------------------------------------------------------------------
+    def migrate_existing_group_entry(self, src_dn, tgt_dn, src_entry, tgt_entry):
 
         return True