Index: modules/univention/s4connector/s4/__init__.py =================================================================== --- modules/univention/s4connector/s4/__init__.py (Revision 33813) +++ modules/univention/s4connector/s4/__init__.py (Arbeitskopie) @@ -664,14 +664,11 @@ self.open_s4() - if not self.config.has_section('S4'): - ud.debug(ud.LDAP, ud.INFO,"__init__: init add config section 'S4'") - self.config.add_section('S4') + for section in ['S4', 'S4 rejected', 'S4 rejected timestamp', 'S4 GUID' ]: + if not self.config.has_section(section): + ud.debug(ud.LDAP, ud.INFO,"__init__: init add config section %s" % section) + self.config.add_section(section) - if not self.config.has_section('S4 rejected'): - ud.debug(ud.LDAP, ud.INFO,"__init__: init add config section 'S4 rejected'") - self.config.add_section('S4 rejected') - if not self.config.has_option('S4','lastUSN'): ud.debug(ud.LDAP, ud.INFO,"__init__: init lastUSN with 0") self._set_config_option('S4','lastUSN','0') @@ -679,9 +676,6 @@ else: self.__lastUSN=int(self._get_config_option('S4','lastUSN')) - if not self.config.has_section('S4 GUID'): - ud.debug(ud.LDAP, ud.INFO,"__init__: init add config section 'S4 GUID'") - self.config.add_section('S4 GUID') try: # LDAP_SERVER_SHOW_DELETED_OID -> 1.2.840.113556.1.4.417 self.ctrl_show_deleted = LDAPControl('1.2.840.113556.1.4.417',criticality=1) @@ -824,6 +818,8 @@ _d=ud.function('ldap._save_rejected') try: self._set_config_option('S4 rejected',str(id),compatible_modstring(dn)) + if not self._get_config_option('S4 rejected timestamp', compatible_modstring(dn.lower())): + self._set_config_option('S4 rejected timestamp', compatible_modstring(dn.lower()), time.time()) except UnicodeEncodeError, msg: self._set_config_option('S4 rejected',str(id),'unknown') self._debug_traceback(ud.WARN, @@ -835,8 +831,23 @@ def _remove_rejected(self,id): _d=ud.function('ldap._remove_rejected') + dn = self._get_rejected(str(id)) self._remove_config_option('S4 rejected',str(id)) + # Remove the timestamp entry for this rejected DN if this is the last + # rejected object with this DN + if dn: + found = False + for f, d in self.list_rejected(): + if d.lower() == dn.lower(): + found = True + break + if not found: + self._remove_config_option('S4 rejected timestamp',dn.lower()) + + def _get_rejected_timestamp(self, dn): + return self._get_config_option('S4 rejected timestamp',dn.lower()) + def _list_rejected(self): _d=ud.function('ldap._list_rejected') result = [] @@ -2081,7 +2092,25 @@ return True pre_mapped_ucs_old_dn = old_dn - + + ## Is the object rejected in S4? + # If sync_mode is not sync, it does not matter + if self.property[property_type].sync_mode == 'sync': + t_s4 = self._get_rejected_timestamp(pre_mapped_ucs_dn.lower()) + t_ucs = self._get_rejected_timestamp_ucs(object['dn'].lower()) + if t_s4: + ud.debug(ud.LDAP, ud.PROCESS, 't_s4=%s'% float(t_s4)) + if t_ucs: + ud.debug(ud.LDAP, ud.PROCESS, 't_ucs=%s'% float(t_ucs)) + + if t_s4: + # We have a rejected UCS object, so check the timestamp + if not t_ucs or float(t_s4) < float(t_ucs): + if t_ucs: + ud.debug(ud.LDAP, ud.PROCESS, 'This object is already rejected in the different direction (S4 to UCS). This direction (UCS to S4) will now also rejected until the firsrst rejection is solved.') + # The UCS object is older, this object must be synced first + return False + if old_dn: ud.debug(ud.LDAP, ud.INFO, "move %s from [%s] to [%s]" % (property_type, old_dn, object['dn'])) if hasattr ( self.property[property_type], 'dn_mapping_function' ): @@ -2272,7 +2301,7 @@ modlist.append((ldap.MOD_DELETE, yank_empty_attr, None)) if modlist: - ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: modlist: %s" % modlist) + ud.debug(ud.LDAP, ud.PROCESS, "sync_from_ucs: modlist: %s" % modlist) self.lo_s4.lo.modify_ext_s(compatible_modstring(object['dn']), compatible_modlist(modlist), serverctrls=self.serverctrls_for_add_and_modify) Index: modules/univention/s4connector/__init__.py =================================================================== --- modules/univention/s4connector/__init__.py (Revision 33813) +++ modules/univention/s4connector/__init__.py (Arbeitskopie) @@ -409,9 +409,9 @@ self.open_ucs() - for section in ['DN Mapping UCS','DN Mapping CON','UCS rejected']: + for section in ['DN Mapping UCS', 'DN Mapping CON', 'UCS rejected', 'UCS rejected timestamp']: if not self.config.has_section(section): - self.config.add_section(section) + self.config.add_section(section) ud.debug(ud.LDAP, ud.INFO, "init finished") @@ -488,6 +488,8 @@ def _save_rejected_ucs(self, filename, dn): _d=ud.function('ldap._save_rejected_ucs') self._set_config_option('UCS rejected',filename,dn) + if not self._get_config_option('UCS rejected timestamp', dn.lower()): + self._set_config_option('UCS rejected timestamp', dn.lower(), time.time()) def _get_rejected_ucs(self, filename): _d=ud.function('ldap._get_rejected_ucs') @@ -495,8 +497,20 @@ def _remove_rejected_ucs(self,filename): _d=ud.function('ldap._remove_rejected_ucs') + dn = self._get_rejected_ucs(filename) self._remove_config_option('UCS rejected',filename) + # Remove the timestamp entry for this rejected DN if this is the last + # rejected object with this DN + if dn: + found = False + for f, d in self.list_rejected_ucs(): + if d.lower() == dn.lower(): + found = True + break + if not found: + self._remove_config_option('UCS rejected timestamp',dn.lower()) + def _list_rejected_ucs(self): _d=ud.function('ldap._list_rejected_ucs') result = [] @@ -513,6 +527,9 @@ def list_rejected_ucs(self): return self._get_config_items('UCS rejected') + + def _get_rejected_timestamp_ucs(self, dn): + return self._get_config_option('UCS rejected timestamp',dn.lower()) def _encode_dn_as_config_option(self, dn): return dn @@ -1243,6 +1260,24 @@ ud.debug(ud.LDAP, ud.INFO, "sync_to_ucs ignored, sync_mode is %s" % self.property[property_type].sync_mode) return True + ## Is the object rejected in UCS? + # If sync_mode is not sync, it does not matter + if self.property[property_type].sync_mode == 'sync': + t_s4 = self._get_rejected_timestamp(premapped_s4_dn.lower()) + t_ucs = self._get_rejected_timestamp_ucs(object['dn'].lower()) + if t_s4: + ud.debug(ud.LDAP, ud.PROCESS, 't_s4=%s'% float(t_s4)) + if t_ucs: + ud.debug(ud.LDAP, ud.PROCESS, 't_ucs=%s'% float(t_ucs)) + + if t_ucs: + # We have a rejected UCS object, so check the timestamp + if not t_s4 or float(t_ucs) < float(t_s4): + if t_s4: + ud.debug(ud.LDAP, ud.PROCESS, 'This object is already rejected in the different direction (UCS to S4 LDAP). This direction (S4 to UCS) will now also rejected until the first rejection will solved.') + # The UCS object is older, this object must be synced first + return False + if object.has_key('olddn'): old_object = self.get_ucs_object(property_type,object['olddn']) else: