from .idict import CaseInsensitiveDict
from .istringset import CaseInsensitiveStringSet
-__version__ = '0.6.8'
+__version__ = '0.6.9'
LOG = logging.getLogger(__name__)
CFG_BASENAME = 'ldap-migration.ini'
self.attribute_types = CaseInsensitiveDict()
self.dns = CaseInsensitiveDict()
self.struct_dns = CaseInsensitiveDict()
+ self.migrated_entries = CaseInsensitiveDict()
self.integer_attribute_types = CaseInsensitiveStringSet([])
super(LDAPMigrationApplication, self).__init__(
def get_source_item(self, src_dn, tgt_dn, with_acl=False):
"""Reading a single LDAP item."""
- # ReadLDAPItemError
src_entry = None
sfilter = '(objectClass=*)'
return entry
+ # -------------------------------------------------------------------------
+ def get_target_item(self, tgt_dn, with_acl=False):
+
+ tgt_entry = None
+
+ tgt_attrs = [ALL_ATTRIBUTES]
+ sfilter = '(objectClass=*)'
+
+ if self.verbose > 1:
+ LOG.debug("Searching for target DN {dn!r}.".format(dn=tgt_dn))
+
+ tgt_status, tgt_result, tgt_response, _ = self.target.search(
+ search_base=tgt_dn, search_scope=BASE, search_filter=sfilter,
+ get_operational_attributes=with_acl, attributes=tgt_attrs,
+ time_limit=self.config.timeout)
+
+ target_entry = None
+ if tgt_status:
+ target_entry = tgt_response[0]
+ if self.verbose > 3:
+ LOG.debug("Result of searching for target DN {dn!r}:\n{res}".format(
+ dn=tgt_dn, res=pp(tgt_result)))
+ if self.verbose > 4:
+ LOG.debug("Response of searching for target DN {dn!r}:\n{res}".format(
+ dn=tgt_dn, res=pp(target_entry)))
+ else:
+ if self.verbose > 3:
+ LOG.debug("Target DN {dn!r} not found.".format(dn=tgt_dn))
+
+ return target_entry
+
# -------------------------------------------------------------------------
def discover_target_schema(self):
return ','.join(parts)
+ # -------------------------------------------------------------------------
+ def get_reverse_dn(self, dn):
+
+ parts = reversed(self.re_dn_split.split(dn))
+ return ':'.join(parts)
+
# -------------------------------------------------------------------------
def register_dn_tokens(self, dn, object_classes, cur_hash=None):
src_dn = cur_hash['dn']
LOG.debug("Migrating source DN {dn!r}.".format(dn=src_dn))
- src_entry = None
- tgt_entry = None
- sfilter = '(objectClass=*)'
-
tgt_dn = self.mangle_dn(src_dn)
- src_entry = self.get_source_item(src_dn, tgt_dn, with_acl=with_acl)
- tgt_attrs = [ALL_ATTRIBUTES]
- if self.verbose > 1:
- LOG.debug("Searching for target DN {dn!r}.".format(dn=tgt_dn))
- tgt_status, tgt_result, tgt_response, _ = self.target.search(
- search_base=tgt_dn, search_scope=BASE, search_filter=sfilter,
- get_operational_attributes=with_acl, attributes=tgt_attrs,
- time_limit=self.config.timeout)
-
- target_entry = None
- if tgt_status:
- target_entry = tgt_response[0]
- if self.verbose > 2:
- LOG.debug("Result of searching for target DN {dn!r}:\n{res}".format(
- dn=tgt_dn, res=pp(tgt_result)))
- if self.verbose > 2:
- LOG.debug("Response of searching for target DN {dn!r}:\n{res}".format(
- dn=tgt_dn, res=pp(target_entry)))
- changes = self.generate_modify_data(src_entry, target_entry, src_dn, tgt_dn)
- if changes:
+ rev_dn = self.get_reverse_dn(tgt_dn)
+ if rev_dn in self.migrated_entries:
+ LOG.debug("Entry {!r} is already migrated.".format(tgt_dn))
+ else:
+
+ src_entry = self.get_source_item(src_dn, tgt_dn, with_acl=with_acl)
+ tgt_entry = self.get_target_item(tgt_dn, with_acl=with_acl)
+
+ if tgt_entry:
+
+ changes = self.generate_modify_data(src_entry, tgt_entry, src_dn, tgt_dn)
+ if changes:
+ if self.verbose:
+ LOG.info("Updating target entry {!r} ...".format(tgt_dn))
+ if self.verbose > 2:
+ msg = "Changes on target entry {tdn!r}:\n{ch}".format(
+ tdn=tgt_dn, ch=pp(changes))
+ LOG.debug(msg)
+ self.count_modified += 1
+ if not self.simulate:
+ self.target.modify(tgt_dn, changes)
+ self.migrated_entries[rev_dn] = tgt_dn
+ if wait:
+ time.sleep(wait)
+
+ else:
+ (tgt_obj_classes, tgt_entry) = self.generate_target_entry(src_entry, src_dn, tgt_dn)
if self.verbose:
- LOG.info("Updating target entry {!r} ...".format(tgt_dn))
+ LOG.info("Creating target entry {!r} ...".format(tgt_dn))
if self.verbose > 2:
- msg = "Changes on target entry {tdn!r}:\n{ch}".format(
- tdn=tgt_dn, ch=pp(changes))
+ 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_modified += 1
+ self.count_added += 1
if not self.simulate:
- self.target.modify(tgt_dn, changes)
+ self.target.add(tgt_dn, object_class=tgt_obj_classes, attributes=tgt_entry)
+ self.migrated_entries[rev_dn] = tgt_dn
if wait:
time.sleep(wait)
- else:
- if self.verbose > 2:
- LOG.debug("Target DN {dn!r} not found.".format(dn=tgt_dn))
- (tgt_obj_classes, tgt_entry) = self.generate_target_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:
- self.target.add(tgt_dn, object_class=tgt_obj_classes, attributes=tgt_entry)
- if wait:
- time.sleep(wait)
-
for key in cur_hash['childs'].keys():
self._migrate_entries(cur_hash['childs'][key], is_root=False, with_acl=with_acl)
self.get_all_dns()
self.get_structural_dns()
self.migrate_entries()
+ if self.verbose > 1:
+ mlist = []
+ for key in self.migrated_entries:
+ dn = self.migrated_entries[key]
+ mlist.append(dn)
+ LOG.debug("Migrated items:\n{}".format(pp(mlist)))
finally:
self.disconnect()