From: Frank Brehm Date: Fri, 8 Jan 2021 14:06:25 +0000 (+0100) Subject: Zwischenstand Gruppenmigration X-Git-Url: https://git.uhu-banane.org/?a=commitdiff_plain;h=d1283149ed9fa4c408d19a0088a1a014ffb0b593;p=pixelpark%2Fldap-migration.git Zwischenstand Gruppenmigration --- diff --git a/lib/ldap_migration/__init__.py b/lib/ldap_migration/__init__.py index 67c0fdc..c5589f2 100644 --- a/lib/ldap_migration/__init__.py +++ b/lib/ldap_migration/__init__.py @@ -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