From f17aa00ff01e3fff35d3b3ac75f001d076827ec8 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Thu, 31 Jan 2013 11:56:47 +0100 Subject: Aggregate IPASimpleLDAPObject in LDAPEntry. --- ipaserver/ipaldap.py | 58 +++++++++++++++++++++++++++++++++++++++------- ipaserver/plugins/ldap2.py | 8 +++---- 2 files changed, 53 insertions(+), 13 deletions(-) (limited to 'ipaserver') diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py index ef0febabe..9cff10169 100644 --- a/ipaserver/ipaldap.py +++ b/ipaserver/ipaldap.py @@ -403,7 +403,7 @@ class IPASimpleLDAPObject(object): original_dn = dn_tuple[0] original_attrs = dn_tuple[1] - ipa_entry = LDAPEntry(DN(original_dn)) + ipa_entry = LDAPEntry(self, DN(original_dn)) for attr, original_values in original_attrs.items(): target_type = self._SYNTAX_MAPPING.get(self.get_syntax(attr), unicode_from_utf8) @@ -583,11 +583,31 @@ class IPASimpleLDAPObject(object): # r[0] == r.dn # r[1] == r.data class LDAPEntry(dict): - __slots__ = ('_dn', '_names', '_orig') + __slots__ = ('_conn', '_dn', '_names', '_orig') - def __init__(self, _dn=None, _obj=None, **kwargs): + def __init__(self, _conn, _dn=None, _obj=None, **kwargs): + """ + LDAPEntry constructor. + + Takes 1 to 3 positional arguments and an arbitrary number of keyword + arguments. The 3 forms of positional arguments are: + + * LDAPEntry(entry) - create a shallow copy of an existing LDAPEntry. + * LDAPEntry(dn, entry) - create a shallow copy of an existing + LDAPEntry with a different DN. + * LDAPEntry(conn, dn, mapping) - create a new LDAPEntry using the + specified IPASimpleLDAPObject and DN and optionally initialize + attributes from the specified mapping object. + + Keyword arguments can be used to override values of specific attributes. + """ super(LDAPEntry, self).__init__() + if isinstance(_conn, LDAPEntry): + assert _dn is None + _dn = _conn + _conn = _conn._conn + if isinstance(_dn, LDAPEntry): assert _obj is None _obj = _dn @@ -598,19 +618,22 @@ class LDAPEntry(dict): else: if _obj is None: _obj = {} - orig = None + orig = self + assert isinstance(_conn, IPASimpleLDAPObject) assert isinstance(_dn, DN) + self._conn = _conn self._dn = _dn self._orig = orig self._names = CIDict() - if orig is None: - self.commit() - self.update(_obj, **kwargs) + @property + def conn(self): + return self._conn + # properties for Entry and Entity compatibility @property def dn(self): @@ -638,9 +661,26 @@ class LDAPEntry(dict): def copy(self): return LDAPEntry(self) + def clone(self): + result = LDAPEntry(self._conn, self._dn) + + for name in self.iterkeys(): + super(LDAPEntry, result).__setitem__( + name, deepcopy(super(LDAPEntry, self).__getitem__(name))) + + result._names = deepcopy(self._names) + if self._orig is not self: + result._orig = self._orig.clone() + + return result + def commit(self): + """ + Make the current state of the entry a new reference point for change + tracking. + """ self._orig = self - self._orig = deepcopy(self) + self._orig = self.clone() def _attr_name(self, name): if not isinstance(name, basestring): @@ -971,7 +1011,7 @@ class LDAPClient(object): return DN((primary_key, entry_attrs[primary_key]), parent_dn) def make_entry(self, _dn=None, _obj=None, **kwargs): - return LDAPEntry(_dn, _obj, **kwargs) + return LDAPEntry(self.conn, _dn, _obj, **kwargs) # generating filters for find_entry # some examples: diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index 360e6e2e2..9483611bd 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -27,7 +27,6 @@ Backend plugin for LDAP. # binding encodes them into the appropriate representation. This applies to # everything except the CrudBackend methods, where dn is part of the entry dict. -import copy import os import re import pwd @@ -207,7 +206,8 @@ class ldap2(LDAPClient, CrudBackend): try: config_entry = getattr(context, 'config_entry') - return copy.deepcopy(config_entry) + if config_entry.conn is self.conn: + return config_entry.clone() except AttributeError: # Not in our context yet pass @@ -220,11 +220,11 @@ class ldap2(LDAPClient, CrudBackend): raise errors.LimitsExceeded() config_entry = entry[0] except errors.NotFound: - config_entry = {} + config_entry = self.make_entry(cdn) for a in self.config_defaults: if a not in config_entry: config_entry[a] = self.config_defaults[a] - context.config_entry = copy.deepcopy(config_entry) + context.config_entry = config_entry.clone() return config_entry def has_upg(self): -- cgit