Lines 2579-2738
class s4(univention.s4connector.ucs):
|
Link Here
|
---|
|
2579 |
# |
2579 |
# |
2580 |
elif (object['modtype'] == 'modify' and s4_object) or (object['modtype'] == 'add' and s4_object): |
2580 |
elif (object['modtype'] == 'modify' and s4_object) or (object['modtype'] == 'add' and s4_object): |
2581 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: modify object: %s" % object['dn']) |
2581 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: modify object: %s" % object['dn']) |
2582 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: old_object: %s" % old_ucs_object) |
2582 |
ud.debug(ud.LDAP, ud.INFO, |
2583 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: new_object: %s" % new_ucs_object) |
2583 |
"sync_from_ucs: old_object: %s" % old_ucs_object) |
|
|
2584 |
ud.debug(ud.LDAP, ud.INFO, |
2585 |
"sync_from_ucs: new_object: %s" % new_ucs_object) |
2584 |
object['old_ucs_object'] = old_ucs_object |
2586 |
object['old_ucs_object'] = old_ucs_object |
2585 |
object['new_ucs_object'] = new_ucs_object |
2587 |
object['new_ucs_object'] = new_ucs_object |
2586 |
attribute_list = set(old_ucs_object.keys()).union(set(new_ucs_object.keys())) |
2588 |
attribute_list = set(old_ucs_object.keys() + new_ucs_object.keys()) |
2587 |
if hasattr(self.property[property_type], "con_sync_function"): |
|
|
2588 |
self.property[property_type].con_sync_function(self, property_type, object) |
2589 |
else: |
2590 |
# Iterate over attributes and post_attributes |
2591 |
for attribute_type_name, attribute_type in [('attributes', self.property[property_type].attributes), ('post_attributes', self.property[property_type].post_attributes)]: |
2592 |
if hasattr(self.property[property_type], attribute_type_name) and attribute_type is not None: |
2593 |
for attr in attribute_list: |
2594 |
value = new_ucs_object.get(attr) |
2595 |
if not self.__has_attribute_value_changed(attr, old_ucs_object, new_ucs_object): |
2596 |
continue |
2597 |
|
2589 |
|
2598 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: The following attribute has been changed: %s" % attr) |
2590 |
def find_case_independent(s4_object, attribute): |
2599 |
|
2591 |
attr = attribute.lower() |
2600 |
for attribute in attribute_type.keys(): |
2592 |
matching = (v for (k, v) in s4_object.iteritems() if k.lower() == attr) |
2601 |
if attribute_type[attribute].ldap_attribute != attr: |
2593 |
try: |
2602 |
continue |
2594 |
values = next(matching) |
|
|
2595 |
except StopIteration: |
2596 |
values = [] |
2597 |
return set(values) |
2598 |
|
2599 |
# Iterate over attributes and post_attributes |
2600 |
for attribute_type_name, attribute_type in [('attributes', self.property[property_type].attributes), |
2601 |
('post_attributes', self.property[property_type].post_attributes)]: |
2602 |
if hasattr(self.property[property_type], attribute_type_name) and attribute_type is not None: |
2603 |
for attr in attribute_list: |
2604 |
if not self.__has_attribute_value_changed(attr, old_ucs_object, new_ucs_object): |
2605 |
continue |
2603 |
|
2606 |
|
2604 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: Found a corresponding mapping defintion: %s" % attribute) |
2607 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: The following attribute has been changed: %s" % attr) |
2605 |
s4_attribute = attribute_type[attribute].con_attribute |
|
|
2606 |
s4_other_attribute = attribute_type[attribute].con_other_attribute |
2607 |
|
2608 |
|
2608 |
if not attribute_type[attribute].sync_mode in ['write', 'sync']: |
2609 |
for attribute in attribute_type.keys(): |
2609 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: %s is in not in write or sync mode. Skipping" % attribute) |
2610 |
if attribute_type[attribute].ldap_attribute != attr: |
2610 |
continue |
2611 |
continue |
2611 |
|
2612 |
|
2612 |
modify = False |
2613 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: Found a corresponding mapping defintion: %s" % attribute) |
|
|
2614 |
s4_attribute = attribute_type[attribute].con_attribute |
2615 |
s4_other_attribute = attribute_type[attribute].con_other_attribute |
2613 |
|
2616 |
|
2614 |
# Get the UCS attributes |
2617 |
if not attribute_type[attribute].sync_mode in ['write', 'sync']: |
2615 |
old_values = set(old_ucs_object.get(attr, [])) |
2618 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: %s is in not in write or sync mode. Skipping" % attribute) |
2616 |
new_values = set(new_ucs_object.get(attr, [])) |
2619 |
continue |
2617 |
|
2620 |
|
2618 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: old_values: %s" % old_values) |
2621 |
# Get the UCS attributes |
2619 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: new_values: %s" % new_values) |
2622 |
old_values = set(old_ucs_object.get(attr, [])) |
|
|
2623 |
new_values = set(new_ucs_object.get(attr, [])) |
2620 |
|
2624 |
|
2621 |
if attribute_type[attribute].compare_function: |
2625 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: old_values: %s" % old_values) |
2622 |
if not attribute_type[attribute].compare_function(list(old_values), list(new_values)): |
2626 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: new_values: %s" % new_values) |
2623 |
modify = True |
|
|
2624 |
elif not univention.s4connector.compare_lowercase(list(old_values), list(new_values)): # FIXME: use defined compare-function from mapping.py |
2625 |
modify = True |
2626 |
|
2627 |
|
2627 |
if not modify: |
2628 |
current_s4_values = find_case_independent(s4_object, s4_attribute) |
2628 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: no modification necessary for %s" % attribute) |
|
|
2629 |
continue |
2630 |
|
2629 |
|
2631 |
# So, at this point we have the old and the new UCS object. |
2630 |
compare_function = attribute_type[attribute].compare_function or \ |
2632 |
# Thus we can create the diff, but we have to check the current S4 object |
2631 |
univention.s4connector.compare_lowercase |
|
|
2632 |
if compare_function(list(old_values), list(new_values)): |
2633 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: no modification necessary for %s" % attribute) |
2634 |
continue |
2633 |
|
2635 |
|
2634 |
if not old_values: |
2636 |
# So, at this point we have the old and the new UCS object. |
2635 |
to_add = new_values |
2637 |
# Thus we can create the diff, but we have to check the current S4 object |
2636 |
to_remove = set([]) |
2638 |
to_add = new_values - old_values |
2637 |
elif not new_values: |
2639 |
to_remove = old_values - new_values |
2638 |
to_remove = old_values |
2640 |
|
2639 |
to_add = set([]) |
2641 |
if s4_other_attribute: |
2640 |
else: |
2642 |
# This is the case, where we map from a multi-valued UCS attribute to two S4 attributes. |
2641 |
to_add = new_values - old_values |
2643 |
# telephoneNumber/otherTelephone (S4) to telephoneNumber (UCS) would be an example. |
2642 |
to_remove = old_values - new_values |
2644 |
# |
2643 |
|
2645 |
# The direct mapping assumes preserved ordering of the multi-valued UCS |
2644 |
if s4_other_attribute: |
2646 |
# attributes and places the first value in the primary S4 attribute, |
2645 |
# This is the case, where we map from a multi-valued UCS attribute to two S4 attributes. |
2647 |
# the rest in the secondary S4 attributes. |
2646 |
# telephoneNumber/otherTelephone (S4) to telephoneNumber (UCS) would be an example. |
2648 |
# |
2647 |
# |
2649 |
# The following code handles the correct distribution of the UCS attribute, |
2648 |
# The direct mapping assumes preserved ordering of the multi-valued UCS |
2650 |
# to two S4 attributes. It also ensures, that the primary S4 attribute keeps |
2649 |
# attributes and places the first value in the primary S4 attribute, |
2651 |
# its value as long as that value is not removed. If removed the primary |
2650 |
# the rest in the secondary S4 attributes. |
2652 |
# attribute is assigned a random value from the UCS attribute. |
2651 |
# Assuming preserved ordering is wrong, as LDAP does not guarantee is and the |
2653 |
current_s4_other_values = find_case_independent(s4_object, s4_other_attribute) |
2652 |
# deduplication of LDAP attribute values in `__set_values()` destroys it. |
2654 |
|
2653 |
# |
2655 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: The current S4 values: %s" % current_s4_values) |
2654 |
# The following code handles the correct distribution of the UCS attribute, |
2656 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: The current S4 other values: %s" % current_s4_other_values) |
2655 |
# to two S4 attributes. It also ensures, that the primary S4 attribute keeps |
2657 |
|
2656 |
# its value as long as that value is not removed. If removed the primary |
2658 |
# If we removed the value on the UCS side that was contained in the `s4_attribute`, |
2657 |
# attribute is assigned a random value from the UCS attribute. |
2659 |
# but are adding new values, we choose a random value from the new values. |
2658 |
try: |
2660 |
new_s4_values = current_s4_values - to_remove |
2659 |
current_s4_values = set([v for k, v in s4_object.iteritems() if s4_attribute.lower() == k.lower()][0]) |
2661 |
if not new_s4_values and to_add: |
2660 |
except IndexError: |
2662 |
new_s4_values.add(to_add.pop()) |
2661 |
current_s4_values = set([]) |
2663 |
new_s4_other_values = (current_s4_other_values | to_add) - to_remove - current_s4_values |
2662 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: The current S4 values: %s" % current_s4_values) |
2664 |
|
2663 |
|
2665 |
if current_s4_values != new_s4_values: |
2664 |
try: |
2666 |
modlist.append((ldap.MOD_REPLACE, s4_attribute, new_s4_values)) |
2665 |
current_s4_other_values = set([v for k, v in s4_object.iteritems() if s4_other_attribute.lower() == k.lower()][0]) |
2667 |
if current_s4_other_values != new_s4_other_values: |
2666 |
except IndexError: |
2668 |
modlist.append((ldap.MOD_REPLACE, s4_other_attribute, new_s4_other_values)) |
2667 |
current_s4_other_values = set([]) |
2669 |
else: |
2668 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: The current S4 other values: %s" % current_s4_other_values) |
2670 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: The current S4 values: %s" % current_s4_values) |
2669 |
|
2671 |
|
2670 |
new_s4_values = current_s4_values - to_remove |
2672 |
if (to_add or to_remove) and attribute_type[attribute].single_value: |
2671 |
if not new_s4_values and to_add: |
2673 |
value = new_ucs_object.get(attr) |
2672 |
for n_value in new_ucs_object.get(attr, []): |
2674 |
modify = not current_s4_values or not value or \ |
2673 |
if n_value in to_add: |
2675 |
not compare_function(list(current_s4_values), list(value)) |
2674 |
to_add = to_add - set([n_value]) |
2676 |
if modify: |
2675 |
new_s4_values = [n_value] |
2677 |
mapping = getattr(attribute_type[attribute], 'mapping', ()) |
2676 |
break |
2678 |
if len(mapping) > 0 and mapping[0]: |
2677 |
|
2679 |
ud.debug(ud.LDAP, ud.PROCESS, "Calling single value mapping function") |
2678 |
new_s4_other_values = (current_s4_other_values | to_add) - to_remove - current_s4_values |
2680 |
value = mapping[0](self, None, object) |
2679 |
if current_s4_values != new_s4_values: |
2681 |
modlist.append((ldap.MOD_REPLACE, s4_attribute, value)) |
2680 |
if new_s4_values: |
|
|
2681 |
modlist.append((ldap.MOD_REPLACE, s4_attribute, new_s4_values)) |
2682 |
else: |
2683 |
modlist.append((ldap.MOD_REPLACE, s4_attribute, [])) |
2684 |
|
2685 |
if current_s4_other_values != new_s4_other_values: |
2686 |
modlist.append((ldap.MOD_REPLACE, s4_other_attribute, new_s4_other_values)) |
2687 |
else: |
2682 |
else: |
2688 |
try: |
2683 |
if to_remove: |
2689 |
current_s4_values = set([v for k, v in s4_object.iteritems() if s4_attribute.lower() == k.lower()][0]) |
2684 |
r = current_s4_values & to_remove |
2690 |
except IndexError: |
2685 |
if r: |
2691 |
current_s4_values = set([]) |
2686 |
modlist.append((ldap.MOD_DELETE, s4_attribute, r)) |
2692 |
|
2687 |
if to_add: |
2693 |
ud.debug(ud.LDAP, ud.INFO, "sync_from_ucs: The current S4 values: %s" % current_s4_values) |
2688 |
a = to_add - current_s4_values |
2694 |
|
2689 |
if a: |
2695 |
if (to_add or to_remove) and attribute_type[attribute].single_value: |
2690 |
modlist.append((ldap.MOD_ADD, s4_attribute, a)) |
2696 |
modify = False |
2691 |
|
2697 |
if not current_s4_values or not value: |
2692 |
if not modlist: |
2698 |
modify = True |
2693 |
ud.debug(ud.LDAP, ud.ALL, "nothing to modify: %s" % object['dn']) |
2699 |
elif attribute_type[attribute].compare_function: |
2694 |
else: |
2700 |
if not attribute_type[attribute].compare_function(list(current_s4_values), list(value)): |
2695 |
ud.debug(ud.LDAP, ud.INFO, "to modify: %s" % object['dn']) |
2701 |
modify = True |
2696 |
ud.debug(ud.LDAP, ud.ALL, "sync_from_ucs: modlist: %s" % modlist) |
2702 |
elif not univention.s4connector.compare_lowercase(list(current_s4_values), list(value)): |
2697 |
try: |
2703 |
modify = True |
2698 |
self.lo_s4.lo.modify_ext_s(compatible_modstring(object['dn']), compatible_modlist(modlist), serverctrls=self.serverctrls_for_add_and_modify) |
2704 |
if modify: |
2699 |
except: |
2705 |
if hasattr(attribute_type[attribute], 'mapping') and len(attribute_type[attribute].mapping) > 0 and attribute_type[attribute].mapping[0]: |
2700 |
ud.debug(ud.LDAP, ud.ERROR, "sync_from_ucs: traceback during modify object: %s" % object['dn']) |
2706 |
ud.debug(ud.LDAP, ud.PROCESS, "Calling single value mapping function") |
2701 |
ud.debug(ud.LDAP, ud.ERROR, "sync_from_ucs: traceback due to modlist: %s" % modlist) |
2707 |
value = attribute_type[attribute].mapping[0](self, None, object) |
2702 |
raise |
2708 |
modlist.append((ldap.MOD_REPLACE, s4_attribute, value)) |
|
|
2709 |
else: |
2710 |
if to_remove: |
2711 |
r = current_s4_values & to_remove |
2712 |
if r: |
2713 |
modlist.append((ldap.MOD_DELETE, s4_attribute, r)) |
2714 |
if to_add: |
2715 |
a = to_add - current_s4_values |
2716 |
if a: |
2717 |
modlist.append((ldap.MOD_ADD, s4_attribute, a)) |
2718 |
|
2719 |
if not modlist: |
2720 |
ud.debug(ud.LDAP, ud.ALL, "nothing to modify: %s" % object['dn']) |
2721 |
else: |
2722 |
ud.debug(ud.LDAP, ud.INFO, "to modify: %s" % object['dn']) |
2723 |
ud.debug(ud.LDAP, ud.ALL, "sync_from_ucs: modlist: %s" % modlist) |
2724 |
try: |
2725 |
self.lo_s4.lo.modify_ext_s(compatible_modstring(object['dn']), compatible_modlist(modlist), serverctrls=self.serverctrls_for_add_and_modify) |
2726 |
except: |
2727 |
ud.debug(ud.LDAP, ud.ERROR, "sync_from_ucs: traceback during modify object: %s" % object['dn']) |
2728 |
ud.debug(ud.LDAP, ud.ERROR, "sync_from_ucs: traceback due to modlist: %s" % modlist) |
2729 |
raise |
2730 |
|
2703 |
|
2731 |
if hasattr(self.property[property_type], "post_con_modify_functions"): |
2704 |
if hasattr(self.property[property_type], "post_con_modify_functions"): |
2732 |
for f in self.property[property_type].post_con_modify_functions: |
2705 |
for f in self.property[property_type].post_con_modify_functions: |
2733 |
ud.debug(ud.LDAP, ud.INFO, "Call post_con_modify_functions: %s" % f) |
2706 |
ud.debug(ud.LDAP, ud.INFO, "Call post_con_modify_functions: %s" % f) |
2734 |
f(self, property_type, object) |
2707 |
f(self, property_type, object) |
2735 |
ud.debug(ud.LDAP, ud.INFO, "Call post_con_modify_functions: %s (done)" % f) |
2708 |
ud.debug(ud.LDAP, ud.INFO, "Call post_con_modify_functions: %s (done)" % f) |
2736 |
# |
2709 |
# |
2737 |
# DELETE |
2710 |
# DELETE |
2738 |
# |
2711 |
# |
2739 |
- |
|
|
2740 |
handling |
2712 |
handling |
2741 |
-- |
|
|
2742 |
.../modules/univention/s4connector/s4/__init__.py | 57 ++++++++++++++++------ |
2713 |
.../modules/univention/s4connector/s4/__init__.py | 57 ++++++++++++++++------ |
2743 |
1 file changed, 41 insertions(+), 16 deletions(-) |
2714 |
1 file changed, 41 insertions(+), 16 deletions(-) |