[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Freeipa-devel] [PATCHES] 225-230 Drop support for the legacy LDAP API



Hi,

I believe the time has come to drop support for the legacy (dn, entry_attrs) tuple API and move to the new LDAPEntry API exclusively. The attached patches convert existing code which uses the old API to the new API and remove backward compatibility code from the ipaldap module.

Note that there are still some functions/methods which accept separate dn and entry_attrs arguments, they will be adapted to LDAPEntry later.

Honza

--
Jan Cholasta
>From 61b4f9470308709c113747c11ac8ef370d582762 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast redhat com>
Date: Thu, 31 Oct 2013 16:53:44 +0000
Subject: [PATCH 1/6] Convert remaining backend code to LDAPEntry API.

---
 ipapython/ipaldap.py        |  6 +++---
 ipaserver/plugins/dogtag.py |  4 +---
 ipaserver/plugins/ldap2.py  | 39 +++++++++++++++++++--------------------
 ipaserver/rpcserver.py      |  2 +-
 4 files changed, 24 insertions(+), 27 deletions(-)

diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py
index 39d0edb..a48879f 100644
--- a/ipapython/ipaldap.py
+++ b/ipapython/ipaldap.py
@@ -1521,14 +1521,14 @@ class LDAPClient(object):
 
         assert isinstance(dn, DN)
 
-        (entry, truncated) = self.find_entries(
+        (entries, truncated) = self.find_entries(
             None, attrs_list, dn, self.SCOPE_BASE, time_limit=time_limit,
             size_limit=size_limit
         )
 
         if truncated:
             raise errors.LimitsExceeded()
-        return entry[0]
+        return entries[0]
 
     def _get_dn_and_attrs(self, entry_or_dn, entry_attrs):
         """Helper for legacy calling style for {add,update}_entry
@@ -1577,7 +1577,7 @@ class LDAPClient(object):
         assert isinstance(dn, DN)
 
         # get original entry
-        dn, entry_attrs_old = self.get_entry(dn, entry_attrs.keys())
+        entry_attrs_old = self.get_entry(dn, entry_attrs.keys())
 
         # generate modlist
         # for multi value attributes: no MOD_REPLACE to handle simultaneous
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
index e5a8d3b..123c2d5 100644
--- a/ipaserver/plugins/dogtag.py
+++ b/ipaserver/plugins/dogtag.py
@@ -1303,9 +1303,7 @@ class ra(rabase.rabase):
             ent, trunc = ldap2.find_entries(filter=filter, base_dn=base_dn)
             if len(ent):
                 entry = random.choice(ent)
-                dn = entry[0]
-                assert isinstance(dn, DN)
-                return dn[1].value
+                return entry.dn[1].value
         except Exception, e:
             pass
         return None
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index fa58b22..97f26ec 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -277,13 +277,13 @@ class ldap2(LDAPClient, CrudBackend):
             # Not in our context yet
             pass
         try:
-            (entry, truncated) = self.find_entries(
+            (entries, truncated) = self.find_entries(
                 None, attrs_list, base_dn=dn, scope=self.SCOPE_BASE,
                 time_limit=2, size_limit=10
             )
             if truncated:
                 raise errors.LimitsExceeded()
-            config_entry = entry[0]
+            config_entry = entries[0]
         except errors.NotFound:
             config_entry = self.make_entry(dn)
         for a in self.config_defaults:
@@ -304,15 +304,15 @@ class ldap2(LDAPClient, CrudBackend):
             upg_entry = self.conn.search_s(upg_dn, _ldap.SCOPE_BASE,
                                            attrlist=['*'])[0]
             disable_attr = '(objectclass=disable)'
-            if 'originfilter' in upg_entry[1]:
-                org_filter = upg_entry[1]['originfilter']
+            if 'originfilter' in upg_entry:
+                org_filter = upg_entry['originfilter']
                 return not bool(re.search(r'%s' % disable_attr, org_filter[0]))
             else:
                 return False
         except _ldap.NO_SUCH_OBJECT, e:
             return False
 
-    def get_effective_rights(self, dn, entry_attrs):
+    def get_effective_rights(self, dn, attrs_list):
         """Returns the rights the currently bound user has for the given DN.
 
            Returns 2 attributes, the attributeLevelRights for the given list of
@@ -322,15 +322,14 @@ class ldap2(LDAPClient, CrudBackend):
         assert isinstance(dn, DN)
 
         principal = getattr(context, 'principal')
-        (binddn, attrs) = self.find_entry_by_attr("krbprincipalname", principal,
+        entry = self.find_entry_by_attr("krbprincipalname", principal,
             "krbPrincipalAux", base_dn=api.env.basedn)
-        assert isinstance(binddn, DN)
-        sctrl = [GetEffectiveRightsControl(True, "dn: " + str(binddn))]
+        sctrl = [GetEffectiveRightsControl(True, "dn: " + str(entry.dn))]
         self.conn.set_option(_ldap.OPT_SERVER_CONTROLS, sctrl)
-        (dn, attrs) = self.get_entry(dn, entry_attrs)
+        entry = self.get_entry(dn, attrs_list)
         # remove the control so subsequent operations don't include GER
         self.conn.set_option(_ldap.OPT_SERVER_CONTROLS, [])
-        return (dn, attrs)
+        return entry
 
     def can_write(self, dn, attr):
         """Returns True/False if the currently bound user has write permissions
@@ -339,7 +338,7 @@ class ldap2(LDAPClient, CrudBackend):
 
         assert isinstance(dn, DN)
 
-        (dn, attrs) = self.get_effective_rights(dn, [attr])
+        attrs = self.get_effective_rights(dn, [attr])
         if 'attributelevelrights' in attrs:
             attr_rights = attrs.get('attributelevelrights')[0].decode('UTF-8')
             (attr, rights) = attr_rights.split(':')
@@ -354,7 +353,7 @@ class ldap2(LDAPClient, CrudBackend):
         """
         assert isinstance(dn, DN)
 
-        (dn, attrs) = self.get_effective_rights(dn, [attr])
+        attrs = self.get_effective_rights(dn, [attr])
         if 'attributelevelrights' in attrs:
             attr_rights = attrs.get('attributelevelrights')[0].decode('UTF-8')
             (attr, rights) = attr_rights.split(':')
@@ -379,7 +378,7 @@ class ldap2(LDAPClient, CrudBackend):
 
         assert isinstance(dn, DN)
 
-        (dn, attrs) = self.get_effective_rights(dn, ["*"])
+        attrs = self.get_effective_rights(dn, ["*"])
         if 'entrylevelrights' in attrs:
             entry_rights = attrs['entrylevelrights'][0].decode('UTF-8')
             if 'd' in entry_rights:
@@ -392,7 +391,7 @@ class ldap2(LDAPClient, CrudBackend):
            on the entry.
         """
         assert isinstance(dn, DN)
-        (dn, attrs) = self.get_effective_rights(dn, ["*"])
+        attrs = self.get_effective_rights(dn, ["*"])
         if 'entrylevelrights' in attrs:
             entry_rights = attrs['entrylevelrights'][0].decode('UTF-8')
             if 'a' in entry_rights:
@@ -478,7 +477,7 @@ class ldap2(LDAPClient, CrudBackend):
         assert isinstance(active, bool)
 
         # get the entry in question
-        (dn, entry_attrs) = self.get_entry(dn, ['nsaccountlock'])
+        entry_attrs = self.get_entry(dn, ['nsaccountlock'])
 
         # check nsAccountLock attribute
         account_lock_attr = entry_attrs.get('nsaccountlock', ['false'])
@@ -495,7 +494,7 @@ class ldap2(LDAPClient, CrudBackend):
         account_lock_attr = str(not active).upper()
 
         entry_attrs['nsaccountlock'] = account_lock_attr
-        self.update_entry(dn, entry_attrs)
+        self.update_entry(entry_attrs)
 
     def activate_entry(self, dn):
         """Mark entry active."""
@@ -529,7 +528,7 @@ class ldap2(LDAPClient, CrudBackend):
 
         assert isinstance(dn, DN)
 
-        (dn, entry_attrs) = self.get_entry(dn, attrs_list)
+        entry_attrs = self.get_entry(dn, attrs_list)
         return entry_attrs
 
     def create(self, **kw):
@@ -542,7 +541,7 @@ class ldap2(LDAPClient, CrudBackend):
         dn = kw['dn']
         assert isinstance(dn, DN)
         del kw['dn']
-        self.add_entry(dn, kw)
+        self.add_entry(self.make_entry(dn, kw))
         return self._get_normalized_entry_for_crud(dn)
 
     def retrieve(self, primary_key, attributes):
@@ -559,7 +558,7 @@ class ldap2(LDAPClient, CrudBackend):
 
         Extends CrudBackend.update.
         """
-        self.update_entry(primary_key, kw)
+        self.update_entry(self.make_entry(primary_key, kw))
         return self._get_normalized_entry_for_crud(primary_key)
 
     def delete(self, primary_key):
@@ -604,7 +603,7 @@ class ldap2(LDAPClient, CrudBackend):
         (entries, truncated) = self.find_entries(
             filter, attrs_list, base_dn, scope
         )
-        for (dn, entry_attrs) in entries:
+        for entry_attrs in entries:
             output.append(entry_attrs)
 
         if truncated:
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index a37d3cd..92ab17d 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -923,7 +923,7 @@ class login_password(Backend, KerberosSession, HTTP_Status):
                 conn.connect(bind_dn=dn, bind_pw=password)
 
                 # password is ok, must be expired, lets double-check
-                (userdn, entry_attrs) = conn.get_entry(dn,
+                entry_attrs = conn.get_entry(dn,
                     ['krbpasswordexpiration'])
                 if 'krbpasswordexpiration' in entry_attrs:
                     expiration = entry_attrs['krbpasswordexpiration'][0]
-- 
1.8.4.2

>From badf34b5a0c64db5729e7533c3ae819cb0068b46 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast redhat com>
Date: Thu, 31 Oct 2013 16:54:21 +0000
Subject: [PATCH 2/6] Convert remaining frontend code to LDAPEntry API.

---
 ipalib/plugins/aci.py            |  13 ++-
 ipalib/plugins/automember.py     |  18 ++---
 ipalib/plugins/automount.py      |  10 +--
 ipalib/plugins/baseldap.py       | 168 +++++++++++++++++++--------------------
 ipalib/plugins/config.py         |   6 +-
 ipalib/plugins/dns.py            |  48 +++++------
 ipalib/plugins/group.py          |  26 +++---
 ipalib/plugins/hbacrule.py       |  28 ++++---
 ipalib/plugins/hbactest.py       |   6 +-
 ipalib/plugins/host.py           |  35 ++++----
 ipalib/plugins/hostgroup.py      |   3 +-
 ipalib/plugins/idrange.py        |  10 +--
 ipalib/plugins/krbtpolicy.py     |   8 +-
 ipalib/plugins/migration.py      |  77 ++++++++----------
 ipalib/plugins/netgroup.py       |   5 +-
 ipalib/plugins/passwd.py         |   6 +-
 ipalib/plugins/permission.py     |  20 ++---
 ipalib/plugins/pkinit.py         |   5 +-
 ipalib/plugins/pwpolicy.py       |  10 +--
 ipalib/plugins/realmdomains.py   |   6 +-
 ipalib/plugins/selinuxusermap.py |  27 ++++---
 ipalib/plugins/service.py        |  15 ++--
 ipalib/plugins/sudocmd.py        |   8 +-
 ipalib/plugins/sudorule.py       |  34 ++++----
 ipalib/plugins/trust.py          |  10 +--
 ipalib/plugins/user.py           |  45 ++++++-----
 ipalib/util.py                   |   2 +-
 ipaserver/dcerpc.py              |  18 ++---
 28 files changed, 326 insertions(+), 341 deletions(-)

diff --git a/ipalib/plugins/aci.py b/ipalib/plugins/aci.py
index 328effc..89f55b0 100644
--- a/ipalib/plugins/aci.py
+++ b/ipalib/plugins/aci.py
@@ -367,17 +367,16 @@ def _aci_to_kw(ldap, a, test=False, pkey_only=False):
         groupdn = DN(groupdn)
         if len(groupdn) and groupdn[0].attr == 'cn':
             dn = DN()
-            entry = {}
+            entry = ldap.make_entry(dn)
             try:
                 entry = ldap.get_entry(groupdn, ['cn'])
-                dn = entry.dn
             except errors.NotFound, e:
                 # FIXME, use real name here
                 if test:
                     dn = DN(('cn', 'test'), api.env.container_permission,
                             api.env.basedn)
-                    entry = {'cn': [u'test']}
-            if api.env.container_permission in dn:
+                    entry = ldap.make_entry(dn, {'cn': [u'test']})
+            if api.env.container_permission in entry.dn:
                 kw['permission'] = entry['cn'][0]
             else:
                 if 'cn' in entry:
@@ -539,7 +538,6 @@ class aci_add(crud.Create):
         newaci = _make_aci(ldap, None, aciname, kw)
 
         entry = ldap.get_entry(self.api.env.basedn, ['aci'])
-        dn = entry.dn
 
         acis = _convert_strings_to_acis(entry.get('aci', []))
         for a in acis:
@@ -584,7 +582,6 @@ class aci_del(crud.Delete):
         ldap = self.api.Backend.ldap2
 
         entry = ldap.get_entry(self.api.env.basedn, ['aci'])
-        dn = entry.dn
 
         acistrs = entry.get('aci', [])
         acis = _convert_strings_to_acis(acistrs)
@@ -704,7 +701,6 @@ class aci_find(crud.Search):
         ldap = self.api.Backend.ldap2
 
         entry = ldap.get_entry(self.api.env.basedn, ['aci'])
-        dn = entry.dn
 
         acis = _convert_strings_to_acis(entry.get('aci', []))
         results = []
@@ -754,7 +750,8 @@ class aci_find(crud.Search):
                 pass
             else:
                 for a in acis:
-                    if a.bindrule['expression'] != ('ldap:///%s' % dn):
+                    uri = 'ldap:///%s' % entry.dn
+                    if a.bindrule['expression'] != uri:
                         results.remove(a)
                 acis = list(results)
 
diff --git a/ipalib/plugins/automember.py b/ipalib/plugins/automember.py
index 71f9a83..a12bfb5 100644
--- a/ipalib/plugins/automember.py
+++ b/ipalib/plugins/automember.py
@@ -300,7 +300,7 @@ class automember_add_condition(LDAPUpdate):
         assert isinstance(dn, DN)
         # Check to see if the automember rule exists
         try:
-            (tdn, test_attrs) = ldap.get_entry(dn, [])
+            dn = ldap.get_entry(dn, []).dn
         except errors.NotFound:
             raise errors.NotFound(reason=_(u'Auto member rule: %s not found!') % keys[0])
         # Define container key
@@ -318,7 +318,7 @@ class automember_add_condition(LDAPUpdate):
                 entry_attrs[attr] = [key + condition for condition in options[attr]]
                 completed += len(entry_attrs[attr])
                 try:
-                    (dn, old_entry) = ldap.get_entry(dn, [attr])
+                    old_entry = ldap.get_entry(dn, [attr])
                     for regex in old_entry.keys():
                         if not isinstance(entry_attrs[regex], (list, tuple)):
                             entry_attrs[regex] = [entry_attrs[regex]]
@@ -339,7 +339,7 @@ class automember_add_condition(LDAPUpdate):
 
         # Make sure to returned the failed results if there is nothing to remove
         if completed == 0:
-            (dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
+            ldap.get_entry(dn, attrs_list)
             raise errors.EmptyModlist
         return dn
 
@@ -386,7 +386,7 @@ class automember_remove_condition(LDAPUpdate):
         assert isinstance(dn, DN)
         # Check to see if the automember rule exists
         try:
-            (tdn, test_attrs) = ldap.get_entry(dn, [])
+            ldap.get_entry(dn, [])
         except errors.NotFound:
             raise errors.NotFound(reason=_(u'Auto member rule: %s not found!') % keys[0])
 
@@ -402,13 +402,13 @@ class automember_remove_condition(LDAPUpdate):
         failed = {'failed': {}}
 
         # Check to see if there are existing exclusive conditions present.
-        (dn, exclude_present) = ldap.get_entry(dn, [EXCLUDE_RE])
+        dn = ldap.get_entry(dn, [EXCLUDE_RE]).dn
 
         for attr in (INCLUDE_RE, EXCLUDE_RE):
             failed['failed'][attr] = []
             if attr in options and options[attr]:
                 entry_attrs[attr] = [key + condition for condition in options[attr]]
-                (dn, entry_attrs_) = ldap.get_entry(dn, [attr])
+                entry_attrs_ = ldap.get_entry(dn, [attr])
                 old_entry = entry_attrs_.get(attr, [])
                 for regex in entry_attrs[attr]:
                     if regex in old_entry:
@@ -427,7 +427,7 @@ class automember_remove_condition(LDAPUpdate):
 
         # Make sure to returned the failed results if there is nothing to remove
         if completed == 0:
-            (dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
+            ldap.get_entry(dn, attrs_list)
             raise errors.EmptyModlist
         return dn
 
@@ -557,13 +557,13 @@ class automember_default_group_remove(LDAPUpdate):
                 api.env.basedn)
         attr = 'automemberdefaultgroup'
 
-        (dn, entry_attrs_) = ldap.get_entry(dn, [attr])
+        entry_attrs_ = ldap.get_entry(dn, [attr])
 
         if attr not in entry_attrs_:
             raise errors.NotFound(reason=_(u'No default (fallback) group set'))
         else:
             entry_attrs[attr] = []
-        return dn
+        return entry_attrs_.dn
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         assert isinstance(dn, DN)
diff --git a/ipalib/plugins/automount.py b/ipalib/plugins/automount.py
index a7596b4..4b94a59 100644
--- a/ipalib/plugins/automount.py
+++ b/ipalib/plugins/automount.py
@@ -603,11 +603,11 @@ class automountmap_del(LDAPDelete):
         assert isinstance(dn, DN)
         # delete optional parental connection (direct maps may not have this)
         try:
-            (dn_, entry_attrs) = ldap.find_entry_by_attr(
+            entry_attrs = ldap.find_entry_by_attr(
                 'automountinformation', keys[0], 'automount',
                 base_dn=DN(self.obj.container_dn, api.env.basedn)
             )
-            ldap.delete_entry(dn_)
+            ldap.delete_entry(entry_attrs)
         except errors.NotFound:
             pass
         return True
@@ -715,7 +715,7 @@ class automountkey(LDAPObject):
         # First we look with the information given, then try to search for
         # the right entry.
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, ['*'])
+            dn = ldap.get_entry(dn, ['*']).dn
         except errors.NotFound:
             if kwargs.get('automountinformation', False):
                 sfilter = '(&(automountkey=%s)(automountinformation=%s))' % \
@@ -732,7 +732,7 @@ class automountkey(LDAPObject):
                 raise errors.NotFound(reason=_('More than one entry with key %(key)s found, use --info to select specific entry.') % dict(key=pkey))
             if truncated:
                 raise errors.LimitsExceeded()
-            dn = entries[0][0]
+            dn = entries[0].dn
 
         return dn
 
@@ -955,7 +955,7 @@ class automountkey_mod(LDAPUpdate):
                 # automountinformation attribute of existing LDAP object needs
                 # to be retrieved so that RDN can be generated
                 dn = self.obj.get_dn(*keys, **options)
-                (dn_, entry_attrs_) = ldap.get_entry(dn, ['automountinformation'])
+                entry_attrs_ = ldap.get_entry(dn, ['automountinformation'])
                 new_info = entry_attrs_.get('automountinformation', [])[0]
 
             # automounkey attribute cannot be overwritten so that get_dn()
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index eab8d74..3d401e4 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -203,8 +203,8 @@ def get_effective_rights(ldap, dn, attrs=None):
         attrs = ['*', 'nsaccountlock', 'cospriority']
     rights = ldap.get_effective_rights(dn, attrs)
     rdict = {}
-    if 'attributelevelrights' in rights[1]:
-        rights = rights[1]['attributelevelrights']
+    if 'attributelevelrights' in rights:
+        rights = rights['attributelevelrights']
         rights = rights[0].split(', ')
         for r in rights:
             (k,v) = r.split(':')
@@ -262,7 +262,7 @@ def wait_for_value(ldap, dn, attr, value):
 
         # FIXME: put a try/except around here? I think it is probably better
         # to just let the exception filter up to the caller.
-        (dn, entry_attrs) = ldap.get_entry( dn, ['*'])
+        entry_attrs = ldap.get_entry(dn, ['*'])
         if attr in entry_attrs:
             if isinstance(entry_attrs[attr], (list, tuple)):
                 values = map(lambda y:y.lower(), entry_attrs[attr])
@@ -332,8 +332,8 @@ def add_external_post_callback(memberattr, membertype, externalattr, ldap, compl
     # Sift through the failures. We assume that these are all
     # entries that aren't stored in IPA, aka external entries.
     if memberattr in failed and membertype in failed[memberattr]:
-        (dn, entry_attrs_) = ldap.get_entry(dn, [externalattr])
-        assert isinstance(dn, DN)
+        entry_attrs_ = ldap.get_entry(dn, [externalattr])
+        dn = entry_attrs_.dn
         members = entry_attrs.get(memberattr, [])
         external_entries = entry_attrs_.get(externalattr, [])
         lc_external_entries = set(e.lower() for e in external_entries)
@@ -364,8 +364,9 @@ def add_external_post_callback(memberattr, membertype, externalattr, ldap, compl
                 failed_entries.append(membername)
 
         if completed_external:
+            entry_attrs_[externalattr] = external_entries
             try:
-                ldap.update_entry(dn, {externalattr: external_entries})
+                ldap.update_entry(entry_attrs_)
             except errors.EmptyModlist:
                 pass
             failed[memberattr][membertype] = failed_entries
@@ -378,7 +379,8 @@ def remove_external_post_callback(memberattr, membertype, externalattr, ldap, co
     # Run through the failures and gracefully remove any member defined
     # as an external member.
     if memberattr in failed and membertype in failed[memberattr]:
-        (dn, entry_attrs_) = ldap.get_entry(dn, [externalattr])
+        entry_attrs_ = ldap.get_entry(dn, [externalattr])
+        dn = entry_attrs_.dn
         external_entries = entry_attrs_.get(externalattr, [])
         failed_entries = []
         completed_external = 0
@@ -398,8 +400,9 @@ def remove_external_post_callback(memberattr, membertype, externalattr, ldap, co
                 failed_entries.append(membername)
 
         if completed_external:
+            entry_attrs_[externalattr] = external_entries
             try:
-                ldap.update_entry(dn, {externalattr: external_entries})
+                ldap.update_entry(entry_attrs_)
             except errors.EmptyModlist:
                 pass
             failed[memberattr][membertype] = failed_entries
@@ -415,7 +418,7 @@ def host_is_master(ldap, fqdn):
     """
     master_dn = DN(('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
     try:
-        (dn, entry_attrs) = ldap.get_entry(master_dn, ['objectclass'])
+        ldap.get_entry(master_dn, ['objectclass'])
         raise errors.ValidationError(name='hostname', error=_('An IPA master host cannot be deleted or disabled'))
     except errors.NotFound:
         # Good, not a master
@@ -478,14 +481,14 @@ class LDAPObject(Object):
             parent_dn = DN(self.container_dn, api.env.basedn)
         if self.rdn_attribute:
             try:
-                (dn, entry_attrs) = self.backend.find_entry_by_attr(
+                entry_attrs = self.backend.find_entry_by_attr(
                     self.primary_key.name, keys[-1], self.object_class, [''],
                     DN(self.container_dn, api.env.basedn)
                 )
             except errors.NotFound:
                 pass
             else:
-                return dn
+                return entry_attrs.dn
         if self.primary_key and keys[-1] is not None:
             return self.backend.make_dn_from_attr(
                 self.primary_key.name, keys[-1], parent_dn
@@ -502,7 +505,7 @@ class LDAPObject(Object):
         assert isinstance(dn, DN)
         try:
             if self.rdn_attribute:
-                (dn, entry_attrs) = self.backend.get_entry(
+                entry_attrs = self.backend.get_entry(
                     dn, [self.primary_key.name]
                 )
                 try:
@@ -609,7 +612,7 @@ class LDAPObject(Object):
             json_dict['primary_key'] = self.primary_key.name
         objectclasses = self.object_class
         if self.object_class_config:
-            config = ldap.get_ipa_config()[1]
+            config = ldap.get_ipa_config()
             objectclasses = config.get(
                 self.object_class_config, objectclasses
             )
@@ -872,7 +875,7 @@ last, after all sets and adds."""),
 
         if needldapattrs:
             try:
-                (dn, old_entry) = self._exc_wrapper(keys, options, ldap.get_entry)(
+                old_entry = self._exc_wrapper(keys, options, ldap.get_entry)(
                     dn, needldapattrs
                 )
             except errors.NotFound:
@@ -1004,15 +1007,16 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
     def execute(self, *keys, **options):
         ldap = self.obj.backend
 
-        entry_attrs = self.args_options_2_entry(*keys, **options)
-        entry_attrs = ldap.make_entry(DN(), entry_attrs)
+        dn = self.obj.get_dn(*keys, **options)
+        entry_attrs = ldap.make_entry(
+            dn, self.args_options_2_entry(*keys, **options))
 
         self.process_attr_options(entry_attrs, None, keys, options)
 
         entry_attrs['objectclass'] = deepcopy(self.obj.object_class)
 
         if self.obj.object_class_config:
-            config = ldap.get_ipa_config()[1]
+            config = ldap.get_ipa_config()
             entry_attrs['objectclass'] = config.get(
                 self.obj.object_class_config, entry_attrs['objectclass']
             )
@@ -1020,8 +1024,6 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
         if self.obj.uuid_attribute:
             entry_attrs[self.obj.uuid_attribute] = 'autogenerate'
 
-        dn = self.obj.get_dn(*keys, **options)
-        assert isinstance(dn, DN)
         if self.obj.rdn_attribute:
             try:
                 dn_attr = dn[0].attr
@@ -1029,10 +1031,9 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
                 dn_attr = None
             if dn_attr != self.obj.primary_key.name:
                 self.obj.handle_duplicate_entry(*keys)
-            dn = ldap.make_dn(
+            entry_attrs.dn = ldap.make_dn(
                 entry_attrs, self.obj.rdn_attribute,
-                DN(self.obj.container_dn, api.env.basedn)
-            )
+                DN(self.obj.container_dn, api.env.basedn))
 
         if options.get('all', False):
             attrs_list = ['*'] + self.obj.default_attributes
@@ -1044,16 +1045,16 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
             attrs_list = list(attrs_list)
 
         for callback in self.get_callbacks('pre'):
-            dn = callback(
-                self, ldap, dn, entry_attrs, attrs_list, *keys, **options)
-            assert isinstance(dn, DN)
+            entry_attrs.dn = callback(
+                self, ldap, entry_attrs.dn, entry_attrs, attrs_list,
+                *keys, **options)
 
         _check_single_value_attrs(self.params, entry_attrs)
         _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.limit_object_classes), entry_attrs.keys(), allow_only=True)
         _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.disallow_object_classes), entry_attrs.keys(), allow_only=False)
 
         try:
-            self._exc_wrapper(keys, options, ldap.add_entry)(dn, entry_attrs)
+            self._exc_wrapper(keys, options, ldap.add_entry)(entry_attrs)
         except errors.NotFound:
             parent = self.obj.parent_object
             if parent:
@@ -1078,25 +1079,23 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
                     object_class = self.obj.object_class
                 else:
                     object_class = None
-                (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.find_entry_by_attr)(
+                entry_attrs = self._exc_wrapper(keys, options, ldap.find_entry_by_attr)(
                     self.obj.primary_key.name, keys[-1], object_class, attrs_list,
                     DN(self.obj.container_dn, api.env.basedn)
                 )
-                assert isinstance(dn, DN)
             else:
-                (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)(
-                    dn, attrs_list
-                )
-                assert isinstance(dn, DN)
+                entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(
+                    entry_attrs.dn, attrs_list)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
         for callback in self.get_callbacks('post'):
-            dn = callback(self, ldap, dn, entry_attrs, *keys, **options)
+            entry_attrs.dn = callback(
+                self, ldap, entry_attrs.dn, entry_attrs, *keys, **options)
 
         self.obj.convert_attribute_members(entry_attrs, *keys, **options)
 
-        assert isinstance(dn, DN)
+        dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
         entry_attrs['dn'] = dn
 
@@ -1204,23 +1203,23 @@ class LDAPRetrieve(LDAPQuery):
             assert isinstance(dn, DN)
 
         try:
-            (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)(
+            entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(
                 dn, attrs_list
             )
-            assert isinstance(dn, DN)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
         if options.get('rights', False) and options.get('all', False):
-            entry_attrs['attributelevelrights'] = get_effective_rights(ldap, dn)
+            entry_attrs['attributelevelrights'] = get_effective_rights(
+                ldap, entry_attrs.dn)
 
         for callback in self.get_callbacks('post'):
-            dn = callback(self, ldap, dn, entry_attrs, *keys, **options)
-            assert isinstance(dn, DN)
+            entry_attrs.dn = callback(
+                self, ldap, entry_attrs.dn, entry_attrs, *keys, **options)
 
         self.obj.convert_attribute_members(entry_attrs, *keys, **options)
 
-        assert isinstance(dn, DN)
+        dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
         entry_attrs['dn'] = dn
 
@@ -1282,10 +1281,7 @@ class LDAPUpdate(LDAPQuery, crud.Update):
             raise errors.EmptyModlist()
 
         dn = self.obj.get_dn(*keys, **options)
-        assert isinstance(dn, DN)
-
-        entry_attrs = self.args_options_2_entry(**options)
-        entry_attrs = ldap.make_entry(dn, entry_attrs)
+        entry_attrs = ldap.make_entry(dn, self.args_options_2_entry(**options))
 
         self.process_attr_options(entry_attrs, dn, keys, options)
 
@@ -1302,9 +1298,9 @@ class LDAPUpdate(LDAPQuery, crud.Update):
         _check_empty_attrs(self.obj.params, entry_attrs)
 
         for callback in self.get_callbacks('pre'):
-            dn = callback(
-                self, ldap, dn, entry_attrs, attrs_list, *keys, **options)
-            assert isinstance(dn, DN)
+            entry_attrs.dn = callback(
+                self, ldap, entry_attrs.dn, entry_attrs, attrs_list,
+                *keys, **options)
 
         _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.limit_object_classes), entry_attrs.keys(), allow_only=True)
         _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.disallow_object_classes), entry_attrs.keys(), allow_only=False)
@@ -1318,11 +1314,12 @@ class LDAPUpdate(LDAPQuery, crud.Update):
 
             if self.obj.rdn_is_primary_key and self.obj.primary_key.name in entry_attrs:
                 # RDN change
-                self._exc_wrapper(keys, options, ldap.update_entry_rdn)(dn,
-                    RDN((self.obj.primary_key.name, entry_attrs[self.obj.primary_key.name])))
+                self._exc_wrapper(keys, options, ldap.update_entry_rdn)(
+                    entry_attrs.dn,
+                    RDN((self.obj.primary_key.name,
+                         entry_attrs[self.obj.primary_key.name])))
                 rdnkeys = keys[:-1] + (entry_attrs[self.obj.primary_key.name], )
-                dn = self.obj.get_dn(*rdnkeys)
-                assert isinstance(dn, DN)
+                entry_attrs.dn = self.obj.get_dn(*rdnkeys)
                 del entry_attrs[self.obj.primary_key.name]
                 options['rdnupdate'] = True
                 rdnupdate = True
@@ -1331,8 +1328,7 @@ class LDAPUpdate(LDAPQuery, crud.Update):
             # to decide what to do. An EmptyModlist in this context doesn't
             # mean an error occurred, just that there were no other updates to
             # perform.
-            assert isinstance(dn, DN)
-            self._exc_wrapper(keys, options, ldap.update_entry)(dn, entry_attrs)
+            self._exc_wrapper(keys, options, ldap.update_entry)(entry_attrs)
         except errors.EmptyModlist, e:
             if not rdnupdate:
                 raise e
@@ -1340,20 +1336,20 @@ class LDAPUpdate(LDAPQuery, crud.Update):
             self.obj.handle_not_found(*keys)
 
         try:
-            (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)(
-                dn, attrs_list
-            )
+            entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(
+                entry_attrs.dn, attrs_list)
         except errors.NotFound:
             raise errors.MidairCollision(
                 format=_('the entry was deleted while being modified')
             )
 
         if options.get('rights', False) and options.get('all', False):
-            entry_attrs['attributelevelrights'] = get_effective_rights(ldap, dn)
+            entry_attrs['attributelevelrights'] = get_effective_rights(
+                ldap, entry_attrs.dn)
 
         for callback in self.get_callbacks('post'):
-            dn = callback(self, ldap, dn, entry_attrs, *keys, **options)
-            assert isinstance(dn, DN)
+            entry_attrs.dn = callback(
+                self, ldap, entry_attrs.dn, entry_attrs, *keys, **options)
 
         self.obj.convert_attribute_members(entry_attrs, *keys, **options)
 
@@ -1409,8 +1405,8 @@ class LDAPDelete(LDAPMultiQuery):
                     except errors.NotFound:
                         break
                     else:
-                        for (dn_, entry_attrs) in subentries:
-                            delete_subtree(dn_)
+                        for entry_attrs in subentries:
+                            delete_subtree(entry_attrs.dn)
                 try:
                     self._exc_wrapper(nkeys, options, ldap.delete_entry)(base_dn)
                 except errors.NotFound:
@@ -1572,21 +1568,20 @@ class LDAPAddMember(LDAPModMember):
             attrs_list = list(attrs_list)
 
         try:
-            (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)(
+            entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(
                 dn, attrs_list
             )
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
         for callback in self.get_callbacks('post'):
-            (completed, dn) = callback(
-                self, ldap, completed, failed, dn, entry_attrs, *keys,
-                **options)
-            assert isinstance(dn, DN)
+            (completed, entry_attrs.dn) = callback(
+                self, ldap, completed, failed, entry_attrs.dn, entry_attrs,
+                *keys, **options)
 
         self.obj.convert_attribute_members(entry_attrs, *keys, **options)
 
-        assert isinstance(dn, DN)
+        dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
         entry_attrs['dn'] = dn
 
@@ -1675,21 +1670,20 @@ class LDAPRemoveMember(LDAPModMember):
         time.sleep(.3)
 
         try:
-            (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)(
+            entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(
                 dn, attrs_list
             )
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
         for callback in self.get_callbacks('post'):
-            (completed, dn) = callback(
-                self, ldap, completed, failed, dn, entry_attrs, *keys,
-                **options)
-            assert isinstance(dn, DN)
+            (completed, entry_attrs.dn) = callback(
+                self, ldap, completed, failed, entry_attrs.dn, entry_attrs,
+                *keys, **options)
 
         self.obj.convert_attribute_members(entry_attrs, *keys, **options)
 
-        assert isinstance(dn, DN)
+        dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
         entry_attrs['dn'] = dn
 
@@ -1852,7 +1846,7 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
         else:
             search_attrs = self.obj.default_attributes
         if self.obj.search_attributes_config:
-            config = ldap.get_ipa_config()[1]
+            config = ldap.get_ipa_config()
             config_attrs = config.get(
                 self.obj.search_attributes_config, [])
             if len(config_attrs) == 1 and (
@@ -1894,12 +1888,12 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
         if self.sort_result_entries:
             if self.obj.primary_key:
                 def sort_key(x):
-                    return x[1][self.obj.primary_key.name][0].lower()
+                    return x[self.obj.primary_key.name][0].lower()
                 entries.sort(key=sort_key)
 
         if not options.get('raw', False):
             for e in entries:
-                self.obj.convert_attribute_members(e[1], *args, **options)
+                self.obj.convert_attribute_members(e, *args, **options)
 
         for (i, e) in enumerate(entries):
             entries[i] = entry_to_dict(e, **options)
@@ -2031,16 +2025,15 @@ class LDAPAddReverseMember(LDAPModReverseMember):
                 failed['member'][self.reverse_attr].append((attr, unicode(msg)))
 
         # Update the member data.
-        (dn, entry_attrs) = ldap.get_entry(dn, ['*'])
+        entry_attrs = ldap.get_entry(dn, ['*'])
         self.obj.convert_attribute_members(entry_attrs, *keys, **options)
 
         for callback in self.get_callbacks('post'):
-            (completed, dn) = callback(
-                self, ldap, completed, failed, dn, entry_attrs, *keys,
-                **options)
-            assert isinstance(dn, DN)
+            (completed, entry_attrs.dn) = callback(
+                self, ldap, completed, failed, entry_attrs.dn, entry_attrs,
+                *keys, **options)
 
-        assert isinstance(dn, DN)
+        dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
         entry_attrs['dn'] = dn
 
@@ -2136,16 +2129,15 @@ class LDAPRemoveReverseMember(LDAPModReverseMember):
                 failed['member'][self.reverse_attr].append((attr, unicode(msg)))
 
         # Update the member data.
-        (dn, entry_attrs) = ldap.get_entry(dn, ['*'])
+        entry_attrs = ldap.get_entry(dn, ['*'])
         self.obj.convert_attribute_members(entry_attrs, *keys, **options)
 
         for callback in self.get_callbacks('post'):
-            (completed, dn) = callback(
-                self, ldap, completed, failed, dn, entry_attrs, *keys,
-                **options)
-            assert isinstance(dn, DN)
+            (completed, entry_attrs.dn) = callback(
+                self, ldap, completed, failed, entry_attrs.dn, entry_attrs,
+                *keys, **options)
 
-        assert isinstance(dn, DN)
+        dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
         entry_attrs['dn'] = dn
 
diff --git a/ipalib/plugins/config.py b/ipalib/plugins/config.py
index e20e5e8..da6b88f 100644
--- a/ipalib/plugins/config.py
+++ b/ipalib/plugins/config.py
@@ -232,7 +232,7 @@ class config_mod(LDAPUpdate):
         if kw:
             config = ldap.get_ipa_config(kw.values())
             for (k, v) in kw.iteritems():
-                allowed_attrs = ldap.get_allowed_attributes(config[1][v])
+                allowed_attrs = ldap.get_allowed_attributes(config[v])
                 fields = entry_attrs[k].split(',')
                 for a in fields:
                     a = a.strip()
@@ -285,7 +285,7 @@ class config_mod(LDAPUpdate):
                                 error=error_message)
 
             else:
-                config = ldap.get_ipa_config()[1]
+                config = ldap.get_ipa_config()
                 defaultuser = config.get('ipaselinuxusermapdefault', [None])[0]
 
             if 'ipaselinuxusermaporder' in entry_attrs:
@@ -307,7 +307,7 @@ class config_mod(LDAPUpdate):
                                 error=error_message)
             else:
                 if not config:
-                    config = ldap.get_ipa_config()[1]
+                    config = ldap.get_ipa_config()
                 order = config['ipaselinuxusermaporder']
                 userlist = order[0].split('$')
             if defaultuser and defaultuser not in userlist:
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index 07523dc..557897f 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -1716,7 +1716,7 @@ class dnszone(LDAPObject):
             test_dn = super(dnszone, self).get_dn(zone, **options)
 
             try:
-                (dn, entry_attrs) = self.backend.get_entry(test_dn, [''])
+                dn = self.backend.get_entry(test_dn, ['']).dn
             except errors.NotFound:
                 pass
 
@@ -1984,7 +1984,7 @@ class dnszone_disable(LDAPQuery):
         dn = self.obj.get_dn(*keys, **options)
 
         try:
-            ldap.update_entry(dn, {'idnszoneactive': 'FALSE'})
+            ldap.update_entry(ldap.make_entry(dn, {'idnszoneactive': 'FALSE'}))
         except errors.EmptyModlist:
             pass
 
@@ -2005,7 +2005,7 @@ class dnszone_enable(LDAPQuery):
         dn = self.obj.get_dn(*keys, **options)
 
         try:
-            ldap.update_entry(dn, {'idnszoneactive': 'TRUE'})
+            ldap.update_entry(ldap.make_entry(dn, {'idnszoneactive': 'TRUE'}))
         except errors.EmptyModlist:
             pass
 
@@ -2024,7 +2024,7 @@ class dnszone_add_permission(LDAPQuery):
         dn = self.obj.get_dn(*keys, **options)
 
         try:
-            (dn_, entry_attrs) = ldap.get_entry(dn, ['objectclass'])
+            entry_attrs = ldap.get_entry(dn, ['objectclass'])
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
@@ -2033,14 +2033,14 @@ class dnszone_add_permission(LDAPQuery):
                          permissiontype=u'SYSTEM'
                      )['result']
 
-        update = {}
+        update = ldap.make_entry(dn)
         dnszone_ocs = entry_attrs.get('objectclass')
         if dnszone_ocs:
             dnszone_ocs.append('ipadnszone')
             update['objectclass'] = list(set(dnszone_ocs))
 
         update['managedby'] = [permission['dn']]
-        ldap.update_entry(dn, update)
+        ldap.update_entry(update)
 
         return dict(
             result=True,
@@ -2060,7 +2060,7 @@ class dnszone_remove_permission(LDAPQuery):
         dn = self.obj.get_dn(*keys, **options)
 
         try:
-            ldap.update_entry(dn, {'managedby': None})
+            ldap.update_entry(ldap.make_entry(dn, {'managedby': None}))
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         except errors.EmptyModlist:
@@ -2177,7 +2177,7 @@ class dnsrecord(LDAPObject):
             # zone must exist
             ldap = self.api.Backend.ldap2
             try:
-                (dn_, zone) = ldap.get_entry(dn, [])
+                ldap.get_entry(dn, [])
             except errors.NotFound:
                 self.api.Object['dnszone'].handle_not_found(keys[-2])
             return self.api.Object[self.parent_object].get_dn(*keys[:-1], **options)
@@ -2200,10 +2200,8 @@ class dnsrecord(LDAPObject):
             entries = ldap.find_entries(filter=ldap_filter, base_dn=base_dn)[0]
 
             for entry in entries:
-                master_dn = entry[0]
-                assert isinstance(master_dn, DN)
                 try:
-                    master = master_dn[1]['cn']
+                    master = entry.dn[1]['cn']
                     dns_masters.append(master)
                 except (IndexError, KeyError):
                     pass
@@ -2227,8 +2225,11 @@ class dnsrecord(LDAPObject):
             raise errors.OptionError(no_option_msg)
 
     def get_record_entry_attrs(self, entry_attrs):
-        return dict((attr, val) for attr,val in entry_attrs.iteritems() \
-                    if attr in self.params and not self.params[attr].primary_key)
+        entry_attrs = entry_attrs.copy()
+        for attr in entry_attrs.keys():
+            if attr not in self.params or self.params[attr].primary_key:
+                del entry_attrs[attr]
+        return entry_attrs
 
     def postprocess_record(self, record, **options):
         if options.get('structured', False):
@@ -2498,7 +2499,7 @@ class dnsrecord_add(LDAPCreate):
         # We always want to retrieve all DNS record attributes to test for
         # record type collisions (#2601)
         try:
-            (dn_, old_entry) = ldap.get_entry(dn, _record_attributes)
+            old_entry = ldap.get_entry(dn, _record_attributes)
         except errors.NotFound:
             old_entry = None
         else:
@@ -2523,9 +2524,8 @@ class dnsrecord_add(LDAPCreate):
                 # Update can be safely run as old record values has been
                 # already merged in pre_callback
                 ldap = self.obj.backend
-                dn = call_args[0]
-                entry_attrs = self.obj.get_record_entry_attrs(call_args[1])
-                ldap.update_entry(dn, entry_attrs, **call_kwargs)
+                entry_attrs = self.obj.get_record_entry_attrs(call_args[0])
+                ldap.update_entry(entry_attrs, **call_kwargs)
                 return
         raise exc
 
@@ -2592,7 +2592,7 @@ class dnsrecord_mod(LDAPUpdate):
         # current entry is needed in case of per-dns-record-part updates and
         # for record type collision check
         try:
-            (dn_, old_entry) = ldap.get_entry(dn, _record_attributes)
+            old_entry = ldap.get_entry(dn, _record_attributes)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
@@ -2627,7 +2627,7 @@ class dnsrecord_mod(LDAPUpdate):
                 keys = keys[:-1] + (rename,)
             dn = self.obj.get_dn(*keys, **options)
             ldap = self.obj.backend
-            (dn_, old_entry) = ldap.get_entry(dn, _record_attributes)
+            old_entry = ldap.get_entry(dn, _record_attributes)
 
             del_all = True
             for attr in old_entry.keys():
@@ -2744,7 +2744,7 @@ class dnsrecord_del(LDAPUpdate):
     def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (dn_, old_entry) = ldap.get_entry(dn, _record_attributes)
+            old_entry = ldap.get_entry(dn, _record_attributes)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
@@ -2910,10 +2910,10 @@ class dnsrecord_find(LDAPSearch):
         if entries:
             zone_obj = self.api.Object[self.obj.parent_object]
             zone_dn = zone_obj.get_dn(args[0])
-            if entries[0][0] == zone_dn:
-                entries[0][1][zone_obj.primary_key.name] = [_dns_zone_record]
+            if entries[0].dn == zone_dn:
+                entries[0][zone_obj.primary_key.name] = [_dns_zone_record]
             for entry in entries:
-                self.obj.postprocess_record(entry[1], **options)
+                self.obj.postprocess_record(entry, **options)
 
         return truncated
 
@@ -3016,7 +3016,7 @@ class dnsconfig(LDAPObject):
         return DN(api.env.container_dns, api.env.basedn)
 
     def get_dnsconfig(self, ldap):
-        (dn, entry) = ldap.get_entry(self.get_dn(), None)
+        entry = ldap.get_entry(self.get_dn(), None)
 
         return entry
 
diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py
index 02eeb10..8429797 100644
--- a/ipalib/plugins/group.py
+++ b/ipalib/plugins/group.py
@@ -217,7 +217,7 @@ class group_del(LDAPDelete):
 
     def pre_callback(self, ldap, dn, *keys, **options):
         assert isinstance(dn, DN)
-        config = ldap.get_ipa_config()[1]
+        config = ldap.get_ipa_config()
         def_primary_group = config.get('ipadefaultprimarygroup', '')
         def_primary_group_dn = group_dn = self.obj.get_dn(def_primary_group)
         if dn == def_primary_group_dn:
@@ -272,7 +272,8 @@ class group_mod(LDAPUpdate):
                     reason=u'Cannot be renamed')
 
         if ('posix' in options and options['posix']) or 'gidnumber' in options:
-            (dn, old_entry_attrs) = ldap.get_entry(dn, ['objectclass'])
+            old_entry_attrs = ldap.get_entry(dn, ['objectclass'])
+            dn = old_entry_attrs.dn
             if 'ipaexternalgroup' in old_entry_attrs['objectclass']:
                 raise errors.ExternalGroupViolation()
             if 'posixgroup' in old_entry_attrs['objectclass']:
@@ -288,7 +289,8 @@ class group_mod(LDAPUpdate):
             if is_protected_group:
                 raise errors.ProtectedEntryError(label=u'group', key=keys[-1],
                     reason=u'Cannot support external non-IPA members')
-            (dn, old_entry_attrs) = ldap.get_entry(dn, ['objectclass'])
+            old_entry_attrs = ldap.get_entry(dn, ['objectclass'])
+            dn = old_entry_attrs.dn
             if 'posixgroup' in old_entry_attrs['objectclass']:
                 raise errors.PosixGroupViolation()
             if 'ipaexternalgroup' in old_entry_attrs['objectclass']:
@@ -367,7 +369,7 @@ class group_find(LDAPSearch):
 
             # filter based on 'criteria' argument
             search_kw = {}
-            config = ldap.get_ipa_config()[1]
+            config = ldap.get_ipa_config()
             attrs = config.get(self.obj.search_attributes_config, [])
             if len(attrs) == 1 and isinstance(attrs[0], basestring):
                 search_attrs = attrs[0].split(',')
@@ -505,7 +507,7 @@ class group_detach(LDAPQuery):
         user_dn = self.api.Object['user'].get_dn(*keys)
 
         try:
-            (user_dn, user_attrs) = ldap.get_entry(user_dn)
+            user_attrs = ldap.get_entry(user_dn)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         is_managed = self.obj.has_objectclass(user_attrs['objectclass'], 'mepmanagedentry')
@@ -513,7 +515,7 @@ class group_detach(LDAPQuery):
             not (ldap.can_write(user_dn, "mepManagedEntry")) and is_managed):
             raise errors.ACIError(info=_('not allowed to modify user entries'))
 
-        (group_dn, group_attrs) = ldap.get_entry(group_dn)
+        group_attrs = ldap.get_entry(group_dn)
         is_managed = self.obj.has_objectclass(group_attrs['objectclass'], 'mepmanagedby')
         if (not ldap.can_write(group_dn, "objectclass") or
             not (ldap.can_write(group_dn, "mepManagedBy")) and is_managed):
@@ -523,14 +525,14 @@ class group_detach(LDAPQuery):
         try:
             i = objectclasses.index('mepOriginEntry')
             del objectclasses[i]
-            update_attrs = {'objectclass': objectclasses, 'mepManagedEntry': None}
-            ldap.update_entry(user_dn, update_attrs)
+            user_attrs['mepManagedEntry'] = None
+            ldap.update_entry(user_attrs)
         except ValueError:
             # Somehow the user isn't managed, let it pass for now. We'll
             # let the group throw "Not managed".
             pass
 
-        (group_dn, group_attrs) = ldap.get_entry(group_dn)
+        group_attrs = ldap.get_entry(group_dn)
         objectclasses = group_attrs['objectclass']
         try:
             i = objectclasses.index('mepManagedEntry')
@@ -540,14 +542,14 @@ class group_detach(LDAPQuery):
         del objectclasses[i]
 
         # Make sure the resulting group has the default group objectclasses
-        config = ldap.get_ipa_config()[1]
+        config = ldap.get_ipa_config()
         def_objectclass = config.get(
             self.obj.object_class_config, objectclasses
         )
         objectclasses = list(set(def_objectclass + objectclasses))
 
-        update_attrs = {'objectclass': objectclasses, 'mepManagedBy': None}
-        ldap.update_entry(group_dn, update_attrs)
+        group_attrs['mepManagedBy'] = None
+        ldap.update_entry(group_attrs)
 
         return dict(
             result=True,
diff --git a/ipalib/plugins/hbacrule.py b/ipalib/plugins/hbacrule.py
index 5cc8bc1..618d10c 100644
--- a/ipalib/plugins/hbacrule.py
+++ b/ipalib/plugins/hbacrule.py
@@ -253,7 +253,8 @@ class hbacrule_mod(LDAPUpdate):
     def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
+            entry_attrs = ldap.get_entry(dn, attrs_list)
+            dn = entry_attrs.dn
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
@@ -294,10 +295,10 @@ class hbacrule_enable(LDAPQuery):
         ldap = self.obj.backend
 
         dn = self.obj.get_dn(cn)
-        entry_attrs = {'ipaenabledflag': 'TRUE'}
+        entry_attrs = ldap.make_entry(dn, {'ipaenabledflag': 'TRUE'})
 
         try:
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except errors.EmptyModlist:
             pass
         except errors.NotFound:
@@ -321,10 +322,10 @@ class hbacrule_disable(LDAPQuery):
         ldap = self.obj.backend
 
         dn = self.obj.get_dn(cn)
-        entry_attrs = {'ipaenabledflag': 'FALSE'}
+        entry_attrs = ldap.make_entry(dn, {'ipaenabledflag': 'FALSE'})
 
         try:
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except errors.EmptyModlist:
             pass
         except errors.NotFound:
@@ -355,12 +356,12 @@ class hbacrule_add_accesstime(LDAPQuery):
 
         dn = self.obj.get_dn(cn)
 
-        (dn, entry_attrs) = ldap.get_entry(dn, ['accesstime'])
+        entry_attrs = ldap.get_entry(dn, ['accesstime'])
         entry_attrs.setdefault('accesstime', []).append(
             options['accesstime']
         )
         try:
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except errors.EmptyModlist:
             pass
         except errors.NotFound:
@@ -395,12 +396,12 @@ class hbacrule_remove_accesstime(LDAPQuery):
 
         dn = self.obj.get_dn(cn)
 
-        (dn, entry_attrs) = ldap.get_entry(dn, ['accesstime'])
+        entry_attrs = ldap.get_entry(dn, ['accesstime'])
         try:
             entry_attrs.setdefault('accesstime', []).remove(
                 options['accesstime']
             )
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except (ValueError, errors.EmptyModlist):
             pass
         except errors.NotFound:
@@ -428,7 +429,8 @@ class hbacrule_add_user(LDAPAddMember):
     def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
+            dn = entry_attrs.dn
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if 'usercategory' in entry_attrs and \
@@ -458,7 +460,8 @@ class hbacrule_add_host(LDAPAddMember):
     def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
+            dn = entry_attrs.dn
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if 'hostcategory' in entry_attrs and \
@@ -512,7 +515,8 @@ class hbacrule_add_service(LDAPAddMember):
     def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
+            dn = entry_attrs.dn
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if 'servicecategory' in entry_attrs and \
diff --git a/ipalib/plugins/hbactest.py b/ipalib/plugins/hbactest.py
index fed39b0..efbdf5a 100644
--- a/ipalib/plugins/hbactest.py
+++ b/ipalib/plugins/hbactest.py
@@ -405,9 +405,9 @@ class hbactest(Command):
                     request.user.groups = []
                 else:
                     groups = []
-                    for dn, entry in entries:
-                        if dn.endswith(group_container):
-                            groups.append(dn[0][0].value)
+                    for entry in entries:
+                        if entry.dn.endswith(group_container):
+                            groups.append(entry.dn[0][0].value)
                     request.user.groups = sorted(set(groups))
             else:
                 # try searching for a local user
diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index ef7ec52..3dc4e23 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -340,9 +340,10 @@ class host(LDAPObject):
             self.backend.get_entry(dn, [''])
         except errors.NotFound:
             try:
-                (dn, entry_attrs) = self.backend.find_entry_by_attr(
+                entry_attrs = self.backend.find_entry_by_attr(
                     'serverhostname', hostname, self.object_class, [''],
                     DN(self.container_dn, api.env.basedn))
+                dn = entry_attrs.dn
             except errors.NotFound:
                 pass
         return dn
@@ -359,7 +360,7 @@ class host(LDAPObject):
                 filter=host_filter, attrs_list=host_attrs)
 
             for host in hosts:
-                managed_hosts.append(host[0])
+                managed_hosts.append(host.dn)
         except errors.NotFound:
             return []
 
@@ -581,7 +582,7 @@ class host_del(LDAPDelete):
 
         if self.api.env.enable_ra:
             try:
-                (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate'])
+                entry_attrs = ldap.get_entry(dn, ['usercertificate'])
             except errors.NotFound:
                 self.obj.handle_not_found(*keys)
             cert = entry_attrs.single_value.get('usercertificate')
@@ -651,7 +652,7 @@ class host_mod(LDAPUpdate):
         if 'locality' in entry_attrs:
             entry_attrs['l'] = entry_attrs['locality']
         if 'krbprincipalname' in entry_attrs:
-            (dn, entry_attrs_old) = ldap.get_entry(
+            entry_attrs_old = ldap.get_entry(
                 dn, ['objectclass', 'krbprincipalname']
             )
             if 'krbprincipalname' in entry_attrs_old:
@@ -665,7 +666,7 @@ class host_mod(LDAPUpdate):
         if cert:
             if self.api.env.enable_ra:
                 x509.verify_cert_subject(ldap, keys[-1], cert)
-                (dn, entry_attrs_old) = ldap.get_entry(dn, ['usercertificate'])
+                entry_attrs_old = ldap.get_entry(dn, ['usercertificate'])
                 oldcert = entry_attrs_old.single_value.get('usercertificate')
                 if oldcert:
                     oldcert = x509.normalize_certificate(oldcert)
@@ -703,9 +704,7 @@ class host_mod(LDAPUpdate):
             if 'objectclass' in entry_attrs:
                 obj_classes = entry_attrs['objectclass']
             else:
-                (_dn, _entry_attrs) = ldap.get_entry(
-                    dn, ['objectclass']
-                )
+                _entry_attrs = ldap.get_entry(dn, ['objectclass'])
                 obj_classes = _entry_attrs['objectclass']
             if 'ieee802device' not in obj_classes:
                 obj_classes.append('ieee802device')
@@ -725,7 +724,7 @@ class host_mod(LDAPUpdate):
             if 'objectclass' in entry_attrs:
                 obj_classes = entry_attrs['objectclass']
             else:
-                (_dn, _entry_attrs) = ldap.get_entry(dn, ['objectclass'])
+                _entry_attrs = ldap.get_entry(dn, ['objectclass'])
                 obj_classes = entry_attrs['objectclass'] = _entry_attrs['objectclass']
             if 'ipasshhost' not in obj_classes:
                 obj_classes.append('ipasshhost')
@@ -792,7 +791,7 @@ class host_find(LDAPSearch):
                 for pkey in options.get('man_host', []):
                     dn = self.obj.get_dn(pkey)
                     try:
-                        (dn, entry_attrs) = ldap.get_entry(dn, ['managedby'])
+                        entry_attrs = ldap.get_entry(dn, ['managedby'])
                     except errors.NotFound:
                         self.obj.handle_not_found(pkey)
                     hosts.append(set(entry_attrs.get('managedby', '')))
@@ -809,7 +808,7 @@ class host_find(LDAPSearch):
                 for pkey in options.get('not_man_host', []):
                     dn = self.obj.get_dn(pkey)
                     try:
-                        (dn, entry_attrs) = ldap.get_entry(dn, ['managedby'])
+                        entry_attrs = ldap.get_entry(dn, ['managedby'])
                     except errors.NotFound:
                         self.obj.handle_not_found(pkey)
                     not_hosts += entry_attrs.get('managedby', [])
@@ -830,11 +829,10 @@ class host_find(LDAPSearch):
     def post_callback(self, ldap, entries, truncated, *args, **options):
         if options.get('pkey_only', False):
             return truncated
-        for entry in entries:
-            (dn, entry_attrs) = entry
+        for entry_attrs in entries:
             set_certificate_attrs(entry_attrs)
             set_kerberos_attrs(entry_attrs, options)
-            self.obj.get_password_attributes(ldap, dn, entry_attrs)
+            self.obj.get_password_attributes(ldap, entry_attrs.dn, entry_attrs)
             self.obj.suppress_netgroup_memberof(ldap, entry_attrs)
             if entry_attrs['has_password']:
                 # If an OTP is set there is no keytab, at least not one
@@ -842,9 +840,9 @@ class host_find(LDAPSearch):
                 entry_attrs['has_keytab'] = False
 
             if options.get('all', False):
-                entry_attrs['managing'] = self.obj.get_managed_hosts(entry[0])
+                entry_attrs['managing'] = self.obj.get_managed_hosts(entry_attrs.dn)
 
-            convert_sshpubkey_post(ldap, dn, entry_attrs)
+            convert_sshpubkey_post(ldap, entry_attrs.dn, entry_attrs)
 
         return truncated
 
@@ -941,7 +939,7 @@ class host_disable(LDAPQuery):
 
         dn = self.obj.get_dn(*keys, **options)
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate'])
+            entry_attrs = ldap.get_entry(dn, ['usercertificate'])
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         cert = entry_attrs.single_value.get('usercertificate')
@@ -972,7 +970,8 @@ class host_disable(LDAPQuery):
                         raise nsprerr
 
             # Remove the usercertificate altogether
-            ldap.update_entry(dn, {'usercertificate': None})
+            entry_attrs['usercertificate'] = None
+            ldap.update_entry(entry_attrs)
             done_work = True
 
         self.obj.get_password_attributes(ldap, dn, entry_attrs)
diff --git a/ipalib/plugins/hostgroup.py b/ipalib/plugins/hostgroup.py
index 8a49573..4b8702b 100644
--- a/ipalib/plugins/hostgroup.py
+++ b/ipalib/plugins/hostgroup.py
@@ -188,8 +188,7 @@ class hostgroup_find(LDAPSearch):
         if options.get('pkey_only', False):
             return truncated
         for entry in entries:
-            (dn, entry_attrs) = entry
-            self.obj.suppress_netgroup_memberof(ldap, dn, entry_attrs)
+            self.obj.suppress_netgroup_memberof(ldap, entry.dn, entry)
         return truncated
 
 api.register(hostgroup_find)
diff --git a/ipalib/plugins/idrange.py b/ipalib/plugins/idrange.py
index cf74a75..3a92d98 100644
--- a/ipalib/plugins/idrange.py
+++ b/ipalib/plugins/idrange.py
@@ -551,9 +551,9 @@ class idrange_del(LDAPDelete):
 
     def pre_callback(self, ldap, dn, *keys, **options):
         try:
-            (old_dn, old_attrs) = ldap.get_entry(dn, ['ipabaseid',
-                                                      'ipaidrangesize',
-                                                      'ipanttrusteddomainsid'])
+            old_attrs = ldap.get_entry(dn, ['ipabaseid',
+                                            'ipaidrangesize',
+                                            'ipanttrusteddomainsid'])
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
@@ -595,7 +595,7 @@ class idrange_find(LDAPSearch):
         return (filters, base_dn, ldap.SCOPE_ONELEVEL)
 
     def post_callback(self, ldap, entries, truncated, *args, **options):
-        for dn, entry in entries:
+        for entry in entries:
             self.obj.handle_iparangetype(entry, options)
         return truncated
 
@@ -629,7 +629,7 @@ class idrange_mod(LDAPUpdate):
         attrs_list.append('objectclass')
 
         try:
-            (old_dn, old_attrs) = ldap.get_entry(dn, ['*'])
+            old_attrs = ldap.get_entry(dn, ['*'])
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
diff --git a/ipalib/plugins/krbtpolicy.py b/ipalib/plugins/krbtpolicy.py
index a383d68..329e1e4 100644
--- a/ipalib/plugins/krbtpolicy.py
+++ b/ipalib/plugins/krbtpolicy.py
@@ -157,24 +157,24 @@ class krbtpolicy_reset(LDAPQuery):
 
         dn = self.obj.get_dn(*keys, **options)
 
-        def_values = {}
+        def_values = ldap.make_entry(dn)
         # if reseting policy for a user - just his values
         if keys[-1] is not None:
             for a in self.obj.default_attributes:
                 def_values[a] = None
         # if reseting global policy - set values to default
         else:
-            def_values = _default_values
+            def_values.update(_default_values)
 
         try:
-            ldap.update_entry(dn, def_values)
+            ldap.update_entry(def_values)
         except errors.EmptyModlist:
             pass
 
         if keys[-1] is not None:
             # policy for user was deleted, retrieve global policy
             dn = self.obj.get_dn(None)
-        (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+        entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
 
         entry_attrs = entry_to_dict(entry_attrs, **options)
 
diff --git a/ipalib/plugins/migration.py b/ipalib/plugins/migration.py
index a89e944..c3ee2ab 100644
--- a/ipalib/plugins/migration.py
+++ b/ipalib/plugins/migration.py
@@ -158,7 +158,7 @@ def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs
                          % (entry_attrs['gidnumber'][0], pkey))
         elif entry_attrs['gidnumber'][0] not in valid_gids:
             try:
-                (remote_dn, remote_entry) = ds_ldap.find_entry_by_attr(
+                remote_entry = ds_ldap.find_entry_by_attr(
                     'gidnumber', entry_attrs['gidnumber'][0], 'posixgroup',
                     [''], search_bases['group']
                 )
@@ -238,7 +238,7 @@ def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs
                                 pkey, value, type(value), attr, e)
                         continue
                 try:
-                    (remote_dn, remote_entry) = ds_ldap.get_entry(value, [api.Object.user.primary_key.name, api.Object.group.primary_key.name])
+                    remote_entry = ds_ldap.get_entry(value, [api.Object.user.primary_key.name, api.Object.group.primary_key.name])
                 except errors.NotFound:
                     api.log.warn('%s: attribute %s refers to non-existent entry %s' % (pkey, attr, value))
                     continue
@@ -270,9 +270,10 @@ def _post_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx):
 
     if 'description' in entry_attrs and NO_UPG_MAGIC in entry_attrs['description']:
         entry_attrs['description'].remove(NO_UPG_MAGIC)
-        update_attrs = dict(description = entry_attrs['description'])
+        update_attrs = ldap.make_entry(
+            dn, description=entry_attrs['description'])
         try:
-            ldap.update_entry(dn, update_attrs)
+            ldap.update_entry(update_attrs)
         except (errors.EmptyModlist, errors.NotFound):
             pass
 
@@ -292,17 +293,17 @@ def _update_default_group(ldap, pkey, config, ctx, force):
         except errors.NotFound:
             return
         new_members = []
-        (group_dn, group_entry_attrs) = ldap.get_entry(group_dn, ['member'])
+        group_entry_attrs = ldap.get_entry(group_dn, ['member'])
         for m in result:
-            if m[0] not in group_entry_attrs.get('member', []):
-                new_members.append(m[0])
+            if m.dn not in group_entry_attrs.get('member', []):
+                new_members.append(m.dn)
         if len(new_members) > 0:
             members = group_entry_attrs.get('member', [])
             members.extend(new_members)
             group_entry_attrs['member'] = members
 
             try:
-                ldap.update_entry(group_dn, group_entry_attrs)
+                ldap.update_entry(group_entry_attrs)
             except errors.EmptyModlist:
                 pass
 
@@ -406,8 +407,9 @@ def _group_exc_callback(ldap, dn, entry_attrs, exc, options):
         if options.get('groupoverwritegid', False) and \
            entry_attrs.get('gidnumber') is not None:
             try:
-                new_entry_attrs = {'gidnumber':entry_attrs['gidnumber']}
-                ldap.update_entry(dn, new_entry_attrs)
+                new_entry_attrs = ldap.make_entry(
+                    dn, {'gidnumber':entry_attrs['gidnumber']})
+                ldap.update_entry(new_entry_attrs)
             except errors.EmptyModlist:
                 # no change to the GID
                 pass
@@ -747,7 +749,7 @@ can use their Kerberos accounts.''')
                 def_group = config.get('ipadefaultprimarygroup')
                 context['def_group_dn'] = api.Object.group.get_dn(def_group)
                 try:
-                    (g_dn, g_attrs) = ldap.get_entry(context['def_group_dn'], ['gidnumber', 'cn'])
+                    g_attrs = ldap.get_entry(context['def_group_dn'], ['gidnumber', 'cn'])
                 except errors.NotFound:
                     error_msg = _('Default group for new users not found')
                     raise errors.NotFound(reason=error_msg)
@@ -760,20 +762,11 @@ can use their Kerberos accounts.''')
             invalid_gids = []
             migrate_cnt = 0
             context['migrate_cnt'] = 0
-            for (dn, entry_attrs) in entries:
+            for entry_attrs in entries:
                 context['migrate_cnt'] = migrate_cnt
                 s = datetime.datetime.now()
-                if dn is None:  # LDAP search reference
-                    failed[ldap_obj_name][entry_attrs[0]] = unicode(_ref_err_msg)
-                    continue
 
-                try:
-                    dn = DN(dn)
-                except ValueError:
-                    failed[ldap_obj_name][dn] = unicode(_dn_err_msg)
-                    continue
-
-                ava = dn[0][0]
+                ava = entry_attrs.dn[0][0]
                 if ava.attr == ldap_obj.primary_key.name:
                     # In case if pkey attribute is in the migrated object DN
                     # and the original LDAP is multivalued, make sure that
@@ -785,8 +778,7 @@ can use their Kerberos accounts.''')
                 if pkey in exclude:
                     continue
 
-                dn = ldap_obj.get_dn(pkey)
-                assert isinstance(dn, DN)
+                entry_attrs.dn = ldap_obj.get_dn(pkey)
                 entry_attrs['objectclass'] = list(
                     set(
                         config.get(
@@ -799,28 +791,29 @@ can use their Kerberos accounts.''')
                 callback = self.migrate_objects[ldap_obj_name]['pre_callback']
                 if callable(callback):
                     try:
-                        dn = callback(
-                            ldap, pkey, dn, entry_attrs, failed[ldap_obj_name],
-                            config, context, schema = options['schema'],
-                            search_bases = search_bases,
-                            valid_gids = valid_gids,
-                            invalid_gids = invalid_gids,
+                        entry_attrs.dn = callback(
+                            ldap, pkey, entry_attrs.dn, entry_attrs,
+                            failed[ldap_obj_name], config, context,
+                            schema=options['schema'],
+                            search_bases=search_bases,
+                            valid_gids=valid_gids,
+                            invalid_gids=invalid_gids,
                             **blacklists
                         )
-                        assert isinstance(dn, DN)
-                        if not dn:
+                        if not entry_attrs.dn:
                             continue
                     except errors.NotFound, e:
                         failed[ldap_obj_name][pkey] = unicode(e.reason)
                         continue
 
                 try:
-                    ldap.add_entry(dn, entry_attrs)
+                    ldap.add_entry(entry_attrs)
                 except errors.ExecutionError, e:
                     callback = self.migrate_objects[ldap_obj_name]['exc_callback']
                     if callable(callback):
                         try:
-                            callback(ldap, dn, entry_attrs, e, options)
+                            callback(
+                                ldap, entry_attrs.dn, entry_attrs, e, options)
                         except errors.ExecutionError, e:
                             failed[ldap_obj_name][pkey] = unicode(e)
                             continue
@@ -833,9 +826,8 @@ can use their Kerberos accounts.''')
                 callback = self.migrate_objects[ldap_obj_name]['post_callback']
                 if callable(callback):
                     callback(
-                        ldap, pkey, dn, entry_attrs, failed[ldap_obj_name],
-                        config, context,
-                    )
+                        ldap, pkey, entry_attrs.dn, entry_attrs,
+                        failed[ldap_obj_name], config, context)
                 e = datetime.datetime.now()
                 d = e - s
                 total_dur = e - migration_start
@@ -851,7 +843,7 @@ can use their Kerberos accounts.''')
     def execute(self, ldapuri, bindpw, **options):
         ldap = self.api.Backend.ldap2
         self.normalize_options(options)
-        config = ldap.get_ipa_config()[1]
+        config = ldap.get_ipa_config()
 
         ds_base_dn = options.get('basedn')
         if ds_base_dn is not None:
@@ -881,8 +873,7 @@ can use their Kerberos accounts.''')
         #check whether the compat plugin is enabled
         if not options.get('compat'):
             try:
-                (dn,check_compat) = ldap.get_entry(_compat_dn)
-                assert isinstance(dn, DN)
+                check_compat = ldap.get_entry(_compat_dn)
                 if check_compat is not None and \
                         check_compat.get('nsslapd-pluginenabled', [''])[0].lower() == 'on':
                     return dict(result={}, failed={}, enabled=True, compat=False)
@@ -895,12 +886,12 @@ can use their Kerberos accounts.''')
                 '', ['namingcontexts', 'defaultnamingcontext'], DN(''),
                 ds_ldap.SCOPE_BASE, size_limit=-1, time_limit=0,
             )
-            if 'defaultnamingcontext' in entries[0][1]:
-                ds_base_dn = DN(entries[0][1]['defaultnamingcontext'][0])
+            if 'defaultnamingcontext' in entries[0]:
+                ds_base_dn = DN(entries[0]['defaultnamingcontext'][0])
                 assert isinstance(ds_base_dn, DN)
             else:
                 try:
-                    ds_base_dn = DN(entries[0][1]['namingcontexts'][0])
+                    ds_base_dn = DN(entries[0]['namingcontexts'][0])
                     assert isinstance(ds_base_dn, DN)
                 except (IndexError, KeyError), e:
                     raise StandardError(str(e))
diff --git a/ipalib/plugins/netgroup.py b/ipalib/plugins/netgroup.py
index 84bc749..e454b9a 100644
--- a/ipalib/plugins/netgroup.py
+++ b/ipalib/plugins/netgroup.py
@@ -167,7 +167,7 @@ class netgroup_add(LDAPCreate):
 
         try:
             test_dn = self.obj.get_dn(keys[-1])
-            (test_dn_, netgroup) = ldap.get_entry(test_dn, ['objectclass'])
+            netgroup = ldap.get_entry(test_dn, ['objectclass'])
             if 'mepManagedEntry' in netgroup.get('objectclass', []):
                 raise errors.DuplicateEntry(message=unicode(self.msg_collision % keys[-1]))
             else:
@@ -206,7 +206,8 @@ class netgroup_mod(LDAPUpdate):
     def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
+            entry_attrs = ldap.get_entry(dn, attrs_list)
+            dn = entry_attrs.dn
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if is_all(options, 'usercategory') and 'memberuser' in entry_attrs:
diff --git a/ipalib/plugins/passwd.py b/ipalib/plugins/passwd.py
index 280517c..2581a46 100644
--- a/ipalib/plugins/passwd.py
+++ b/ipalib/plugins/passwd.py
@@ -103,7 +103,7 @@ class passwd(Command):
         """
         ldap = self.api.Backend.ldap2
 
-        (dn, entry_attrs) = ldap.find_entry_by_attr(
+        entry_attrs = ldap.find_entry_by_attr(
             'krbprincipalname', principal, 'posixaccount', [''],
             DN(api.env.container_user, api.env.basedn)
         )
@@ -115,9 +115,9 @@ class passwd(Command):
             raise errors.ACIError(info=_('Invalid credentials'))
 
         if current_password == MAGIC_VALUE:
-            ldap.modify_password(dn, password)
+            ldap.modify_password(entry_attrs.dn, password)
         else:
-            ldap.modify_password(dn, password, current_password)
+            ldap.modify_password(entry_attrs.dn, password, current_password)
 
         return dict(
             result=True,
diff --git a/ipalib/plugins/permission.py b/ipalib/plugins/permission.py
index 0f1fe66..4f6d921 100644
--- a/ipalib/plugins/permission.py
+++ b/ipalib/plugins/permission.py
@@ -186,7 +186,7 @@ class permission(LDAPObject):
     # Don't allow SYSTEM permissions to be modified or removed
     def check_system(self, ldap, dn, *keys):
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, ['ipapermissiontype'])
+            entry_attrs = ldap.get_entry(dn, ['ipapermissiontype'])
         except errors.NotFound:
             self.handle_not_found(*keys)
         if 'ipapermissiontype' in entry_attrs:
@@ -332,7 +332,8 @@ class permission_mod(LDAPUpdate):
 
         # check if permission is in LDAP
         try:
-            (dn, attrs) = ldap.get_entry(dn, attrs_list)
+            attrs = ldap.get_entry(dn, attrs_list)
+            dn = attrs.dn
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
@@ -347,7 +348,7 @@ class permission_mod(LDAPUpdate):
                     except (IndexError, KeyError), e:
                         raise ValueError("expected dn starting with 'cn=' but got '%s'" % dn)
                     new_dn[0].value = options['rename']
-                    entry = ldap.get_entry(new_dn, attrs_list)
+                    ldap.get_entry(new_dn, [''])
                     raise errors.DuplicateEntry()
                 except errors.NotFound:
                     pass    # permission may be renamed, continue
@@ -423,8 +424,7 @@ class permission_find(LDAPSearch):
 
         pkey_only = options.pop('pkey_only', False)
         if not pkey_only:
-            for entry in entries:
-                (dn, attrs) = entry
+            for attrs in entries:
                 try:
                     common_options = filter_options(options, ['all', 'raw'])
                     aci = self.api.Command.aci_show(attrs['cn'][0],
@@ -443,7 +443,7 @@ class permission_find(LDAPSearch):
         if 'sizelimit' in options:
             max_entries = options['sizelimit']
         else:
-            config = ldap.get_ipa_config()[1]
+            config = ldap.get_ipa_config()
             max_entries = config['ipasearchrecordslimit']
 
         # Now find all the ACIs that match. Once we find them, add any that
@@ -461,8 +461,7 @@ class permission_find(LDAPSearch):
         for aci in results:
             found = False
             if 'permission' in aci:
-                for entry in entries:
-                    (dn, attrs) = entry
+                for attrs in entries:
                     if aci['permission'] == attrs['cn'][0]:
                         found = True
                         break
@@ -472,13 +471,14 @@ class permission_find(LDAPSearch):
                         aci['permission'], **common_options)['result']
                     dn = permission['dn']
                     del permission['dn']
+                    permission = ldap.make_entry(dn, permission)
                     if pkey_only:
                         pk = self.obj.primary_key.name
                         new_entry = ldap.make_entry(dn, {pk: permission[pk]})
                     else:
-                        new_entry = ldap.make_entry(dn, permission)
+                        new_entry = permission
 
-                    if (dn, permission) not in entries:
+                    if permission not in entries:
                        if len(entries) < max_entries:
                            entries.append(new_entry)
                        else:
diff --git a/ipalib/plugins/pkinit.py b/ipalib/plugins/pkinit.py
index 981e411..30c9120 100644
--- a/ipalib/plugins/pkinit.py
+++ b/ipalib/plugins/pkinit.py
@@ -79,7 +79,7 @@ class pkinit_anonymous(Command):
         set_lock = False
         lock = None
 
-        (dn, entry_attrs) = ldap.get_entry(self.default_dn, ['nsaccountlock'])
+        entry_attrs = ldap.get_entry(self.default_dn, ['nsaccountlock'])
 
         if 'nsaccountlock' in entry_attrs:
             lock = entry_attrs['nsaccountlock'][0].lower()
@@ -94,7 +94,8 @@ class pkinit_anonymous(Command):
                 lock = 'TRUE'
 
         if set_lock:
-            ldap.update_entry(dn, {'nsaccountlock':lock})
+            entry_attrs['nsaccountlock'] = lock
+            ldap.update_entry(entry_attrs)
 
         return dict(result=True)
 
diff --git a/ipalib/plugins/pwpolicy.py b/ipalib/plugins/pwpolicy.py
index da24f7c..46e839a 100644
--- a/ipalib/plugins/pwpolicy.py
+++ b/ipalib/plugins/pwpolicy.py
@@ -478,13 +478,13 @@ class pwpolicy_find(LDAPSearch):
         returns a pair: (is_global, priority)
         """
         # global policy will be always last in the output
-        if entry[1]['cn'][0] == global_policy_name:
+        if entry['cn'][0] == global_policy_name:
             return True, 0
         else:
             # policies with higher priority (lower number) will be at the
             # beginning of the list
             try:
-                cospriority = int(entry[1]['cospriority'][0])
+                cospriority = int(entry['cospriority'][0])
             except KeyError:
                 # if cospriority is not present in the entry, rather return 0
                 # than crash
@@ -496,9 +496,9 @@ class pwpolicy_find(LDAPSearch):
             # When pkey_only flag is on, entries should contain only a cn.
             # Add a cospriority attribute that will be used for sorting.
             # Attribute rights are not allowed for pwpolicy_find.
-            self.obj.add_cospriority(e[1], e[1]['cn'][0], rights=False)
+            self.obj.add_cospriority(e, e['cn'][0], rights=False)
 
-            self.obj.convert_time_for_output(e[1], **options)
+            self.obj.convert_time_for_output(e, **options)
 
         # do custom entry sorting by its cospriority
         entries.sort(key=self.priority_sort_key)
@@ -507,7 +507,7 @@ class pwpolicy_find(LDAPSearch):
             # remove cospriority that was used for sorting
             for e in entries:
                 try:
-                    del e[1]['cospriority']
+                    del e['cospriority']
                 except KeyError:
                     pass
 
diff --git a/ipalib/plugins/realmdomains.py b/ipalib/plugins/realmdomains.py
index cff193f..1928e48 100644
--- a/ipalib/plugins/realmdomains.py
+++ b/ipalib/plugins/realmdomains.py
@@ -120,7 +120,7 @@ class realmdomains_mod(LDAPUpdate):
 
         # If --add-domain or --del-domain options were provided, read
         # the curent list from LDAP, modify it, and write the changes back
-        domains = ldap.get_entry(dn)[1]['associateddomain']
+        domains = ldap.get_entry(dn)['associateddomain']
 
         if add_domain:
             if not force and not has_soa_or_ns_record(add_domain):
@@ -144,9 +144,9 @@ class realmdomains_mod(LDAPUpdate):
         dn = self.obj.get_dn(*keys, **options)
         ldap = self.obj.backend
 
-        domains_old = set(ldap.get_entry(dn)[1]['associateddomain'])
+        domains_old = set(ldap.get_entry(dn)['associateddomain'])
         result = super(realmdomains_mod, self).execute(*keys, **options)
-        domains_new = set(ldap.get_entry(dn)[1]['associateddomain'])
+        domains_new = set(ldap.get_entry(dn)['associateddomain'])
 
         domains_added = domains_new - domains_old
         domains_deleted = domains_old - domains_new
diff --git a/ipalib/plugins/selinuxusermap.py b/ipalib/plugins/selinuxusermap.py
index e0e995e..f69e582 100644
--- a/ipalib/plugins/selinuxusermap.py
+++ b/ipalib/plugins/selinuxusermap.py
@@ -112,7 +112,7 @@ def validate_selinuxuser_inlist(ldap, user):
 
     Returns nothing if the user is found, raises an exception otherwise.
     """
-    config = ldap.get_ipa_config()[1]
+    config = ldap.get_ipa_config()
     item = config.get('ipaselinuxusermaporder', [])
     if len(item) != 1:
         raise errors.NotFound(reason=_('SELinux user map list not '
@@ -217,13 +217,13 @@ class selinuxusermap(LDAPObject):
             return str(dn)
         except ValueError:
             try:
-                (dn, entry_attrs) = self.backend.find_entry_by_attr(
+                entry_attrs = self.backend.find_entry_by_attr(
                     self.api.Object['hbacrule'].primary_key.name,
                     seealso,
                     self.api.Object['hbacrule'].object_class,
                     [''],
                     DN(self.api.Object['hbacrule'].container_dn, api.env.basedn))
-                seealso = dn
+                seealso = entry_attrs.dn
             except errors.NotFound:
                 raise errors.NotFound(reason=_('HBAC rule %(rule)s not found') % dict(rule=seealso))
 
@@ -237,7 +237,7 @@ class selinuxusermap(LDAPObject):
             return
 
         if 'seealso' in entry_attrs:
-            (hbac_dn, hbac_attrs) = ldap.get_entry(entry_attrs['seealso'][0], ['cn'])
+            hbac_attrs = ldap.get_entry(entry_attrs['seealso'][0], ['cn'])
             entry_attrs['seealso'] = hbac_attrs['cn'][0]
 
 api.register(selinuxusermap)
@@ -296,7 +296,7 @@ class selinuxusermap_mod(LDAPUpdate):
     def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (_dn, _entry_attrs) = ldap.get_entry(dn, attrs_list)
+            _entry_attrs = ldap.get_entry(dn, attrs_list)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
@@ -369,8 +369,7 @@ all=True)['result']
     def post_callback(self, ldap, entries, truncated, *args, **options):
         if options.get('pkey_only', False):
             return truncated
-        for entry in entries:
-            (dn, attrs) = entry
+        for attrs in entries:
             self.obj._convert_seealso(ldap, attrs, **options)
         return truncated
 
@@ -398,10 +397,10 @@ class selinuxusermap_enable(LDAPQuery):
         ldap = self.obj.backend
 
         dn = self.obj.get_dn(cn)
-        entry_attrs = {'ipaenabledflag': 'TRUE'}
+        entry_attrs = ldap.make_entry(dn, {'ipaenabledflag': 'TRUE'})
 
         try:
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except errors.EmptyModlist:
             raise errors.AlreadyActive()
         except errors.NotFound:
@@ -425,10 +424,10 @@ class selinuxusermap_disable(LDAPQuery):
         ldap = self.obj.backend
 
         dn = self.obj.get_dn(cn)
-        entry_attrs = {'ipaenabledflag': 'FALSE'}
+        entry_attrs = ldap.make_entry(dn, {'ipaenabledflag': 'FALSE'})
 
         try:
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except errors.EmptyModlist:
             raise errors.AlreadyInactive()
         except errors.NotFound:
@@ -451,7 +450,8 @@ class selinuxusermap_add_user(LDAPAddMember):
     def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
+            dn = entry_attrs.dn
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if 'usercategory' in entry_attrs and \
@@ -483,7 +483,8 @@ class selinuxusermap_add_host(LDAPAddMember):
     def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
+            dn = entry_attrs.dn
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if 'hostcategory' in entry_attrs and \
diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py
index 50dfbb9..67fbea6 100644
--- a/ipalib/plugins/service.py
+++ b/ipalib/plugins/service.py
@@ -434,7 +434,7 @@ class service_del(LDAPDelete):
         check_required_principal(ldap, hostname, service)
         if self.api.env.enable_ra:
             try:
-                (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate'])
+                entry_attrs = ldap.get_entry(dn, ['usercertificate'])
             except errors.NotFound:
                 self.obj.handle_not_found(*keys)
             cert = entry_attrs.get('usercertificate')
@@ -486,8 +486,7 @@ class service_mod(LDAPUpdate):
                 dercert = x509.normalize_certificate(cert)
                 x509.verify_cert_subject(ldap, hostname, dercert)
                 try:
-                    (dn, entry_attrs_old) = ldap.get_entry(
-                        dn, ['usercertificate'])
+                    entry_attrs_old = ldap.get_entry(dn, ['usercertificate'])
                 except errors.NotFound:
                     self.obj.handle_not_found(*keys)
                 if 'usercertificate' in entry_attrs_old:
@@ -541,9 +540,8 @@ class service_find(LDAPSearch):
     def post_callback(self, ldap, entries, truncated, *args, **options):
         if options.get('pkey_only', False):
             return truncated
-        for entry in entries:
-            (dn, entry_attrs) = entry
-            self.obj.get_password_attributes(ldap, dn, entry_attrs)
+        for entry_attrs in entries:
+            self.obj.get_password_attributes(ldap, entry_attrs.dn, entry_attrs)
             set_certificate_attrs(entry_attrs)
             set_kerberos_attrs(entry_attrs, options)
         return truncated
@@ -615,7 +613,7 @@ class service_disable(LDAPQuery):
         ldap = self.obj.backend
 
         dn = self.obj.get_dn(*keys, **options)
-        (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate'])
+        entry_attrs = ldap.get_entry(dn, ['usercertificate'])
 
         (service, hostname, realm) = split_principal(keys[-1])
         check_required_principal(ldap, hostname, service)
@@ -648,7 +646,8 @@ class service_disable(LDAPQuery):
                         raise nsprerr
 
             # Remove the usercertificate altogether
-            ldap.update_entry(dn, {'usercertificate': None})
+            entry_attrs['usercertificate'] = None
+            ldap.update_entry(entry_attrs)
             done_work = True
 
         self.obj.get_password_attributes(ldap, dn, entry_attrs)
diff --git a/ipalib/plugins/sudocmd.py b/ipalib/plugins/sudocmd.py
index 0c2160c..35c01aa 100644
--- a/ipalib/plugins/sudocmd.py
+++ b/ipalib/plugins/sudocmd.py
@@ -87,10 +87,10 @@ class sudocmd(LDAPObject):
             self.backend.get_entry(dn, [''])
         except errors.NotFound:
             try:
-                (dn, entry_attrs) = self.backend.find_entry_by_attr(
+                entry_attrs = self.backend.find_entry_by_attr(
                     'sudocmd', keys[-1], self.object_class, [''],
-                    DN(self.container_dn, api.env.basedn)
-                )
+                    DN(self.container_dn, api.env.basedn))
+                dn = entry_attrs.dn
             except errors.NotFound:
                 pass
         return dn
@@ -125,7 +125,7 @@ class sudocmd_del(LDAPDelete):
         except errors.NotFound:
             pass
         else:
-            for entry_dn, entry_attrs in entries:
+            for entry_attrs in entries:
                 [cn] = entry_attrs['cn']
                 dependent_sudorules.append(cn)
 
diff --git a/ipalib/plugins/sudorule.py b/ipalib/plugins/sudorule.py
index a89941c..dfdbb20 100644
--- a/ipalib/plugins/sudorule.py
+++ b/ipalib/plugins/sudorule.py
@@ -281,7 +281,7 @@ class sudorule_mod(LDAPUpdate):
             else:
                 self.obj.check_order_uniqueness(*keys, **options)
         try:
-            (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
 
@@ -325,10 +325,10 @@ class sudorule_enable(LDAPQuery):
         ldap = self.obj.backend
 
         dn = self.obj.get_dn(cn)
-        entry_attrs = {'ipaenabledflag': 'TRUE'}
+        entry_attrs = ldap.make_entry(dn, {'ipaenabledflag': 'TRUE'})
 
         try:
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except errors.EmptyModlist:
             pass
         except errors.NotFound:
@@ -349,10 +349,10 @@ class sudorule_disable(LDAPQuery):
         ldap = self.obj.backend
 
         dn = self.obj.get_dn(cn)
-        entry_attrs = {'ipaenabledflag': 'FALSE'}
+        entry_attrs = ldap.make_entry(dn, {'ipaenabledflag': 'FALSE'})
 
         try:
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except errors.EmptyModlist:
             pass
         except errors.NotFound:
@@ -375,7 +375,7 @@ class sudorule_add_allow_command(LDAPAddMember):
     def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if is_all(_entry_attrs, 'cmdcategory'):
@@ -404,7 +404,7 @@ class sudorule_add_deny_command(LDAPAddMember):
     def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if is_all(_entry_attrs, 'cmdcategory'):
@@ -432,7 +432,7 @@ class sudorule_add_user(LDAPAddMember):
     def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if is_all(_entry_attrs, 'usercategory'):
@@ -468,7 +468,7 @@ class sudorule_add_host(LDAPAddMember):
     def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
         assert isinstance(dn, DN)
         try:
-            (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if is_all(_entry_attrs, 'hostcategory'):
@@ -509,7 +509,7 @@ class sudorule_add_runasuser(LDAPAddMember):
             return True
 
         try:
-            (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if is_all(_entry_attrs, 'ipasudorunasusercategory') or \
@@ -566,7 +566,7 @@ class sudorule_add_runasgroup(LDAPAddMember):
             return True
 
         try:
-            (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+            _entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
         except errors.NotFound:
             self.obj.handle_not_found(*keys)
         if is_all(_entry_attrs, 'ipasudorunasusercategory') or \
@@ -620,7 +620,7 @@ class sudorule_add_option(LDAPQuery):
 
         if not options['ipasudoopt'].strip():
             raise errors.EmptyModlist()
-        (dn, entry_attrs) = ldap.get_entry(dn, ['ipasudoopt'])
+        entry_attrs = ldap.get_entry(dn, ['ipasudoopt'])
 
         try:
             if options['ipasudoopt'] not in entry_attrs['ipasudoopt']:
@@ -632,14 +632,14 @@ class sudorule_add_option(LDAPQuery):
             entry_attrs.setdefault('ipasudoopt', []).append(
                 options['ipasudoopt'])
         try:
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except errors.EmptyModlist:
             pass
         except errors.NotFound:
             self.obj.handle_not_found(cn)
 
         attrs_list = self.obj.default_attributes
-        (dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
+        entry_attrs = ldap.get_entry(dn, attrs_list)
 
         entry_attrs = entry_to_dict(entry_attrs, **options)
 
@@ -673,12 +673,12 @@ class sudorule_remove_option(LDAPQuery):
 
         if not options['ipasudoopt'].strip():
             raise errors.EmptyModlist()
-        (dn, entry_attrs) = ldap.get_entry(dn, ['ipasudoopt'])
+        entry_attrs = ldap.get_entry(dn, ['ipasudoopt'])
         try:
             if options['ipasudoopt'] in entry_attrs['ipasudoopt']:
                 entry_attrs.setdefault('ipasudoopt', []).remove(
                     options['ipasudoopt'])
-                ldap.update_entry(dn, entry_attrs)
+                ldap.update_entry(entry_attrs)
             else:
                 raise errors.AttrValueNotFound(
                     attr='ipasudoopt',
@@ -695,7 +695,7 @@ class sudorule_remove_option(LDAPQuery):
             self.obj.handle_not_found(cn)
 
         attrs_list = self.obj.default_attributes
-        (dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
+        entry_attrs = ldap.get_entry(dn, attrs_list)
 
         entry_attrs = entry_to_dict(entry_attrs, **options)
 
diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
index 3b1b2fc..6ef3a33 100644
--- a/ipalib/plugins/trust.py
+++ b/ipalib/plugins/trust.py
@@ -352,7 +352,7 @@ sides.
                          base_dn=DN(api.env.container_trusts, api.env.basedn),
                          filter=trust_filter)
 
-        result['result'] = entry_to_dict(trusts[0][1], **options)
+        result['result'] = entry_to_dict(trusts[0], **options)
 
         # For AD trusts with algorithmic mapping, we need to add a separate
         # range for each subdomain.
@@ -777,9 +777,7 @@ class trust_find(LDAPSearch):
         if options.get('pkey_only', False):
             return truncated
 
-        for entry in entries:
-            (dn, attrs) = entry
-
+        for attrs in entries:
             # Translate ipanttrusttype to trusttype if --raw not used
             if not options.get('raw', False):
                 attrs['trusttype'] = trust_type_string(attrs['ipanttrusttype'][0])
@@ -895,7 +893,7 @@ class trustconfig(LDAPObject):
             # and not "ipausergroup" so that it can also match groups like
             # "Default SMB Group" which does not have this objectclass.
             try:
-                (dn, group_entry) = self.backend.find_entry_by_attr(
+                group_entry = self.backend.find_entry_by_attr(
                     self.api.Object['group'].primary_key.name,
                     group,
                     ['posixgroup'],
@@ -904,7 +902,7 @@ class trustconfig(LDAPObject):
             except errors.NotFound:
                 self.api.Object['group'].handle_not_found(group)
             else:
-                entry_attrs['ipantfallbackprimarygroup'] = [dn]
+                entry_attrs['ipantfallbackprimarygroup'] = [group_entry.dn]
 
     def _convert_groupdn(self, entry_attrs, options):
         """
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index c855145..fda7f42 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -400,7 +400,7 @@ class user(LDAPObject):
 
     def _normalize_and_validate_email(self, email, config=None):
         if not config:
-            config = self.backend.get_ipa_config()[1]
+            config = self.backend.get_ipa_config()
 
         # check if default email domain should be added
         defaultdomain = config.get('ipadefaultemaildomain', [None])[0]
@@ -437,11 +437,11 @@ class user(LDAPObject):
             for m in xrange(len(manager)):
                 if isinstance(manager[m], DN) and manager[m].endswith(container_dn):
                     continue
-                (dn, entry_attrs) = self.backend.find_entry_by_attr(
+                entry_attrs = self.backend.find_entry_by_attr(
                         self.primary_key.name, manager[m], self.object_class, [''],
                         container_dn
                     )
-                manager[m] = dn
+                manager[m] = entry_attrs.dn
         except errors.NotFound:
             raise errors.NotFound(reason=_('manager %(manager)s not found') % dict(manager=manager[m]))
 
@@ -510,7 +510,7 @@ class user_add(LDAPCreate):
                 entry_attrs['gidnumber'] = baseldap.DNA_MAGIC
 
         validate_nsaccountlock(entry_attrs)
-        config = ldap.get_ipa_config()[1]
+        config = ldap.get_ipa_config()
         if 'ipamaxusernamelength' in config:
             if len(keys[-1]) > int(config.get('ipamaxusernamelength')[0]):
                 raise errors.ValidationError(
@@ -545,7 +545,7 @@ class user_add(LDAPCreate):
                 def_primary_group = config.get('ipadefaultprimarygroup')
                 group_dn = self.api.Object['group'].get_dn(def_primary_group)
                 try:
-                    (group_dn, group_attrs) = ldap.get_entry(group_dn, ['gidnumber'])
+                    group_attrs = ldap.get_entry(group_dn, ['gidnumber'])
                 except errors.NotFound:
                     error_msg = _('Default group for new users not found')
                     raise errors.NotFound(reason=error_msg)
@@ -593,7 +593,7 @@ class user_add(LDAPCreate):
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         assert isinstance(dn, DN)
-        config = ldap.get_ipa_config()[1]
+        config = ldap.get_ipa_config()
         # add the user we just created into the default primary group
         def_primary_group = config.get('ipadefaultprimarygroup')
         group_dn = self.api.Object['group'].get_dn(def_primary_group)
@@ -610,7 +610,7 @@ class user_add(LDAPCreate):
         # delete description attribute NO_UPG_MAGIC if present
         if options.get('noprivate', False):
             if not options.get('all', False):
-                (dn, desc_attr) = ldap.get_entry(dn, ['description'])
+                desc_attr = ldap.get_entry(dn, ['description'])
                 entry_attrs.update(desc_attr)
             if 'description' in entry_attrs and NO_UPG_MAGIC in entry_attrs['description']:
                 entry_attrs['description'].remove(NO_UPG_MAGIC)
@@ -622,7 +622,7 @@ class user_add(LDAPCreate):
 
         # Fetch the entry again to update memberof, mep data, etc updated
         # at the end of the transaction.
-        (newdn, newentry) = ldap.get_entry(dn, ['*'])
+        newentry = ldap.get_entry(dn, ['*'])
         entry_attrs.update(newentry)
 
         if options.get('random', False):
@@ -663,7 +663,7 @@ class user_mod(LDAPUpdate):
     def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
         assert isinstance(dn, DN)
         if options.get('rename') is not None:
-            config = ldap.get_ipa_config()[1]
+            config = ldap.get_ipa_config()
             if 'ipamaxusernamelength' in config:
                 if len(options['rename']) > int(config.get('ipamaxusernamelength')[0]):
                     raise errors.ValidationError(
@@ -764,12 +764,11 @@ class user_find(LDAPSearch):
     def post_callback(self, ldap, entries, truncated, *args, **options):
         if options.get('pkey_only', False):
             return truncated
-        for entry in entries:
-            (dn, attrs) = entry
+        for attrs in entries:
             self.obj._convert_manager(attrs, **options)
-            self.obj.get_password_attributes(ldap, dn, attrs)
+            self.obj.get_password_attributes(ldap, attrs.dn, attrs)
             convert_nsaccountlock(attrs)
-            convert_sshpubkey_post(ldap, dn, attrs)
+            convert_sshpubkey_post(ldap, attrs.dn, attrs)
         return truncated
 
     msg_summary = ngettext(
@@ -852,10 +851,12 @@ class user_unlock(LDAPQuery):
     msg_summary = _('Unlocked account "%(value)s"')
 
     def execute(self, *keys, **options):
-        dn = self.obj.get_dn(*keys, **options)
-        entry_attrs = {'krbLastAdminUnlock': strftime("%Y%m%d%H%M%SZ",gmtime()), 'krbLoginFailedCount': '0'}
+        entry = self.obj.backend.make_entry(
+            self.obj.get_dn(*keys, **options),
+            {'krbLastAdminUnlock': strftime("%Y%m%d%H%M%SZ", gmtime()),
+             'krbLoginFailedCount': '0'})
 
-        self.obj.backend.update_entry(dn, entry_attrs)
+        self.obj.backend.update_entry(entry)
 
         return dict(
             result=True,
@@ -911,7 +912,7 @@ class user_status(LDAPQuery):
         entries = []
         count = 0
         for master in masters:
-            host = master[1]['cn'][0]
+            host = master['cn'][0]
             if host == api.env.host:
                 other_ldap = self.obj.backend
             else:
@@ -931,8 +932,8 @@ class user_status(LDAPQuery):
                 entry = other_ldap.get_entry(dn, attr_list)
                 newresult = ldap.make_entry(dn)
                 for attr in ['krblastsuccessfulauth', 'krblastfailedauth']:
-                    newresult[attr] = entry[1].get(attr, [u'N/A'])
-                newresult['krbloginfailedcount'] = entry[1].get('krbloginfailedcount', u'0')
+                    newresult[attr] = entry.get(attr, [u'N/A'])
+                newresult['krbloginfailedcount'] = entry.get('krbloginfailedcount', u'0')
                 if not options.get('raw', False):
                     for attr in ['krblastsuccessfulauth', 'krblastfailedauth']:
                         try:
@@ -949,9 +950,9 @@ class user_status(LDAPQuery):
                 else:
                     time_format = '%Y-%m-%dT%H:%M:%SZ'
                 newresult['now'] = unicode(strftime(time_format, gmtime()))
-                convert_nsaccountlock(entry[1])
-                if 'nsaccountlock' in entry[1].keys():
-                    disabled = entry[1]['nsaccountlock']
+                convert_nsaccountlock(entry)
+                if 'nsaccountlock' in entry:
+                    disabled = entry['nsaccountlock']
                 entries.append(newresult)
                 count += 1
             except errors.NotFound:
diff --git a/ipalib/util.py b/ipalib/util.py
index e140774..1701fbd 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -332,7 +332,7 @@ def convert_sshpubkey_post(ldap, dn, entry_attrs):
         pubkeys = entry_attrs['ipasshpubkey']
     else:
         old_entry_attrs = ldap.get_entry(dn, ['ipasshpubkey'])
-        pubkeys = old_entry_attrs[1].get('ipasshpubkey')
+        pubkeys = old_entry_attrs.get('ipasshpubkey')
     if not pubkeys:
         return
 
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index d809c41..5cc168b 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -143,10 +143,10 @@ class DomainValidator(object):
     def is_configured(self):
         cn_trust_local = DN(('cn', self.api.env.domain), self.api.env.container_cifsdomains, self.api.env.basedn)
         try:
-            (dn, entry_attrs) = self.ldap.get_entry(cn_trust_local, [self.ATTR_FLATNAME, self.ATTR_SID])
+            entry_attrs = self.ldap.get_entry(cn_trust_local, [self.ATTR_FLATNAME, self.ATTR_SID])
             self.flatname = entry_attrs[self.ATTR_FLATNAME][0]
             self.sid = entry_attrs[self.ATTR_SID][0]
-            self.dn = dn
+            self.dn = entry_attrs.dn
             self.domain = self.api.env.domain
         except errors.NotFound, e:
             return False
@@ -175,7 +175,7 @@ class DomainValidator(object):
             # domain names as keys and those are generally case-insensitive
             result = ipautil.CIDict()
 
-            for dn, entry in entries:
+            for entry in entries:
                 try:
                     trust_partner = entry[self.ATTR_TRUST_PARTNER][0]
                     flatname_normalized = entry[self.ATTR_FLATNAME][0].lower()
@@ -184,7 +184,7 @@ class DomainValidator(object):
                     # Some piece of trusted domain info in LDAP is missing
                     # Skip the domain, but leave log entry for investigation
                     api.log.warn("Trusted domain '%s' entry misses an "
-                                 "attribute: %s", dn, e)
+                                 "attribute: %s", entry.dn, e)
                     continue
 
                 result[trust_partner] = (flatname_normalized,
@@ -341,7 +341,7 @@ class DomainValidator(object):
             # Treat non-unique entries as invalid
             raise errors.ValidationError(name=_('trusted domain object'),
                error= _('Trusted domain did not return a unique object'))
-        sid = self.__sid_to_str(entries[0][1]['objectSid'][0])
+        sid = self.__sid_to_str(entries[0]['objectSid'][0])
         try:
             test_sid = security.dom_sid(sid)
             return unicode(test_sid)
@@ -378,7 +378,7 @@ class DomainValidator(object):
                         attrs=attrs, scope=_ldap.SCOPE_SUBTREE)
             except errors.NotFound:
                 raise errors.NotFound(reason=_('trusted domain user not found'))
-            user_dn = entries[0][0]
+            user_dn = entries[0].dn
         elif domain or flatname:
             attrs = ['cn']
             filter = '(&(sAMAccountName=%(name)s)(objectClass=user))' \
@@ -388,7 +388,7 @@ class DomainValidator(object):
                         flatname, filter, attrs, _ldap.SCOPE_SUBTREE)
             except errors.NotFound:
                 raise errors.NotFound(reason=_('trusted domain user not found'))
-            user_dn = entries[0][0]
+            user_dn = entries[0].dn
         else:
             # No domain or realm specified, ambiguous search
             raise errors.ValidationError(name=_('trusted domain object'),
@@ -401,8 +401,8 @@ class DomainValidator(object):
         filter = "(objectClass=user)"
         entries = self.get_trusted_domain_objects(domain,
             flatname, filter, attrs, _ldap.SCOPE_BASE, user_dn)
-        object_sid = self.__sid_to_str(entries[0][1]['objectSid'][0])
-        group_sids = [self.__sid_to_str(sid) for sid in entries[0][1]['tokenGroups']]
+        object_sid = self.__sid_to_str(entries[0]['objectSid'][0])
+        group_sids = [self.__sid_to_str(sid) for sid in entries[0]['tokenGroups']]
         return (object_sid, group_sids)
 
     def get_trusted_domain_user_and_groups(self, object_name):
-- 
1.8.4.2

>From f02134eb40824ab8471852575db2636cd9354b40 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast redhat com>
Date: Thu, 31 Oct 2013 16:54:49 +0000
Subject: [PATCH 3/6] Convert remaining installer code to LDAPEntry API.

---
 .../certmonger/dogtag-ipa-retrieve-agent-submit    |  2 +-
 install/restart_scripts/renew_ca_cert              | 12 ++++----
 install/restart_scripts/renew_ra_cert              | 12 ++++----
 install/tools/ipa-adtrust-install                  | 12 ++++----
 install/tools/ipa-compat-manage                    | 10 +++----
 install/tools/ipa-nis-manage                       | 11 +++----
 install/tools/ipa-server-install                   |  6 ++--
 install/tools/ipactl                               |  2 +-
 ipaserver/install/adtrustinstance.py               |  6 ++--
 ipaserver/install/cainstance.py                    | 35 +++++++++++-----------
 ipaserver/install/ipa_replica_prepare.py           |  2 +-
 11 files changed, 58 insertions(+), 52 deletions(-)

diff --git a/install/certmonger/dogtag-ipa-retrieve-agent-submit b/install/certmonger/dogtag-ipa-retrieve-agent-submit
index 3781fc5..df6b695 100644
--- a/install/certmonger/dogtag-ipa-retrieve-agent-submit
+++ b/install/certmonger/dogtag-ipa-retrieve-agent-submit
@@ -58,7 +58,7 @@ try:
     conn.connect(ccache=ccache)
     try:
         syslog.syslog(syslog.LOG_NOTICE, "Updating certificate for %s" % nickname)
-        (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'])
+        entry_attrs = conn.get_entry(dn, ['usercertificate'])
         cert = entry_attrs['usercertificate'][0]
         cert = base64.b64encode(cert)
         print x509.make_pem(cert)
diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert
index ab394b9..cbe1908 100644
--- a/install/restart_scripts/renew_ca_cert
+++ b/install/restart_scripts/renew_ca_cert
@@ -68,13 +68,15 @@ try:
     conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
     conn.connect(ccache=ccache)
     try:
-        (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'])
+        entry_attrs = conn.get_entry(dn, ['usercertificate'])
         entry_attrs['usercertificate'] = cert
-        conn.update_entry(dn, entry_attrs)
+        conn.update_entry(entry_attrs)
     except errors.NotFound:
-        entry_attrs = dict(objectclass=['top', 'pkiuser', 'nscontainer'],
-                                        usercertificate=cert)
-        conn.add_entry(dn, entry_attrs)
+        entry_attrs = conn.make_entry(
+            dn,
+            objectclass=['top', 'pkiuser', 'nscontainer'],
+            usercertificate=cert)
+        conn.add_entry(entry_attrs)
     except errors.EmptyModlist:
         pass
     conn.disconnect()
diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert
index e541e4b..7c70953 100644
--- a/install/restart_scripts/renew_ra_cert
+++ b/install/restart_scripts/renew_ra_cert
@@ -58,13 +58,15 @@ while attempts < 10:
         conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
         conn.connect(ccache=ccache)
         try:
-            (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'])
+            entry_attrs = conn.get_entry(dn, ['usercertificate'])
             entry_attrs['usercertificate'] = dercert
-            conn.update_entry(dn, entry_attrs)
+            conn.update_entry(entry_attrs)
         except errors.NotFound:
-            entry_attrs = dict(objectclass=['top', 'pkiuser', 'nscontainer'],
-                                            usercertificate=dercert)
-            conn.add_entry(dn, entry_attrs)
+            entry_attrs = conn.make_entry(
+                dn,
+                objectclass=['top', 'pkiuser', 'nscontainer'],
+                usercertificate=dercert)
+            conn.add_entry(entry_attrs)
         except errors.EmptyModlist:
             pass
         updated = True
diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install
index fe86a94..bd6f0b4 100755
--- a/install/tools/ipa-adtrust-install
+++ b/install/tools/ipa-adtrust-install
@@ -118,13 +118,13 @@ def set_and_check_netbios_name(netbios_name, unattended):
     cur_netbios_name = None
     gen_netbios_name = None
     reset_netbios_name = False
-    dom_dn = None
+    entry = None
 
     try:
-        (dom_dn, entry) = api.Backend.ldap2.get_entry(DN(('cn', api.env.domain),
-                                    api.env.container_cifsdomains,
-                                    ipautil.realm_to_suffix(api.env.realm)),
-                                    [flat_name_attr])
+        entry = api.Backend.ldap2.get_entry(
+            DN(('cn', api.env.domain), api.env.container_cifsdomains,
+               ipautil.realm_to_suffix(api.env.realm)),
+            [flat_name_attr])
     except errors.NotFound:
         # trust not configured
         pass
@@ -160,7 +160,7 @@ def set_and_check_netbios_name(netbios_name, unattended):
         if not netbios_name:
             gen_netbios_name = adtrustinstance.make_netbios_name(api.env.domain)
 
-        if dom_dn:
+        if entry is not None:
             # Fix existing trust configuration
             print "Trust is configured but no NetBIOS domain name found, " \
                   "setting it now."
diff --git a/install/tools/ipa-compat-manage b/install/tools/ipa-compat-manage
index 7061a3e..8d2438e 100755
--- a/install/tools/ipa-compat-manage
+++ b/install/tools/ipa-compat-manage
@@ -73,7 +73,7 @@ def get_entry(dn, conn):
     """
     entry = None
     try:
-        (dn, entry) = conn.get_entry(dn)
+        entry = conn.get_entry(dn)
     except errors.NotFound:
         pass
     return entry
@@ -143,8 +143,8 @@ def main():
                             print "Updating Directory Server failed."
                             retval = 1
                     else:
-                        mod = {'nsslapd-pluginenabled': 'on'}
-                        conn.update_entry(compat_dn, mod)
+                        entry['nsslapd-pluginenabled'] = ['on']
+                        conn.update_entry(entry)
             except errors.ExecutionError, lde:
                 print "An error occurred while talking to the server."
                 print lde
@@ -174,8 +174,8 @@ def main():
                     else:
                         print "Disabling plugin"
 
-                        mod = {'nsslapd-pluginenabled': 'off'}
-                        conn.update_entry(compat_dn, mod)
+                        entry['nsslapd-pluginenabled'] = ['off']
+                        conn.update_entry(entry)
                 except errors.DatabaseError, dbe:
                     print "An error occurred while talking to the server."
                     print dbe
diff --git a/install/tools/ipa-nis-manage b/install/tools/ipa-nis-manage
index 71c0761..9c2a411 100755
--- a/install/tools/ipa-nis-manage
+++ b/install/tools/ipa-nis-manage
@@ -75,7 +75,7 @@ def get_entry(dn, conn):
     """
     entry = None
     try:
-        (dn, entry) = conn.get_entry(dn)
+        entry = conn.get_entry(dn)
     except errors.NotFound:
         pass
     return entry
@@ -165,16 +165,17 @@ def main():
             elif entry.get('nsslapd-pluginenabled', [''])[0].lower() == 'off':
                 print "Enabling plugin"
                 # Already configured, just enable the plugin
-                mod = {'nsslapd-pluginenabled': 'on'}
-                conn.update_entry(nis_config_dn, mod)
+                entry['nsslapd-pluginenabled'] = ['on']
+                conn.update_entry(entry)
             else:
                 print "Plugin already Enabled"
                 retval = 2
 
         elif args[0] == "disable":
             try:
-                mod = {'nsslapd-pluginenabled': 'off'}
-                conn.update_entry(nis_config_dn, mod)
+                entry = conn.make_entry(
+                    nis_config_dn, {'nsslapd-pluginenabled': 'off'})
+                conn.update_entry(entry)
             except errors.NotFound:
                 print "Plugin is already disabled"
                 retval = 2
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 458ebba..e67a182 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -556,10 +556,10 @@ def set_subject_in_config(realm_name, dm_password, suffix, subject_base):
         except errors.ExecutionError, e:
             root_logger.critical("Could not connect to the Directory Server on %s" % realm_name)
             raise e
-        (dn, entry_attrs) = conn.get_ipa_config()
+        entry_attrs = conn.get_ipa_config()
         if 'ipacertificatesubjectbase' not in entry_attrs:
-            mod = {'ipacertificatesubjectbase': str(subject_base)}
-            conn.update_entry(dn, mod)
+            entry_attrs['ipacertificatesubjectbase'] = str(subject_base)
+            conn.update_entry(entry_attrs)
         conn.disconnect()
 
 
diff --git a/install/tools/ipactl b/install/tools/ipactl
index 2db0fde..53c9ce9 100755
--- a/install/tools/ipactl
+++ b/install/tools/ipactl
@@ -137,7 +137,7 @@ def get_config(dirsrv):
         except Exception, e:
             masters_list.append("No master found because of error: %s" % str(e))
         else:
-            for dn, master_entry in entries:
+            for master_entry in entries:
                 masters_list.append(master_entry.single_value['cn'])
 
         masters = "\n".join(masters_list)
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index 2f1c999..fcd88dd 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -470,7 +470,7 @@ class ADTRUSTInstance(service.Service):
             members = current.get('memberPrincipal', [])
             if not(self.cifs_principal in members):
                 current["memberPrincipal"] = members + [self.cifs_principal]
-                self.admin_conn.update_entry(targets_dn, current)
+                self.admin_conn.update_entry(current)
             else:
                 self.print_msg('cifs principal already targeted, nothing to do.')
         except errors.NotFound:
@@ -501,7 +501,7 @@ class ADTRUSTInstance(service.Service):
                 members = current.get('member', [])
                 if not(self.cifs_agent in members):
                     current["member"] = members + [self.cifs_agent]
-                    self.admin_conn.update_entry(self.smb_dn, current)
+                    self.admin_conn.update_entry(current)
             except errors.NotFound:
                 entry = self.admin_conn.make_entry(
                     self.smb_dn,
@@ -721,7 +721,7 @@ class ADTRUSTInstance(service.Service):
                 lookup_nsswitch = current.get(lookup_nsswitch_name, [])
                 if not(config[1] in lookup_nsswitch):
                     current[lookup_nsswitch_name] = [config[1]]
-                    self.admin_conn.update_entry(entry_dn, current)
+                    self.admin_conn.update_entry(current)
         except Exception, e:
             root_logger.critical("Enabling nsswitch support in slapi-nis failed with error '%s'" % e)
 
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index ac5c81d..cc4fef5 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -930,21 +930,22 @@ class CAInstance(service.Service):
         decoded = base64.b64decode(self.ra_cert)
 
         entry_dn = DN(('uid', "ipara"), ('ou', 'People'), self.basedn)
-        entry = [
-        ('objectClass', ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'cmsuser']),
-        ('uid', "ipara"),
-        ('sn', "ipara"),
-        ('cn', "ipara"),
-        ('usertype', "agentType"),
-        ('userstate', "1"),
-        ('userCertificate', decoded),
-        ('description', '2;%s;%s;%s' % \
-             (str(self.requestId),
-              DN(('CN', 'Certificate Authority'), self.subject_base),
-              DN(('CN', 'IPA RA'), self.subject_base))),
-        ]
-
-        conn.add_entry(entry_dn, entry)
+        entry = conn.make_entry(
+            entry_dn,
+            objectClass=['top', 'person', 'organizationalPerson',
+                         'inetOrgPerson', 'cmsuser'],
+            uid="ipara",
+            sn="ipara",
+            cn="ipara",
+            usertype="agentType",
+            userstate="1",
+            userCertificate=decoded,
+            description='2;%s;%s;%s' % (
+                str(self.requestId),
+                DN(('CN', 'Certificate Authority'), self.subject_base),
+                DN(('CN', 'IPA RA'), self.subject_base)))
+
+        conn.add_entry(entry)
 
         dn = DN(('cn', 'Certificate Manager Agents'), ('ou', 'groups'), self.basedn)
         modlist = [(0, 'uniqueMember', '%s' % entry_dn)]
@@ -1764,11 +1765,11 @@ def update_people_entry(uid, dercert):
             conn = ldap2.ldap2(shared_instance=False, ldap_uri=dogtag_uri)
             conn.connect(bind_dn=DN(('cn', 'directory manager')),
                 bind_pw=dm_password)
-            (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'])
+            entry_attrs = conn.get_entry(dn, ['usercertificate'])
             entry_attrs['usercertificate'].append(dercert)
             entry_attrs['description'] = '2;%d;%s;%s' % (serial_number, issuer,
                 subject)
-            conn.update_entry(dn, entry_attrs)
+            conn.update_entry(entry_attrs)
             updated = True
             break
         except errors.NetworkError:
diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py
index 36d078a..bd5244d 100644
--- a/ipaserver/install/ipa_replica_prepare.py
+++ b/ipaserver/install/ipa_replica_prepare.py
@@ -162,7 +162,7 @@ class ReplicaPrepare(admintool.AdminTool):
             conn = ldap2(shared_instance=False, base_dn=suffix)
             conn.connect(bind_dn=DN(('cn', 'directory manager')),
                          bind_pw=self.dirman_password)
-            dn, entry_attrs = conn.get_ipa_config()
+            entry_attrs = conn.get_ipa_config()
             conn.disconnect()
         except errors.ACIError:
             raise admintool.ScriptError("The password provided is incorrect "
-- 
1.8.4.2

>From 8beaba2b7fa42bdd5cfa0481d520dacf41a3f275 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast redhat com>
Date: Thu, 31 Oct 2013 16:55:07 +0000
Subject: [PATCH 4/6] Convert remaining update code to LDAPEntry API.

---
 ipaserver/install/plugins/adtrust.py                |  4 ++--
 ipaserver/install/plugins/dns.py                    |  2 +-
 ipaserver/install/plugins/fix_replica_agreements.py |  4 ++--
 ipaserver/install/plugins/rename_managed.py         | 10 +++++-----
 ipaserver/install/plugins/update_anonymous_aci.py   |  4 ++--
 ipaserver/install/plugins/update_idranges.py        | 16 +++++++---------
 ipaserver/install/plugins/update_services.py        | 11 +++++------
 ipaserver/install/plugins/upload_cacrt.py           |  2 +-
 8 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
index 2835858..d567aea 100644
--- a/ipaserver/install/plugins/adtrust.py
+++ b/ipaserver/install/plugins/adtrust.py
@@ -46,7 +46,7 @@ class update_default_range(PostUpdate):
 
         dn = DN(('cn', 'admins'), api.env.container_group, api.env.basedn)
         try:
-            (dn, admins_entry) = ldap.get_entry(dn, ['gidnumber'])
+            admins_entry = ldap.get_entry(dn, ['gidnumber'])
         except errors.NotFound:
             root_logger.error("default_range: No local ID range and no admins "
                               "group found. Cannot create default ID range")
@@ -88,7 +88,7 @@ class update_default_range(PostUpdate):
         else:
             masters = set()
             remaining_values_sum = 0
-            for entry_dn, entry in entries:
+            for entry in entries:
                 hostname = entry.get('dnahostname', [None])[0]
                 if hostname is None or hostname in masters:
                     continue
diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py
index b875ff0..6e6c52f 100644
--- a/ipaserver/install/plugins/dns.py
+++ b/ipaserver/install/plugins/dns.py
@@ -160,7 +160,7 @@ class update_dns_limits(PostUpdate):
                             self.env.basedn)
 
         try:
-            (dn, entry) = ldap.get_entry(dns_service_dn, self.limit_attributes)
+            entry = ldap.get_entry(dns_service_dn, self.limit_attributes)
         except errors.NotFound:
             # this host may not have DNS service set
             root_logger.debug("DNS: service %s not found, no need to update limits" % dns_service_dn)
diff --git a/ipaserver/install/plugins/fix_replica_agreements.py b/ipaserver/install/plugins/fix_replica_agreements.py
index bfd6356..a5ff481 100644
--- a/ipaserver/install/plugins/fix_replica_agreements.py
+++ b/ipaserver/install/plugins/fix_replica_agreements.py
@@ -89,7 +89,7 @@ class update_replica_attribute_lists(PreUpdate):
             replica[attribute] = [template % " ".join(values)]
 
             try:
-                repl.conn.update_entry(replica.dn, replica)
+                repl.conn.update_entry(replica)
                 self.log.debug("Updated")
             except Exception, e:
                 self.log.error("Error caught updating replica: %s", str(e))
@@ -107,7 +107,7 @@ class update_replica_attribute_lists(PreUpdate):
                     '%s %s' % (attrlist, ' '.join(missing))]
 
                 try:
-                    repl.conn.update_entry(replica.dn, replica)
+                    repl.conn.update_entry(replica)
                     self.log.debug("Updated %s", attribute)
                 except Exception, e:
                     self.log.error("Error caught updating %s: %s",
diff --git a/ipaserver/install/plugins/rename_managed.py b/ipaserver/install/plugins/rename_managed.py
index e0fa36b..691f194 100644
--- a/ipaserver/install/plugins/rename_managed.py
+++ b/ipaserver/install/plugins/rename_managed.py
@@ -77,15 +77,15 @@ class GenerateUpdateMixin(object):
                 old_dn = entry.data['managedtemplate'][0]
                 assert isinstance(old_dn, DN)
                 try:
-                    (old_dn, entry) = ldap.get_entry(old_dn, ['*'])
+                    entry = ldap.get_entry(old_dn, ['*'])
                 except errors.NotFound, e:
                     pass
                 else:
                     # Compute the new dn by replacing the old container with the new container
-                    new_dn = EditableDN(old_dn)
+                    new_dn = EditableDN(entry.dn)
                     if new_dn.replace(old_template_container, new_template_container) != 1:
                         self.error("unable to replace '%s' with '%s' in '%s'",
-                                   old_template_container, new_template_container, old_dn)
+                                   old_template_container, new_template_container, entry.dn)
                         continue
 
                     new_dn = DN(new_dn)
@@ -95,10 +95,10 @@ class GenerateUpdateMixin(object):
                                   'default': entry_to_update(entry)}
 
                     # Delete the old entry
-                    old_update = {'dn': old_dn, 'deleteentry': None}
+                    old_update = {'dn': entry.dn, 'deleteentry': None}
 
                     # Add the delete and replacement updates to the list of all updates
-                    update_list.append({old_dn: old_update, new_dn: new_update})
+                    update_list.append({entry.dn: old_update, new_dn: new_update})
 
             else:
                 # Update the template dn by replacing the old containter with the new container
diff --git a/ipaserver/install/plugins/update_anonymous_aci.py b/ipaserver/install/plugins/update_anonymous_aci.py
index 2e01217..0425754 100644
--- a/ipaserver/install/plugins/update_anonymous_aci.py
+++ b/ipaserver/install/plugins/update_anonymous_aci.py
@@ -38,7 +38,7 @@ class update_anonymous_aci(PostUpdate):
         targetfilter = '(&(!(objectClass=ipaToken))(!(objectClass=ipatokenTOTP))(!(objectClass=ipatokenRadiusConfiguration)))'
         filter = None
 
-        (dn, entry_attrs) = ldap.get_entry(api.env.basedn, ['aci'])
+        entry_attrs = ldap.get_entry(api.env.basedn, ['aci'])
 
         acistrs = entry_attrs.get('aci', [])
         acilist = aci._convert_strings_to_acis(entry_attrs.get('aci', []))
@@ -87,7 +87,7 @@ class update_anonymous_aci(PostUpdate):
         entry_attrs['aci'] = acistrs
 
         try:
-            ldap.update_entry(dn, entry_attrs)
+            ldap.update_entry(entry_attrs)
         except Exception, e:
             root_logger.error("Failed to update Anonymous ACI: %s" % e)
 
diff --git a/ipaserver/install/plugins/update_idranges.py b/ipaserver/install/plugins/update_idranges.py
index c3df98a..73dd621 100644
--- a/ipaserver/install/plugins/update_idranges.py
+++ b/ipaserver/install/plugins/update_idranges.py
@@ -71,27 +71,25 @@ class update_idrange_type(PostUpdate):
             error = False
 
             # Set the range type
-            for dn, entry in entries:
-                update = {}
-
+            for entry in entries:
                 objectclasses = [o.lower() for o
                                            in entry.get('objectclass', [])]
 
                 if 'ipatrustedaddomainrange' in objectclasses:
                     # NOTICE: assumes every AD range does not use POSIX
                     #         attributes
-                    update['ipaRangeType'] = 'ipa-ad-trust'
+                    entry['ipaRangeType'] = 'ipa-ad-trust'
                 elif 'ipadomainidrange' in objectclasses:
-                    update['ipaRangeType'] = 'ipa-local'
+                    entry['ipaRangeType'] = 'ipa-local'
                 else:
-                    update['ipaRangeType'] = 'unknown'
+                    entry['ipaRangeType'] = 'unknown'
                     root_logger.error("update_idrange_type: could not detect "
-                                      "range type for entry: %s" % str(dn))
+                                      "range type for entry: %s" % str(entry.dn))
                     root_logger.error("update_idrange_type: ID range type set "
-                                      "to 'unknown' for entry: %s" % str(dn))
+                                      "to 'unknown' for entry: %s" % str(entry.dn))
 
                 try:
-                    ldap.update_entry(dn, update)
+                    ldap.update_entry(entry)
                 except (errors.EmptyModlist, errors.NotFound):
                     pass
                 except errors.ExecutionError, e:
diff --git a/ipaserver/install/plugins/update_services.py b/ipaserver/install/plugins/update_services.py
index c384af5..2122abb 100644
--- a/ipaserver/install/plugins/update_services.py
+++ b/ipaserver/install/plugins/update_services.py
@@ -66,13 +66,12 @@ class update_service_principalalias(PostUpdate):
                               len(entries), truncated)
 
             error = False
-            for dn, entry in entries:
-                update = {}
-                update['objectclass'] = (entry['objectclass'] +
-                                         ['ipakrbprincipal'])
-                update['ipakrbprincipalalias'] = entry['krbprincipalname']
+            for entry in entries:
+                entry['objectclass'] = (entry['objectclass'] +
+                                        ['ipakrbprincipal'])
+                entry['ipakrbprincipalalias'] = entry['krbprincipalname']
                 try:
-                    ldap.update_entry(dn, update)
+                    ldap.update_entry(entry)
                 except (errors.EmptyModlist, errors.NotFound):
                     pass
                 except errors.ExecutionError, e:
diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py
index a82fc36..1da8e88 100644
--- a/ipaserver/install/plugins/upload_cacrt.py
+++ b/ipaserver/install/plugins/upload_cacrt.py
@@ -33,7 +33,7 @@ class update_upload_cacrt(PostUpdate):
 
     def execute(self, **options):
         ldap = self.obj.backend
-        (cdn, ipa_config) = ldap.get_ipa_config()
+        ipa_config = ldap.get_ipa_config()
         subject_base = ipa_config.get('ipacertificatesubjectbase', [None])[0]
         dirname = config_dirname(realm_to_serverid(api.env.realm))
         certdb = certs.CertDB(api.env.realm, nssdir=dirname, subject_base=subject_base)
-- 
1.8.4.2

>From 57632342a00e8b093db07656de87aac61c133e57 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast redhat com>
Date: Thu, 31 Oct 2013 16:55:23 +0000
Subject: [PATCH 5/6] Convert remaining test code to LDAPEntry API.

---
 ipatests/test_ipaserver/test_ldap.py         | 8 ++++----
 ipatests/test_xmlrpc/test_netgroup_plugin.py | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/ipatests/test_ipaserver/test_ldap.py b/ipatests/test_ipaserver/test_ldap.py
index 3a63799..50bb9ca 100644
--- a/ipatests/test_ipaserver/test_ldap.py
+++ b/ipatests/test_ipaserver/test_ldap.py
@@ -61,7 +61,7 @@ class test_ldap(object):
         """
         self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri)
         self.conn.connect()
-        (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate'])
+        entry_attrs = self.conn.get_entry(self.dn, ['usercertificate'])
         cert = entry_attrs.get('usercertificate')
         cert = cert[0]
         serial = unicode(x509.get_serial_number(cert, x509.DER))
@@ -75,7 +75,7 @@ class test_ldap(object):
             raise nose.SkipTest('Missing ccache %s' % self.ccache)
         self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri)
         self.conn.connect(ccache='FILE:%s' % self.ccache)
-        (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate'])
+        entry_attrs = self.conn.get_entry(self.dn, ['usercertificate'])
         cert = entry_attrs.get('usercertificate')
         cert = cert[0]
         serial = unicode(x509.get_serial_number(cert, x509.DER))
@@ -94,7 +94,7 @@ class test_ldap(object):
             raise nose.SkipTest("No directory manager password in %s" % pwfile)
         self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri)
         self.conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password)
-        (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate'])
+        entry_attrs = self.conn.get_entry(self.dn, ['usercertificate'])
         cert = entry_attrs.get('usercertificate')
         cert = cert[0]
         serial = unicode(x509.get_serial_number(cert, x509.DER))
@@ -142,7 +142,7 @@ class test_ldap(object):
             self.conn.connect(autobind=True)
         except errors.ACIError:
             raise nose.SkipTest("Only executed as root")
-        (dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate'])
+        entry_attrs = self.conn.get_entry(self.dn, ['usercertificate'])
         cert = entry_attrs.get('usercertificate')
         cert = cert[0]
         serial = unicode(x509.get_serial_number(cert, x509.DER))
diff --git a/ipatests/test_xmlrpc/test_netgroup_plugin.py b/ipatests/test_xmlrpc/test_netgroup_plugin.py
index 9c21e8d..da9a809 100644
--- a/ipatests/test_xmlrpc/test_netgroup_plugin.py
+++ b/ipatests/test_xmlrpc/test_netgroup_plugin.py
@@ -1306,7 +1306,7 @@ class test_netgroup(Declarative):
 #            raise nose.SkipTest('compat and nis are not enabled, skipping test')
 #        finally:
 #            conn.disconnect()
-#        triples = entries[0][0][1]['nisnetgrouptriple']
+#        triples = entries[0][0]['nisnetgrouptriple']
 #
 #        # This may not prove to be reliable since order is not guaranteed
 #        # and even which user gets into which triple can be random.
-- 
1.8.4.2

>From 0529097556b1b60b809506ef9940dfb8a979902e Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast redhat com>
Date: Thu, 31 Oct 2013 16:59:24 +0000
Subject: [PATCH 6/6] Drop support for the legacy LDAP API.

---
 ipapython/ipaldap.py | 87 ++++------------------------------------------------
 1 file changed, 6 insertions(+), 81 deletions(-)

diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py
index a48879f..4e03dd2 100644
--- a/ipapython/ipaldap.py
+++ b/ipapython/ipaldap.py
@@ -612,13 +612,6 @@ class IPASimpleLDAPObject(object):
         return self.conn.unbind_s()
 
 
-# Make python-ldap tuple style result compatible with Entry and Entity
-# objects by allowing access to the dn (tuple index 0) via the 'dn'
-# attribute name and the attr dict (tuple index 1) via the 'data'
-# attribute name. Thus:
-# r = result[0]
-# r[0] == r.dn
-# r[1] == r.data
 class LDAPEntry(collections.MutableMapping):
     __slots__ = ('_conn', '_dn', '_names', '_nice', '_raw', '_sync',
                  '_not_list', '_orig', '_raw_view', '_single_value_view')
@@ -915,12 +908,6 @@ class LDAPEntry(collections.MutableMapping):
         return value
 
     def __getitem__(self, name):
-        # FIXME: Remove when python-ldap tuple compatibility is dropped
-        if name == 0:
-            return self._dn
-        elif name == 1:
-            return self
-
         return self._get_nice(name)
 
     def __delitem__(self, name):
@@ -961,51 +948,9 @@ class LDAPEntry(collections.MutableMapping):
             return NotImplemented
         return other is not self
 
-    # FIXME: Remove when python-ldap tuple compatibility is dropped
     def __iter__(self):
-        yield self._dn
-        yield self
-
-    # FIXME: Remove when python-ldap tuple compatibility is dropped
-    def iterkeys(self):
         return self._nice.iterkeys()
 
-    # FIXME: Remove when python-ldap tuple compatibility is dropped
-    def itervalues(self):
-        for name in self.iterkeys():
-            yield self[name]
-
-    # FIXME: Remove when python-ldap tuple compatibility is dropped
-    def iteritems(self):
-        for name in self.iterkeys():
-            yield (name, self[name])
-
-    # FIXME: Remove when python-ldap tuple compatibility is dropped
-    def keys(self):
-        return list(self.iterkeys())
-
-    # FIXME: Remove when python-ldap tuple compatibility is dropped
-    def values(self):
-        return list(self.itervalues())
-
-    # FIXME: Remove when python-ldap tuple compatibility is dropped
-    def items(self):
-        return list(self.iteritems())
-
-    # FIXME: Remove when python-ldap tuple compatibility is dropped
-    def update(self, _obj={}, **kwargs):
-        _obj = dict(_obj, **kwargs)
-        super(LDAPEntry, self).update(_obj)
-
-    # FIXME: Remove when python-ldap tuple compatibility is dropped
-    def popitem(self):
-        try:
-            name = self.iterkeys().next()
-        except StopIteration:
-            raise KeyError
-
-        return name, self.pop(name)
-
 class LDAPEntryView(collections.MutableMapping):
     __slots__ = ('_entry',)
 
@@ -1530,31 +1475,16 @@ class LDAPClient(object):
             raise errors.LimitsExceeded()
         return entries[0]
 
-    def _get_dn_and_attrs(self, entry_or_dn, entry_attrs):
-        """Helper for legacy calling style for {add,update}_entry
-        """
-        if entry_attrs is None:
-            return entry_or_dn.dn, entry_or_dn
-        else:
-            assert isinstance(entry_or_dn, DN)
-            entry_attrs = self.make_entry(entry_or_dn, entry_attrs)
-            return entry_or_dn, entry_attrs
-
-    def add_entry(self, entry, entry_attrs=None):
+    def add_entry(self, entry):
         """Create a new entry.
 
         This should be called as add_entry(entry).
-
-        The legacy two-argument variant is:
-            add_entry(dn, entry_attrs)
         """
-        dn, attrs = self._get_dn_and_attrs(entry, entry_attrs)
-
         # remove all [] values (python-ldap hates 'em)
-        attrs = dict((k, v) for k, v in attrs.raw.iteritems() if v)
+        attrs = dict((k, v) for k, v in entry.raw.iteritems() if v)
 
         with self.error_handler():
-            self.conn.add_s(dn, attrs.items())
+            self.conn.add_s(entry.dn, attrs.items())
 
     def update_entry_rdn(self, dn, new_rdn, del_old=True):
         """
@@ -1621,24 +1551,19 @@ class LDAPClient(object):
 
         return modlist
 
-    def update_entry(self, entry, entry_attrs=None):
+    def update_entry(self, entry):
         """Update entry's attributes.
 
         This should be called as update_entry(entry).
-
-        The legacy two-argument variant is:
-            update_entry(dn, entry_attrs)
         """
-        dn, attrs = self._get_dn_and_attrs(entry, entry_attrs)
-
         # generate modlist
-        modlist = self._generate_modlist(dn, attrs)
+        modlist = self._generate_modlist(entry.dn, entry)
         if not modlist:
             raise errors.EmptyModlist()
 
         # pass arguments to python-ldap
         with self.error_handler():
-            self.conn.modify_s(dn, modlist)
+            self.conn.modify_s(entry.dn, modlist)
 
     def delete_entry(self, entry_or_dn):
         """Delete an entry given either the DN or the entry itself"""
-- 
1.8.4.2


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]