Aggregate IPASimpleLDAPObject in LDAPEntry.

This commit is contained in:
Jan Cholasta
2013-01-31 11:56:47 +01:00
committed by Martin Kosek
parent 8f46ca5dd2
commit f17aa00ff0
3 changed files with 57 additions and 14 deletions

View File

@@ -403,7 +403,7 @@ class IPASimpleLDAPObject(object):
original_dn = dn_tuple[0] original_dn = dn_tuple[0]
original_attrs = dn_tuple[1] 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(): for attr, original_values in original_attrs.items():
target_type = self._SYNTAX_MAPPING.get(self.get_syntax(attr), unicode_from_utf8) 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[0] == r.dn
# r[1] == r.data # r[1] == r.data
class LDAPEntry(dict): 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__() super(LDAPEntry, self).__init__()
if isinstance(_conn, LDAPEntry):
assert _dn is None
_dn = _conn
_conn = _conn._conn
if isinstance(_dn, LDAPEntry): if isinstance(_dn, LDAPEntry):
assert _obj is None assert _obj is None
_obj = _dn _obj = _dn
@@ -598,19 +618,22 @@ class LDAPEntry(dict):
else: else:
if _obj is None: if _obj is None:
_obj = {} _obj = {}
orig = None orig = self
assert isinstance(_conn, IPASimpleLDAPObject)
assert isinstance(_dn, DN) assert isinstance(_dn, DN)
self._conn = _conn
self._dn = _dn self._dn = _dn
self._orig = orig self._orig = orig
self._names = CIDict() self._names = CIDict()
if orig is None:
self.commit()
self.update(_obj, **kwargs) self.update(_obj, **kwargs)
@property
def conn(self):
return self._conn
# properties for Entry and Entity compatibility # properties for Entry and Entity compatibility
@property @property
def dn(self): def dn(self):
@@ -638,9 +661,26 @@ class LDAPEntry(dict):
def copy(self): def copy(self):
return LDAPEntry(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): def commit(self):
"""
Make the current state of the entry a new reference point for change
tracking.
"""
self._orig = self self._orig = self
self._orig = deepcopy(self) self._orig = self.clone()
def _attr_name(self, name): def _attr_name(self, name):
if not isinstance(name, basestring): if not isinstance(name, basestring):
@@ -971,7 +1011,7 @@ class LDAPClient(object):
return DN((primary_key, entry_attrs[primary_key]), parent_dn) return DN((primary_key, entry_attrs[primary_key]), parent_dn)
def make_entry(self, _dn=None, _obj=None, **kwargs): 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 # generating filters for find_entry
# some examples: # some examples:

View File

@@ -27,7 +27,6 @@ Backend plugin for LDAP.
# binding encodes them into the appropriate representation. This applies to # binding encodes them into the appropriate representation. This applies to
# everything except the CrudBackend methods, where dn is part of the entry dict. # everything except the CrudBackend methods, where dn is part of the entry dict.
import copy
import os import os
import re import re
import pwd import pwd
@@ -207,7 +206,8 @@ class ldap2(LDAPClient, CrudBackend):
try: try:
config_entry = getattr(context, 'config_entry') config_entry = getattr(context, 'config_entry')
return copy.deepcopy(config_entry) if config_entry.conn is self.conn:
return config_entry.clone()
except AttributeError: except AttributeError:
# Not in our context yet # Not in our context yet
pass pass
@@ -220,11 +220,11 @@ class ldap2(LDAPClient, CrudBackend):
raise errors.LimitsExceeded() raise errors.LimitsExceeded()
config_entry = entry[0] config_entry = entry[0]
except errors.NotFound: except errors.NotFound:
config_entry = {} config_entry = self.make_entry(cdn)
for a in self.config_defaults: for a in self.config_defaults:
if a not in config_entry: if a not in config_entry:
config_entry[a] = self.config_defaults[a] config_entry[a] = self.config_defaults[a]
context.config_entry = copy.deepcopy(config_entry) context.config_entry = config_entry.clone()
return config_entry return config_entry
def has_upg(self): def has_upg(self):

View File

@@ -156,7 +156,10 @@ class test_ldap(object):
dn1 = DN(('cn', cn1[0])) dn1 = DN(('cn', cn1[0]))
dn2 = DN(('cn', cn2[0])) dn2 = DN(('cn', cn2[0]))
e = LDAPEntry(dn1, cn=cn1) self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri)
self.conn.connect()
e = LDAPEntry(self.conn.conn, dn1, cn=cn1)
assert e.dn is dn1 assert e.dn is dn1
assert u'cn' in e assert u'cn' in e
assert u'cn' in e.keys() assert u'cn' in e.keys()