Index: modules/univention/s4connector/__init__.py =================================================================== --- modules/univention/s4connector/__init__.py (Revision 74662) +++ modules/univention/s4connector/__init__.py (Arbeitskopie) @@ -46,6 +46,7 @@ import univention.admin.modules import univention.admin.objects import univention.debug2 as ud +import univention.debug as ud_c from samba.ndr import ndr_unpack from samba.dcerpc import misc from signal import signal, SIGTERM, SIG_DFL @@ -547,6 +548,17 @@ debug_level = 2 ud.set_level(ud.LDAP, int(debug_level)) + try: + udm_function_level = int(self.baseConfig.get('%s/debug/udm/function' % self.CONFIGBASENAME, 0)) + except ValueError: + function_level = 0 + ud_c.init('/var/log/univention/%s-s4.log' % self.CONFIGBASENAME, 1, udm_function_level) + try: + udm_debug_level = int(self.baseConfig.get('%s/debug/udm/level' % self.CONFIGBASENAME, 1)) + except ValueError: + udm_debug_level = 1 + ud_c.set_level(ud.ADMIN, int(udm_debug_level)) + def close_debug(self): _d = ud.function('ldap.close_debug') ud.debug(ud.LDAP, ud.INFO, "close debug") @@ -698,7 +710,7 @@ ''' return dn.split(',', 1)[1] - def __sync_file_from_ucs(self, filename, append_error='', traceback_level=ud.WARN): + def __sync_file_from_ucs(self, filename, append_error='', traceback_level=ud.WARN, reject_if_s4_changed=False): _d = ud.function('ldap._sync_file_from_ucs') ''' sync changes from UCS stored in given file @@ -839,7 +851,7 @@ if not self._ignore_object(key, object) or ignore_subtree_match: ud.debug(ud.LDAP, ud.INFO, "__sync_file_from_ucs: finished mapping") try: - if ((old_dn and not self.sync_from_ucs(key, object, premapped_ucs_dn, unicode(old_dn, 'utf8'), old, new)) or (not old_dn and not self.sync_from_ucs(key, object, premapped_ucs_dn, old_dn, old, new))): + if ((old_dn and not self.sync_from_ucs(key, object, premapped_ucs_dn, unicode(old_dn, 'utf8'), old, new, reject_if_s4_changed)) or (not old_dn and not self.sync_from_ucs(key, object, premapped_ucs_dn, old_dn, old, new, reject_if_s4_changed))): self._save_rejected_ucs(filename, dn) return False else: @@ -968,7 +980,7 @@ # dummy pass - def resync_rejected_ucs(self): + def resync_rejected_ucs(self, reject_if_s4_changed=False): ''' tries to resync rejected changes from UCS ''' @@ -983,7 +995,7 @@ for filename, dn in rejected: ud.debug(ud.LDAP, ud.PROCESS, 'sync from ucs: Resync rejected file: %s' % (filename)) try: - if self.__sync_file_from_ucs(filename, append_error=' rejected'): + if self.__sync_file_from_ucs(filename, append_error=' rejected', reject_if_s4_changed=reject_if_s4_changed): try: os.remove(os.path.join(filename)) except OSError: # file not found @@ -1004,7 +1016,7 @@ # dummy pass - def poll_ucs(self): + def poll_ucs(self, reject_if_s4_changed=False): ''' poll changes from UCS: iterates over files exported by directory-listener module ''' @@ -1044,7 +1056,7 @@ for i in [0, 1]: # do it twice if the LDAP connection was closed try: - sync_successfull = self.__sync_file_from_ucs(filename, traceback_level=traceback_level) + sync_successfull = self.__sync_file_from_ucs(filename, traceback_level=traceback_level, reject_if_s4_changed=reject_if_s4_changed) except (ldap.SERVER_DOWN, SystemExit): # once again, ldap idletimeout ... if i == 0: @@ -1532,7 +1544,7 @@ self._debug_traceback(ud.ERROR, "Unknown Exception during sync_to_ucs") return False - def sync_from_ucs(self, property_type, object, pre_mapped_ucs_dn, old_dn=None, old_ucs_object=None, new_ucs_object=None): + def sync_from_ucs(self, property_type, object, pre_mapped_ucs_dn, old_dn=None, old_ucs_object=None, new_ucs_object=None, reject_if_s4_changed=False): # dummy return False Index: modules/univention/s4connector/s4/__init__.py =================================================================== --- modules/univention/s4connector/s4/__init__.py (Revision 74816) +++ modules/univention/s4connector/s4/__init__.py (Arbeitskopie) @@ -2276,7 +2276,7 @@ def __has_attribute_value_changed(self, attribute, old_ucs_object, new_ucs_object): return not old_ucs_object.get(attribute) == new_ucs_object.get(attribute) - def sync_from_ucs(self, property_type, object, pre_mapped_ucs_dn, old_dn=None, old_ucs_object=None, new_ucs_object=None): + def sync_from_ucs(self, property_type, object, pre_mapped_ucs_dn, old_dn=None, old_ucs_object=None, new_ucs_object=None, reject_if_s4_changed=False): _d = ud.function('ldap.__sync_from_ucs') # Diese Methode erhaelt von der UCS Klasse ein Objekt, # welches hier bearbeitet wird und in das S4 geschrieben wird. @@ -2288,6 +2288,25 @@ ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs ignored, sync_mode is %s" % self.property[property_type].sync_mode) return True + if reject_if_s4_changed: + s4_object = self.get_object(object['dn']) + if s4_object: + guid_blob = s4_object.get('objectGUID')[0] + objectGUID = str(ndr_unpack(misc.GUID, guid_blob)) + + object['changed_attributes'] = [] + if object['modtype'] == 'modify': + old_s4_object = self.s4cache.get_entry(objectGUID) + # ud.debug(ud.LDAP, ud.INFO, "sync_to_ucs: old_s4_object: %s" % old_s4_object) + # ud.debug(ud.LDAP, ud.INFO, "sync_to_ucs: new_s4_object: %s" % original_object['attributes']) + if old_s4_object: + if old_s4_object.get('uSNChanged') != s4_object.get('uSNChanged'): + ud.debug(ud.LDAP, ud.PROCESS, "sync_from_ucs: S4-Object changed: %s" % object['dn']) + rejected = self._list_rejected() + if not rejected: + ud.debug(ud.LDAP, ud.PROCESS, "sync_from_ucs: Temporarily rejecting sync_to_ucs because S4-Object changed: %s" % object['dn']) + return False + pre_mapped_ucs_old_dn = old_dn if old_dn: Index: modules/univention/s4connector/s4/main.py =================================================================== --- modules/univention/s4connector/s4/main.py (Revision 74662) +++ modules/univention/s4connector/s4/main.py (Arbeitskopie) @@ -210,7 +210,7 @@ while True: # Read changes from OpenLDAP try: - change_counter = s4.poll_ucs() + change_counter = s4.poll_ucs(reject_if_s4_changed=True) if change_counter > 0: # UCS changes, read again from UCS retry_rejected = 0 @@ -242,7 +242,7 @@ try: if str(retry_rejected) == baseconfig_retry_rejected: - s4.resync_rejected_ucs() + s4.resync_rejected_ucs(reject_if_s4_changed=True) s4.resync_rejected() retry_rejected = 0 else: