On 31.05.2016 12:44, Martin Babinsky wrote:
On 05/28/2016 01:17 PM, Martin Basti wrote:
https://fedorahosted.org/freeipa/ticket/4995

Patches attached




Hi,

PATCH 0488: LGTM

PATCH 0489:

@@ -996,10 +997,10 @@ def check_deleted_segments(hostname, masters, topo_errors, starting_host):
         i = 0
         while True:
             left = api.Command.topologysegment_find(
- suffix_name, iparepltoposegmentleftnode=hostname, sizelimit=0 + suffix_name, iparepltoposegmentleftnode=hostname, sizelimit=0,
             )['result']
             right = api.Command.topologysegment_find(
- suffix_name, iparepltoposegmentrightnode=hostname, sizelimit=0 + suffix_name, iparepltoposegmentrightnode=hostname, sizelimit=0,
             )['result']

it seems that you added 'no_members=True' there and then removed it because reasons. Please revert the this part to the original code so that it does not stick out.


Thanks,

updated patches attached.

Martin
From 034d3ea3d9e97da6ffb143957f0988f45ceef62d Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Thu, 19 May 2016 13:50:38 +0200
Subject: [PATCH 1/2] Performance: Find commands: do not process members by
 default

In all *-find commands, member attributes shouldn't be processed due
high amount fo ldpaserches cause serious performance issues. For this
reason --no-members option is set by default in CLI and API.

To get members in *-find command option --all in CLI is rquired or
'no_members=False' or 'all=True' must be set in API call.

For other commands processing of members stays unchanged. WebUI is not
affected by this change.

https://fedorahosted.org/freeipa/ticket/4995
---
 API.txt                                            |  44 ++--
 VERSION                                            |   4 +-
 install/tools/ipa-replica-manage                   |   6 +-
 ipalib/plugins/baseldap.py                         |   7 +-
 ipalib/plugins/caacl.py                            |   2 +-
 ipalib/plugins/hbactest.py                         |   3 +-
 ipalib/plugins/otptoken.py                         |   3 +-
 ipalib/plugins/topology.py                         |   6 +-
 ipalib/plugins/user.py                             |   3 +-
 ipaserver/install/replication.py                   |   3 +-
 ipaserver/install/server/install.py                |   3 +-
 ipatests/test_xmlrpc/test_group_plugin.py          |  54 +++-
 ipatests/test_xmlrpc/test_hbacsvcgroup_plugin.py   |  21 +-
 ipatests/test_xmlrpc/test_hostgroup_plugin.py      |   5 +
 ipatests/test_xmlrpc/test_netgroup_plugin.py       | 115 ++++++++-
 ipatests/test_xmlrpc/test_old_permission_plugin.py | 272 ++++++++++++++++++--
 ipatests/test_xmlrpc/test_permission_plugin.py     | 273 ++++++++++++++++++++-
 ipatests/test_xmlrpc/test_privilege_plugin.py      |  60 ++++-
 ipatests/test_xmlrpc/test_role_plugin.py           |  85 ++++++-
 ipatests/test_xmlrpc/test_service_plugin.py        |  20 +-
 .../test_xmlrpc/test_servicedelegation_plugin.py   |  30 ++-
 ipatests/test_xmlrpc/test_sudocmdgroup_plugin.py   |   5 +
 ipatests/test_xmlrpc/test_user_plugin.py           |   2 +-
 ipatests/test_xmlrpc/tracker/host_plugin.py        |   5 +-
 ipatests/test_xmlrpc/tracker/hostgroup_plugin.py   |  13 +-
 ipatests/test_xmlrpc/tracker/sudocmd_plugin.py     |   7 +-
 .../test_xmlrpc/tracker/sudocmdgroup_plugin.py     |   9 +-
 ipatests/test_xmlrpc/tracker/user_plugin.py        |   3 +-
 28 files changed, 973 insertions(+), 90 deletions(-)

diff --git a/API.txt b/API.txt
index dbc6f1adc614607fab106ab0de7163961e7ecedc..3ad250e74f48ef3c54494ba6bd2d398a7c5d1b69 100644
--- a/API.txt
+++ b/API.txt
@@ -551,7 +551,7 @@ option: Str('description?', autofill=False, cli_name='desc')
 option: StrEnum('hostcategory?', autofill=False, cli_name='hostcat', values=[u'all'])
 option: StrEnum('ipacertprofilecategory?', autofill=False, cli_name='profilecat', values=[u'all'])
 option: Bool('ipaenabledflag?', autofill=False)
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: StrEnum('servicecategory?', autofill=False, cli_name='servicecat', values=[u'all'])
@@ -1598,7 +1598,7 @@ option: Str('in_netgroup*', cli_name='in_netgroups')
 option: Str('in_role*', cli_name='in_roles')
 option: Str('in_sudorule*', cli_name='in_sudorules')
 option: Str('no_group*', cli_name='no_groups')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Str('no_user*', cli_name='no_users')
 option: Flag('nonposix', autofill=True, cli_name='nonposix', default=False)
 option: Str('not_in_group*', cli_name='not_in_groups')
@@ -1763,7 +1763,7 @@ option: Str('description?', autofill=False, cli_name='desc')
 option: Str('externalhost*', autofill=False)
 option: StrEnum('hostcategory?', autofill=False, cli_name='hostcat', values=[u'all'])
 option: Bool('ipaenabledflag?', autofill=False)
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: StrEnum('servicecategory?', autofill=False, cli_name='servicecat', values=[u'all'])
@@ -1888,7 +1888,7 @@ arg: Str('criteria?')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('cn?', autofill=False, cli_name='service')
 option: Str('description?', autofill=False, cli_name='desc')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Int('sizelimit?', autofill=False)
@@ -1962,7 +1962,7 @@ arg: Str('criteria?')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('cn?', autofill=False, cli_name='name')
 option: Str('description?', autofill=False, cli_name='desc')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Int('sizelimit?', autofill=False)
@@ -2167,7 +2167,7 @@ option: Str('l?', autofill=False, cli_name='locality')
 option: Str('macaddress*', autofill=False)
 option: Str('man_by_host*', cli_name='man_by_hosts')
 option: Str('man_host*', cli_name='man_hosts')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Str('not_enroll_by_user*', cli_name='not_enroll_by_users')
 option: Str('not_in_hbacrule*', cli_name='not_in_hbacrules')
 option: Str('not_in_hostgroup*', cli_name='not_in_hostgroups')
@@ -2302,7 +2302,7 @@ option: Str('in_netgroup*', cli_name='in_netgroups')
 option: Str('in_sudorule*', cli_name='in_sudorules')
 option: Str('no_host*', cli_name='no_hosts')
 option: Str('no_hostgroup*', cli_name='no_hostgroups')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Str('not_in_hbacrule*', cli_name='not_in_hbacrules')
 option: Str('not_in_hostgroup*', cli_name='not_in_hostgroups')
 option: Str('not_in_netgroup*', cli_name='not_in_netgroups')
@@ -2846,7 +2846,7 @@ option: Str('nisdomainname?', autofill=False, cli_name='nisdomain')
 option: Str('no_group*', cli_name='no_groups')
 option: Str('no_host*', cli_name='no_hosts')
 option: Str('no_hostgroup*', cli_name='no_hostgroups')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Str('no_netgroup*', cli_name='no_netgroups')
 option: Str('no_user*', cli_name='no_users')
 option: Str('not_in_netgroup*', cli_name='not_in_netgroups')
@@ -3017,7 +3017,7 @@ option: Int('ipatokentotpclockoffset?', autofill=False, cli_name='offset', defau
 option: Int('ipatokentotptimestep?', autofill=False, cli_name='interval', default=30)
 option: Str('ipatokenuniqueid?', autofill=False, cli_name='id')
 option: Str('ipatokenvendor?', autofill=False, cli_name='vendor')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Int('sizelimit?', autofill=False)
@@ -3169,7 +3169,7 @@ option: Str('ipapermtargetfilter*', autofill=False, cli_name='rawfilter')
 option: DNParam('ipapermtargetfrom?', autofill=False, cli_name='targetfrom')
 option: DNParam('ipapermtargetto?', autofill=False, cli_name='targetto')
 option: Str('memberof*', autofill=False)
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Str('permissions*', autofill=False)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
@@ -3303,7 +3303,7 @@ arg: Str('criteria?')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('cn?', autofill=False, cli_name='name')
 option: Str('description?', autofill=False, cli_name='desc')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Int('sizelimit?', autofill=False)
@@ -3599,7 +3599,7 @@ arg: Str('criteria?')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('cn?', autofill=False, cli_name='name')
 option: Str('description?', autofill=False, cli_name='desc')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Int('sizelimit?', autofill=False)
@@ -3787,7 +3787,7 @@ option: Str('description?', autofill=False, cli_name='desc')
 option: StrEnum('hostcategory?', autofill=False, cli_name='hostcat', values=[u'all'])
 option: Bool('ipaenabledflag?', autofill=False)
 option: Str('ipaselinuxuser?', autofill=False, cli_name='selinuxuser')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Str('seealso?', autofill=False, cli_name='hbacrule')
@@ -3877,7 +3877,7 @@ option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('cn?', autofill=False, cli_name='name')
 option: Int('ipamaxdomainlevel?', autofill=False, cli_name='maxlevel')
 option: Int('ipamindomainlevel?', autofill=False, cli_name='minlevel')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Str('no_topologysuffix*', cli_name='no_topologysuffixes')
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
@@ -4017,7 +4017,7 @@ option: Flag('all', autofill=True, cli_name='all', default=False)
 option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values=[u'MS-PAC', u'PAD', u'NONE'])
 option: Str('krbprincipalname?', autofill=False, cli_name='principal')
 option: Str('man_by_host*', cli_name='man_by_hosts')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Str('not_man_by_host*', cli_name='not_man_by_hosts')
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
@@ -4127,7 +4127,7 @@ args: 1,8,4
 arg: Str('criteria?')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('cn?', autofill=False, cli_name='delegation_name')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Int('sizelimit?', autofill=False)
@@ -4351,7 +4351,7 @@ option: Str('loginshell?', autofill=False, cli_name='shell')
 option: Str('mail*', autofill=False, cli_name='email')
 option: Str('manager?', autofill=False)
 option: Str('mobile*', autofill=False)
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Str('not_in_group*', cli_name='not_in_groups')
 option: Str('not_in_hbacrule*', cli_name='not_in_hbacrules')
 option: Str('not_in_netgroup*', cli_name='not_in_netgroups')
@@ -4479,7 +4479,7 @@ args: 1,9,4
 arg: Str('criteria?')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('description?', autofill=False, cli_name='desc')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Int('sizelimit?', autofill=False)
@@ -4554,7 +4554,7 @@ arg: Str('criteria?')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('cn?', autofill=False, cli_name='sudocmdgroup_name')
 option: Str('description?', autofill=False, cli_name='desc')
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Int('sizelimit?', autofill=False)
@@ -4741,7 +4741,7 @@ option: Str('ipasudorunasextgroup?', autofill=False, cli_name='runasexternalgrou
 option: Str('ipasudorunasextuser?', autofill=False, cli_name='runasexternaluser')
 option: StrEnum('ipasudorunasgroupcategory?', autofill=False, cli_name='runasgroupcat', values=[u'all'])
 option: StrEnum('ipasudorunasusercategory?', autofill=False, cli_name='runasusercat', values=[u'all'])
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Int('sizelimit?', autofill=False)
@@ -5349,7 +5349,7 @@ option: Str('loginshell?', autofill=False, cli_name='shell')
 option: Str('mail*', autofill=False, cli_name='email')
 option: Str('manager?', autofill=False)
 option: Str('mobile*', autofill=False)
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Str('not_in_group*', cli_name='not_in_groups')
 option: Str('not_in_hbacrule*', cli_name='not_in_hbacrules')
 option: Str('not_in_netgroup*', cli_name='not_in_netgroups')
@@ -5622,7 +5622,7 @@ option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('cn?', autofill=False, cli_name='name')
 option: Str('description?', autofill=False, cli_name='desc')
 option: StrEnum('ipavaulttype?', autofill=False, cli_name='type', default=u'symmetric', values=[u'standard', u'symmetric', u'asymmetric'])
-option: Flag('no_members', autofill=True, default=False)
+option: Flag('no_members', autofill=True, default=True)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Str('service?')
diff --git a/VERSION b/VERSION
index eb7957eb1c5ae2487975a2fae4485a43f613cb64..45fdb09788dbc6496272da786bb6d6afa45bf118 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=169
-# Last change: vault: copy arguments of client commands from server counterparts
+IPA_API_VERSION_MINOR=170
+# Last change: mbasti - *-find: do not search for members by default
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index 8e692d295aafdcd6ae8a32b6d125f998434d8adb..9f6cfa6ca5f1b9a28ec0d63aa06da22ac658760a 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -945,7 +945,8 @@ def del_master_managed(realm, hostname, options):
         sys.exit(1)
 
     # 2. Get all masters
-    masters = api.Command.server_find('', sizelimit=0)['result']
+    masters = api.Command.server_find(
+        '', sizelimit=0, no_members=False)['result']
 
     # 3. Check topology connectivity in all suffixes
     topo_errors = replication.check_last_link_managed(api, hostname, masters)
@@ -1149,7 +1150,8 @@ def del_master_direct(realm, hostname, options):
     # Check for orphans if the remote server is up.
     if delrepl and not winsync:
         try:
-            masters = api.Command.server_find('', sizelimit=0)['result']
+            masters = api.Command.server_find(
+                '', sizelimit=0, no_members=False)['result']
         except Exception as e:
             masters = []
             print("Failed to read masters data from '%s': %s" % (
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 8a696f3c8e6c239f6ac38621de9f2fb403e4f99b..9c77fd62e9a8d8c7147f5ba055f4a9f30ee8e559 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -1117,7 +1117,7 @@ last, after all sets and adds."""),
                     yield Flag('no_members',
                         doc=_('Suppress processing of membership attributes.'),
                         exclude='webui',
-                        flags=['no_output'],
+                        flags={'no_output'},
                     )
                     break
 
@@ -1907,6 +1907,11 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
 
     def get_options(self):
         for option in super(LDAPSearch, self).get_options():
+            if option.name == 'no_members':
+                # no_members are always true for find commands, do not
+                # show option in CLI but keep API compatibility
+                option = option.clone(
+                    default=True, flags=option.flags | {"no_cli"})
             yield option
         if self.obj.primary_key and \
                 'no_output' not in self.obj.primary_key.flags:
diff --git a/ipalib/plugins/caacl.py b/ipalib/plugins/caacl.py
index d3190211bd8333e2573b9aab9a0924bff9e4a034..60eeb5a334acb7822549ff3530b6ec191f5e5abb 100644
--- a/ipalib/plugins/caacl.py
+++ b/ipalib/plugins/caacl.py
@@ -122,7 +122,7 @@ def _acl_make_rule(principal_type, obj):
 
 def acl_evaluate(principal_type, principal, ca_ref, profile_id):
     req = _acl_make_request(principal_type, principal, ca_ref, profile_id)
-    acls = api.Command.caacl_find()['result']
+    acls = api.Command.caacl_find(no_members=False)['result']
     rules = [_acl_make_rule(principal_type, obj) for obj in acls]
     return req.evaluate(rules) == pyhbac.HBAC_EVAL_ALLOW
 
diff --git a/ipalib/plugins/hbactest.py b/ipalib/plugins/hbactest.py
index a10e8a56f2a5c2f06372b6df07749165918ca026..1522b9b3182c837c01389a1c31ca415da05e37b0 100644
--- a/ipalib/plugins/hbactest.py
+++ b/ipalib/plugins/hbactest.py
@@ -337,7 +337,8 @@ class hbactest(Command):
 
         hbacset = []
         if len(testrules) == 0:
-            hbacset = self.api.Command.hbacrule_find(sizelimit=sizelimit)['result']
+            hbacset = self.api.Command.hbacrule_find(
+                sizelimit=sizelimit, no_members=False)['result']
         else:
             for rule in testrules:
                 try:
diff --git a/ipalib/plugins/otptoken.py b/ipalib/plugins/otptoken.py
index 0c96086fe13e78193475214e0c7e763562834d15..ae61ab355f19782c62d4d23547307f76e415e20b 100644
--- a/ipalib/plugins/otptoken.py
+++ b/ipalib/plugins/otptoken.py
@@ -318,7 +318,8 @@ class otptoken_add(LDAPCreate):
         # If owner was not specified, default to the person adding this token.
         # If managedby was not specified, attempt a sensible default.
         if 'ipatokenowner' not in entry_attrs or 'managedby' not in entry_attrs:
-            result = self.api.Command.user_find(whoami=True)['result']
+            result = self.api.Command.user_find(
+                whoami=True, no_members=False)['result']
             if result:
                 cur_uid = result[0]['uid'][0]
                 prev_uid = entry_attrs.setdefault('ipatokenowner', cur_uid)
diff --git a/ipalib/plugins/topology.py b/ipalib/plugins/topology.py
index 69b936eba60687ecfc272973044ab9a5cdc2e2f7..76cf29082bd977087cdcdbc1a3a3814609b2ba97 100644
--- a/ipalib/plugins/topology.py
+++ b/ipalib/plugins/topology.py
@@ -210,7 +210,8 @@ class topologysegment(LDAPObject):
             return  # nothing to check
 
         # check if nodes are IPA servers
-        masters = self.api.Command.server_find('', sizelimit=0)['result']
+        masters = self.api.Command.server_find(
+            '', sizelimit=0, no_members=False)['result']
         m_hostnames = [master['cn'][0].lower() for master in masters]
 
         if leftnode and leftnode not in m_hostnames:
@@ -472,7 +473,8 @@ Checks done:
 
         validate_domain_level(self.api)
 
-        masters = self.api.Command.server_find('', sizelimit=0)['result']
+        masters = self.api.Command.server_find(
+            '', sizelimit=0, no_members=False)['result']
         segments = self.api.Command.topologysegment_find(
             keys[0], sizelimit=0)['result']
         graph = create_topology_graph(masters, segments)
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index d71305d082e1d1f0c7463d12b15569259f2e2edd..5b00b426be0664c8cdfc747e852f8b40fa9547a1 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -710,7 +710,8 @@ class user_del(baseuser_del):
         # Delete all tokens owned and managed by this user.
         # Orphan all tokens owned but not managed by this user.
         owner = self.api.Object.user.get_primary_key_from_dn(dn)
-        results = self.api.Command.otptoken_find(ipatokenowner=owner)['result']
+        results = self.api.Command.otptoken_find(
+            ipatokenowner=owner, no_members=False)['result']
         for token in results:
             orphan = not [x for x in token.get('managedby_user', []) if x == owner]
             token = self.api.Object.otptoken.get_primary_key_from_dn(token['dn'])
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
index dd9453ce4fdac5d1bc43335fca2d8a96da62ad61..c58cce228128613223840599e00b9f6c14f0835f 100644
--- a/ipaserver/install/replication.py
+++ b/ipaserver/install/replication.py
@@ -1781,7 +1781,8 @@ def get_orphaned_suffixes(masters):
     :return a set consisting of suffix names which are not managed by any
     master
     """
-    all_suffixes = api.Command.topologysuffix_find(sizelimit=0)['result']
+    all_suffixes = api.Command.topologysuffix_find(
+        sizelimit=0, no_members=False)['result']
     all_suffix_names = set(s['cn'][0] for s in all_suffixes)
     managed_suffixes = set(map_masters_to_suffixes(masters))
 
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index 2d71b3837214683566f37644c41a680953a64207..e4d4ab1635598eb083b2aec0c5e51a1eec63c8ce 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -1148,7 +1148,8 @@ def uninstall_check(installer):
                     print("Aborting uninstall operation.")
                     sys.exit(1)
         else:
-            masters = api.Command.server_find(sizelimit=0)['result']
+            masters = api.Command.server_find(
+                sizelimit=0, no_members=False)['result']
 
             if not check_master_deleted(api, masters,
                                         not options.unattended):
diff --git a/ipatests/test_xmlrpc/test_group_plugin.py b/ipatests/test_xmlrpc/test_group_plugin.py
index 41d28f1cfdbc3d47ea9c47292394637770222ac2..02467daedfea65b9145a5b505e06fffc1a69bfb6 100644
--- a/ipatests/test_xmlrpc/test_group_plugin.py
+++ b/ipatests/test_xmlrpc/test_group_plugin.py
@@ -177,6 +177,57 @@ class TestFindGroup(XMLRPC_test):
         group.ensure_exists()
         group.find()
 
+    def test_search_for_all_groups_with_members(self, group, group2):
+        """ Search for all groups """
+        group.ensure_exists()
+        group2.create()
+        command = group.make_command('group_find', no_members=False)
+        result = command()
+        assert_deepequal(dict(
+            summary=u'6 groups matched',
+            count=6,
+            truncated=False,
+            result=[
+                {
+                    'dn': get_group_dn('admins'),
+                    'member_user': [u'admin'],
+                    'gidnumber': [fuzzy_digits],
+                    'cn': [u'admins'],
+                    'description': [u'Account administrators group'],
+                },
+                {
+                    'dn': get_group_dn('editors'),
+                    'gidnumber': [fuzzy_digits],
+                    'cn': [u'editors'],
+                    'description':
+                        [u'Limited admins who can edit other users'],
+                },
+                {
+                    'dn': get_group_dn('ipausers'),
+                    'cn': [u'ipausers'],
+                    'description': [u'Default group for all users'],
+                },
+                {
+                    'dn': get_group_dn(group.cn),
+                    'cn': [group.cn],
+                    'description': [u'Test desc1'],
+                    'gidnumber': [fuzzy_digits],
+                },
+                {
+                    'dn': get_group_dn(group2.cn),
+                    'cn': [group2.cn],
+                    'description': [u'Test desc2'],
+                    'gidnumber': [fuzzy_digits],
+                },
+                {
+                    'dn': get_group_dn('trust admins'),
+                    'member_user': [u'admin'],
+                    'cn': [u'trust admins'],
+                    'description': [u'Trusts administrators group'],
+                },
+            ]), result)
+
+
     def test_search_for_all_groups(self, group, group2):
         """ Search for all groups """
         group.ensure_exists()
@@ -190,7 +241,6 @@ class TestFindGroup(XMLRPC_test):
             result=[
                 {
                     'dn': get_group_dn('admins'),
-                    'member_user': [u'admin'],
                     'gidnumber': [fuzzy_digits],
                     'cn': [u'admins'],
                     'description': [u'Account administrators group'],
@@ -221,12 +271,12 @@ class TestFindGroup(XMLRPC_test):
                 },
                 {
                     'dn': get_group_dn('trust admins'),
-                    'member_user': [u'admin'],
                     'cn': [u'trust admins'],
                     'description': [u'Trusts administrators group'],
                 },
             ]), result)
 
+
     def test_search_for_all_posix(self, group, group2):
         """ Search for all posix groups """
         command = group.make_command(
diff --git a/ipatests/test_xmlrpc/test_hbacsvcgroup_plugin.py b/ipatests/test_xmlrpc/test_hbacsvcgroup_plugin.py
index 182a76bf90f80375caf3b313838aa24c978dcf96..9618edba30fbe5129e2c30079a1e9cb570a165ab 100644
--- a/ipatests/test_xmlrpc/test_hbacsvcgroup_plugin.py
+++ b/ipatests/test_xmlrpc/test_hbacsvcgroup_plugin.py
@@ -162,6 +162,26 @@ class test_hbacsvcgroup(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % hbacsvcgroup1,
+            command=('hbacsvcgroup_find', [], dict(
+                cn=hbacsvcgroup1, no_members=False)),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 HBAC service group matched',
+                result=[
+                    {
+                        'dn': dn1,
+                        'member_hbacsvc': [hbacsvc1],
+                        'cn': [hbacsvcgroup1],
+                        'description': [u'Test hbacsvcgroup 1'],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % hbacsvcgroup1,
             command=('hbacsvcgroup_find', [], dict(cn=hbacsvcgroup1)),
             expected=dict(
@@ -171,7 +191,6 @@ class test_hbacsvcgroup(Declarative):
                 result=[
                     {
                         'dn': dn1,
-                        'member_hbacsvc': [hbacsvc1],
                         'cn': [hbacsvcgroup1],
                         'description': [u'Test hbacsvcgroup 1'],
                     },
diff --git a/ipatests/test_xmlrpc/test_hostgroup_plugin.py b/ipatests/test_xmlrpc/test_hostgroup_plugin.py
index 61fda819b979f432150b95e54771130909b230d7..2e93e1013e84b8b76a33d18775d1780349539625 100644
--- a/ipatests/test_xmlrpc/test_hostgroup_plugin.py
+++ b/ipatests/test_xmlrpc/test_hostgroup_plugin.py
@@ -116,6 +116,11 @@ class TestHostGroup(XMLRPC_test):
         hostgroup.ensure_exists()
         hostgroup.find()
 
+    def test_search_for_hostgroup_with_all(self, hostgroup):
+        """ Search for hostgroup """
+        hostgroup.ensure_exists()
+        hostgroup.find(all=True)
+
     def test_update_hostgroup(self, hostgroup):
         """ Update description of hostgroup and verify """
         hostgroup.ensure_exists()
diff --git a/ipatests/test_xmlrpc/test_netgroup_plugin.py b/ipatests/test_xmlrpc/test_netgroup_plugin.py
index c03566b12809d0871275c9a3e83140b73a82e800..2d2df7c49849f216ddc3aea468965163adbd5580 100644
--- a/ipatests/test_xmlrpc/test_netgroup_plugin.py
+++ b/ipatests/test_xmlrpc/test_netgroup_plugin.py
@@ -406,6 +406,34 @@ class test_netgroup(Declarative):
 
 
         dict(
+            desc='Search for netgroups using no_user with members',
+            command=('netgroup_find', [], dict(
+                no_user=user1, no_members=False)),
+            expected=dict(
+                count=2,
+                truncated=False,
+                summary=u'2 netgroups matched',
+                result=[
+                    {
+                        'dn': fuzzy_netgroupdn,
+                        'memberhost_host': (host1,),
+                        'memberhost_hostgroup': (hostgroup1,),
+                        'cn': [netgroup1],
+                        'description': [u'Test netgroup 1'],
+                        'nisdomainname': [u'%s' % api.env.domain],
+                    },
+                    {
+                        'dn': fuzzy_netgroupdn,
+                        'cn': [netgroup2],
+                        'description': [u'Test netgroup 2'],
+                        'nisdomainname': [u'%s' % api.env.domain],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for netgroups using no_user',
             command=('netgroup_find', [], dict(no_user=user1)),
             expected=dict(
@@ -415,8 +443,6 @@ class test_netgroup(Declarative):
                 result=[
                     {
                         'dn': fuzzy_netgroupdn,
-                        'memberhost_host': (host1,),
-                        'memberhost_hostgroup': (hostgroup1,),
                         'cn': [netgroup1],
                         'description': [u'Test netgroup 1'],
                         'nisdomainname': [u'%s' % api.env.domain],
@@ -431,6 +457,7 @@ class test_netgroup(Declarative):
             ),
         ),
 
+
         dict(
             desc="Check %r doesn't match when searching for %s" % (netgroup1, user1),
             command=('netgroup_find', [], dict(user=user1)),
@@ -852,6 +879,32 @@ class test_netgroup(Declarative):
         ),
 
         dict(
+            desc='Search for %r with members' % netgroup1,
+            command=('netgroup_find', [], dict(
+                cn=netgroup1, no_members=False)),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 netgroup matched',
+                result=[
+                    {
+                        'dn': fuzzy_netgroupdn,
+                        'memberhost_host': (host1,),
+                        'memberhost_hostgroup': (hostgroup1,),
+                        'memberuser_user': (user1,),
+                        'memberuser_group': (group1,),
+                        'member_netgroup': (netgroup2,),
+                        'cn': [netgroup1],
+                        'description': [u'Test netgroup 1'],
+                        'nisdomainname': [u'%s' % api.env.domain],
+                        'externalhost': [unknown_host],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % netgroup1,
             command=('netgroup_find', [], dict(cn=netgroup1)),
             expected=dict(
@@ -861,6 +914,27 @@ class test_netgroup(Declarative):
                 result=[
                     {
                         'dn': fuzzy_netgroupdn,
+                        'cn': [netgroup1],
+                        'description': [u'Test netgroup 1'],
+                        'nisdomainname': [u'%s' % api.env.domain],
+                        'externalhost': [unknown_host],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
+            desc='Search for %r using user with members' % netgroup1,
+            command=('netgroup_find', [], dict(
+                user=user1, no_members=False)),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 netgroup matched',
+                result=[
+                    {
+                        'dn': fuzzy_netgroupdn,
                         'memberhost_host': (host1,),
                         'memberhost_hostgroup': (hostgroup1,),
                         'memberuser_user': (user1,),
@@ -875,6 +949,7 @@ class test_netgroup(Declarative):
             ),
         ),
 
+
         dict(
             desc='Search for %r using user' % netgroup1,
             command=('netgroup_find', [], dict(user=user1)),
@@ -885,6 +960,27 @@ class test_netgroup(Declarative):
                 result=[
                     {
                         'dn': fuzzy_netgroupdn,
+                        'cn': [netgroup1],
+                        'description': [u'Test netgroup 1'],
+                        'nisdomainname': [u'%s' % api.env.domain],
+                        'externalhost': [unknown_host],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
+            desc=('Search for all netgroups using empty member user with '
+                  'members'),
+            command=('netgroup_find', [], dict(user=None, no_members=False)),
+            expected=dict(
+                count=2,
+                truncated=False,
+                summary=u'2 netgroups matched',
+                result=[
+                    {
+                        'dn': fuzzy_netgroupdn,
                         'memberhost_host': (host1,),
                         'memberhost_hostgroup': (hostgroup1,),
                         'memberuser_user': (user1,),
@@ -895,10 +991,18 @@ class test_netgroup(Declarative):
                         'nisdomainname': [u'%s' % api.env.domain],
                         'externalhost': [unknown_host],
                     },
+                    {
+                        'dn': fuzzy_netgroupdn,
+                        'memberof_netgroup': (netgroup1,),
+                        'cn': [netgroup2],
+                        'description': [u'Test netgroup 2'],
+                        'nisdomainname': [u'%s' % api.env.domain],
+                    },
                 ],
             ),
         ),
 
+
         dict(
             desc='Search for all netgroups using empty member user',
             command=('netgroup_find', [], dict(user=None)),
@@ -909,11 +1013,6 @@ class test_netgroup(Declarative):
                 result=[
                     {
                         'dn': fuzzy_netgroupdn,
-                        'memberhost_host': (host1,),
-                        'memberhost_hostgroup': (hostgroup1,),
-                        'memberuser_user': (user1,),
-                        'memberuser_group': (group1,),
-                        'member_netgroup': (netgroup2,),
                         'cn': [netgroup1],
                         'description': [u'Test netgroup 1'],
                         'nisdomainname': [u'%s' % api.env.domain],
@@ -921,7 +1020,6 @@ class test_netgroup(Declarative):
                     },
                     {
                         'dn': fuzzy_netgroupdn,
-                        'memberof_netgroup': (netgroup1,),
                         'cn': [netgroup2],
                         'description': [u'Test netgroup 2'],
                         'nisdomainname': [u'%s' % api.env.domain],
@@ -930,6 +1028,7 @@ class test_netgroup(Declarative):
             ),
         ),
 
+
         dict(
             desc='Update %r' % netgroup1,
             command=('netgroup_mod', [netgroup1],
diff --git a/ipatests/test_xmlrpc/test_old_permission_plugin.py b/ipatests/test_xmlrpc/test_old_permission_plugin.py
index 3e086b541d5aada550950ee328aa807bfd276851..38662c21fede6504eeef903eb014c026e54504e9 100644
--- a/ipatests/test_xmlrpc/test_old_permission_plugin.py
+++ b/ipatests/test_xmlrpc/test_old_permission_plugin.py
@@ -269,6 +269,30 @@ class test_old_permission(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % permission1,
+            command=('permission_find', [permission1], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'member_privilege': [privilege1],
+                        'type': u'user',
+                        'permissions': [u'write'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'V2', u'SYSTEM'],
+                        'subtree': u'ldap:///%s' % users_dn,
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % permission1,
             command=('permission_find', [permission1], {}),
             expected=dict(
@@ -280,6 +304,30 @@ class test_old_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
+                        'type': u'user',
+                        'permissions': [u'write'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'V2', u'SYSTEM'],
+                        'subtree': u'ldap:///%s' % users_dn,
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
+            desc='Search for %r using --name with members' % permission1,
+            command=('permission_find', [], {
+                'cn': permission1, 'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
                         'member_privilege': [privilege1],
                         'type': u'user',
                         'permissions': [u'write'],
@@ -304,7 +352,6 @@ class test_old_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member_privilege': [privilege1],
                         'type': u'user',
                         'permissions': [u'write'],
                         'ipapermbindruletype': [u'permission'],
@@ -329,6 +376,30 @@ class test_old_permission(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % privilege1,
+            command=('permission_find', [privilege1], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'member_privilege': [privilege1],
+                        'type': u'user',
+                        'permissions': [u'write'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'V2', u'SYSTEM'],
+                        'subtree': u'ldap:///%s' % users_dn,
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % privilege1,
             command=('permission_find', [privilege1], {}),
             expected=dict(
@@ -340,7 +411,6 @@ class test_old_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member_privilege': [privilege1],
                         'type': u'user',
                         'permissions': [u'write'],
                         'ipapermbindruletype': [u'permission'],
@@ -353,8 +423,9 @@ class test_old_permission(Declarative):
 
 
         dict(
-            desc='Search for %r with --raw' % permission1,
-            command=('permission_find', [permission1], {'raw' : True}),
+            desc='Search for %r with --raw with members' % permission1,
+            command=('permission_find', [permission1], {
+                'raw': True, 'no_members': False}),
             expected=dict(
                 count=1,
                 truncated=False,
@@ -379,6 +450,38 @@ class test_old_permission(Declarative):
 
 
         dict(
+            desc='Search for %r with --raw' % permission1,
+            command=('permission_find', [permission1], {'raw': True}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'aci': [
+                            u'(targetfilter = "(objectclass=posixaccount)")'
+                            u'(version 3.0;acl "permission:testperm";'
+                            u'allow (write) groupdn = "ldap:///%s";;)' %
+                            DN(
+                                ('cn', 'testperm'), ('cn', 'permissions'),
+                                ('cn', 'pbac'), api.env.basedn
+                            )
+                        ],
+                        'ipapermright': [u'write'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'V2', u'SYSTEM'],
+                        'ipapermtargetfilter': [u'(objectclass=posixaccount)'],
+                        'ipapermlocation': [users_dn],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Create %r' % permission2,
             command=(
                 'permission_add', [permission2], dict(
@@ -407,6 +510,40 @@ class test_old_permission(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % permission1,
+            command=('permission_find', [permission1], {'no_members': False}),
+            expected=dict(
+                count=2,
+                truncated=False,
+                summary=u'2 permissions matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'member_privilege': [privilege1],
+                        'type': u'user',
+                        'permissions': [u'write'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'V2', u'SYSTEM'],
+                        'subtree': u'ldap:///%s' % users_dn,
+                    },
+                    {
+                        'dn': permission2_dn,
+                        'cn': [permission2],
+                        'objectclass': objectclasses.permission,
+                        'type': u'user',
+                        'permissions': [u'write'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'V2', u'SYSTEM'],
+                        'subtree': u'ldap:///%s' % users_dn,
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % permission1,
             command=('permission_find', [permission1], {}),
             expected=dict(
@@ -418,7 +555,6 @@ class test_old_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member_privilege': [privilege1],
                         'type': u'user',
                         'permissions': [u'write'],
                         'ipapermbindruletype': [u'permission'],
@@ -486,8 +622,8 @@ class test_old_permission(Declarative):
 
 
         dict(
-            desc='Search for %r' % privilege1,
-            command=('privilege_find', [privilege1], {}),
+            desc='Search for %r with members' % privilege1,
+            command=('privilege_find', [privilege1], {'no_members': False}),
             expected=dict(
                 count=1,
                 truncated=False,
@@ -505,6 +641,60 @@ class test_old_permission(Declarative):
 
 
         dict(
+            desc='Search for %r' % privilege1,
+            command=('privilege_find', [privilege1], {}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 privilege matched',
+                result=[
+                    {
+                        'dn': privilege1_dn,
+                        'cn': [privilege1],
+                        'description': [u'privilege desc. 1'],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
+            desc=('Search for %r with a limit of 1 (truncated) with members' %
+                  permission1),
+            command=('permission_find', [permission1], dict(
+                sizelimit=1, no_members=False)),
+            expected=dict(
+                count=1,
+                truncated=True,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'member_privilege': [privilege1],
+                        'type': u'user',
+                        'permissions': [u'write'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'V2', u'SYSTEM'],
+                        'subtree': u'ldap:///%s' % users_dn,
+                    },
+                ],
+                messages=({
+                    'message': (u'Search result has been truncated: '
+                                u'Configured size limit exceeded'),
+                    'code': 13017,
+                    'type': u'warning',
+                    'name': u'SearchResultTruncated',
+                    'data': {
+                        'reason': u"Configured size limit exceeded"
+                    }
+                },),
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r with a limit of 1 (truncated)' % permission1,
             command=('permission_find', [permission1], dict(sizelimit=1)),
             expected=dict(
@@ -516,7 +706,6 @@ class test_old_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member_privilege': [privilege1],
                         'type': u'user',
                         'permissions': [u'write'],
                         'ipapermbindruletype': [u'permission'],
@@ -550,7 +739,6 @@ class test_old_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member_privilege': [privilege1],
                         'type': u'user',
                         'permissions': [u'write'],
                         'ipapermbindruletype': [u'permission'],
@@ -776,9 +964,11 @@ class test_old_permission(Declarative):
 
 
         dict(
-            desc='Search for %r using --subtree' % permission1,
-            command=('permission_find', [],
-                     {'subtree': u'ldap:///%s' % DN(('cn', 'accounts'), api.env.basedn)}),
+            desc='Search for %r using --subtree with members' % permission1,
+            command=('permission_find', [], {
+                'subtree': u'ldap:///%s' % DN(
+                    ('cn', 'accounts'), api.env.basedn),
+                'no_members': False}),
             expected=dict(
                 count=1,
                 truncated=False,
@@ -801,6 +991,32 @@ class test_old_permission(Declarative):
 
 
         dict(
+            desc='Search for %r using --subtree' % permission1,
+            command=('permission_find', [], {
+                'subtree': u'ldap:///%s' % DN(
+                    ('cn', 'accounts'), api.env.basedn)}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn':permission1_renamed_ucase_dn,
+                        'cn':[permission1_renamed_ucase],
+                        'objectclass': objectclasses.permission,
+                        'subtree':u'ldap:///%s' % DN(
+                            ('cn', 'accounts'), api.env.basedn),
+                        'permissions':[u'write'],
+                        'memberof':u'ipausers',
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'V2', u'SYSTEM'],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search using nonexistent --subtree',
             command=('permission_find', [], {'subtree': u'ldap:///foo=bar'}),
             expected=dict(
@@ -813,8 +1029,9 @@ class test_old_permission(Declarative):
 
 
         dict(
-            desc='Search using --targetgroup',
-            command=('permission_find', [], {'targetgroup': u'ipausers'}),
+            desc='Search using --targetgroup with members',
+            command=('permission_find', [], {
+                'targetgroup': u'ipausers', 'no_members': False}),
             expected=dict(
                 count=1,
                 truncated=False,
@@ -842,6 +1059,33 @@ class test_old_permission(Declarative):
 
 
         dict(
+            desc='Search using --targetgroup',
+            command=('permission_find', [], {'targetgroup': u'ipausers'}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': DN(('cn', 'System: Add User to default group'),
+                                 api.env.container_permission, api.env.basedn),
+                        'cn': [u'System: Add User to default group'],
+                        'objectclass': objectclasses.permission,
+                        'attrs': [u'member'],
+                        'targetgroup': u'ipausers',
+                        'permissions': [u'write'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermtarget': [DN('cn=ipausers', groups_dn)],
+                        'subtree': u'ldap:///%s' % groups_dn,
+                        'ipapermdefaultattr': [u'member'],
+                        'ipapermissiontype': [u'V2', u'MANAGED', u'SYSTEM'],
+                    }
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Delete %r' % permission1_renamed_ucase,
             command=('permission_del', [permission1_renamed_ucase], {}),
             expected=dict(
diff --git a/ipatests/test_xmlrpc/test_permission_plugin.py b/ipatests/test_xmlrpc/test_permission_plugin.py
index cefa93f556f6760755aa39e8349b06d41941006e..938ab4bb652d87329f202e084e9cab4cb2d8f48c 100644
--- a/ipatests/test_xmlrpc/test_permission_plugin.py
+++ b/ipatests/test_xmlrpc/test_permission_plugin.py
@@ -541,6 +541,31 @@ class test_permission(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % permission1,
+            command=('permission_find', [permission1], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'member_privilege': [privilege1],
+                        'type': [u'user'],
+                        'ipapermright': [u'write'],
+                        'attrs': [u'sn'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'SYSTEM', u'V2'],
+                        'ipapermlocation': [users_dn],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % permission1,
             command=('permission_find', [permission1], {}),
             expected=dict(
@@ -552,6 +577,31 @@ class test_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
+                        'type': [u'user'],
+                        'ipapermright': [u'write'],
+                        'attrs': [u'sn'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'SYSTEM', u'V2'],
+                        'ipapermlocation': [users_dn],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
+            desc='Search for %r using --name with members' % permission1,
+            command=('permission_find', [], {
+                'cn': permission1, 'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
                         'member_privilege': [privilege1],
                         'type': [u'user'],
                         'ipapermright': [u'write'],
@@ -577,7 +627,6 @@ class test_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member_privilege': [privilege1],
                         'type': [u'user'],
                         'ipapermright': [u'write'],
                         'attrs': [u'sn'],
@@ -603,6 +652,31 @@ class test_permission(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % privilege1,
+            command=('permission_find', [privilege1], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'member_privilege': [privilege1],
+                        'type': [u'user'],
+                        'ipapermright': [u'write'],
+                        'attrs': [u'sn'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'SYSTEM', u'V2'],
+                        'ipapermlocation': [users_dn],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % privilege1,
             command=('permission_find', [privilege1], {}),
             expected=dict(
@@ -614,7 +688,6 @@ class test_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member_privilege': [privilege1],
                         'type': [u'user'],
                         'ipapermright': [u'write'],
                         'attrs': [u'sn'],
@@ -628,6 +701,38 @@ class test_permission(Declarative):
 
 
         dict(
+            desc='Search for %r with --raw with members' % permission1,
+            command=('permission_find', [permission1], {
+                'raw': True, 'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'member': [privilege1_dn],
+                        'ipapermincludedattr': [u'sn'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermright': [u'write'],
+                        'ipapermissiontype': [u'SYSTEM', u'V2'],
+                        'ipapermlocation': [users_dn],
+                        'ipapermtargetfilter': [u'(objectclass=posixaccount)'],
+                        'aci': ['(targetattr = "sn")'
+                                '(targetfilter = "(objectclass=posixaccount)")' +
+                                '(version 3.0;acl "permission:%(name)s";'
+                                'allow (write) groupdn = "ldap:///%(pdn)s";)' %
+                                {'name': permission1,
+                                 'pdn': permission1_dn}],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r with --raw' % permission1,
             command=('permission_find', [permission1], {'raw': True}),
             expected=dict(
@@ -639,7 +744,6 @@ class test_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member': [privilege1_dn],
                         'ipapermincludedattr': [u'sn'],
                         'ipapermbindruletype': [u'permission'],
                         'ipapermright': [u'write'],
@@ -696,6 +800,43 @@ class test_permission(Declarative):
         ),
 
         dict(
+            desc='Search for %r with members' % permission1,
+            command=('permission_find', [permission1], {
+                'no_members': False}),
+            expected=dict(
+                count=2,
+                truncated=False,
+                summary=u'2 permissions matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'member_privilege': [privilege1],
+                        'type': [u'user'],
+                        'ipapermright': [u'write'],
+                        'attrs': [u'sn'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'SYSTEM', u'V2'],
+                        'ipapermlocation': [users_dn],
+                    },
+                    {
+                        'dn': permission2_dn,
+                        'cn': [permission2],
+                        'objectclass': objectclasses.permission,
+                        'type': [u'user'],
+                        'ipapermright': [u'write'],
+                        'attrs': [u'cn'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'SYSTEM', u'V2'],
+                        'ipapermlocation': [users_dn],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % permission1,
             command=('permission_find', [permission1], {}),
             expected=dict(
@@ -707,7 +848,6 @@ class test_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member_privilege': [privilege1],
                         'type': [u'user'],
                         'ipapermright': [u'write'],
                         'attrs': [u'sn'],
@@ -777,8 +917,8 @@ class test_permission(Declarative):
 
 
         dict(
-            desc='Search for %r' % privilege1,
-            command=('privilege_find', [privilege1], {}),
+            desc='Search for %r with members' % privilege1,
+            command=('privilege_find', [privilege1], {'no_members': False}),
             expected=dict(
                 count=1,
                 truncated=False,
@@ -796,6 +936,63 @@ class test_permission(Declarative):
 
 
         dict(
+            desc='Search for %r' % privilege1,
+            command=('privilege_find', [privilege1], {}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 privilege matched',
+                result=[
+                    {
+                        'dn': privilege1_dn,
+                        'cn': [privilege1],
+                        'description': [u'privilege desc. 1'],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
+            desc=('Search for %r with a limit of 1 (truncated) with members' %
+                  permission1),
+            command=('permission_find', [permission1],
+                dict(sizelimit=1, no_members=False)),
+            expected=dict(
+                count=1,
+                truncated=True,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': permission1_dn,
+                        'cn': [permission1],
+                        'objectclass': objectclasses.permission,
+                        'member_privilege': [privilege1],
+                        'type': [u'user'],
+                        'ipapermright': [u'write'],
+                        'attrs': [u'sn'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'SYSTEM', u'V2'],
+                        'ipapermlocation': [users_dn],
+                    },
+                ],
+                messages=(
+                    {
+                        'message': (u'Search result has been truncated: '
+                                    u'Configured size limit exceeded'),
+                        'code': 13017,
+                        'type': u'warning',
+                        'name': u'SearchResultTruncated',
+                        'data': {
+                            'reason': u"Configured size limit exceeded"
+                        }
+                    },
+                ),
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r with a limit of 1 (truncated)' % permission1,
             command=('permission_find', [permission1], dict(sizelimit=1)),
             expected=dict(
@@ -807,7 +1004,6 @@ class test_permission(Declarative):
                         'dn': permission1_dn,
                         'cn': [permission1],
                         'objectclass': objectclasses.permission,
-                        'member_privilege': [privilege1],
                         'type': [u'user'],
                         'ipapermright': [u'write'],
                         'attrs': [u'sn'],
@@ -850,7 +1046,6 @@ class test_permission(Declarative):
                         'ipapermbindruletype': [u'permission'],
                         'ipapermissiontype': [u'SYSTEM', u'V2'],
                         'ipapermlocation': [users_dn],
-                        'member_privilege': [privilege1],
                     },
                     {
                         'dn': permission2_dn,
@@ -1179,6 +1374,34 @@ class test_permission(Declarative):
         ),
 
         dict(
+            desc=('Search for %r using --subtree with membes' %
+                  permission1_renamed_ucase),
+            command=('permission_find', [],
+                     {'ipapermlocation': u'ldap:///%s' % admin_dn,
+                     'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn':permission1_renamed_ucase_dn,
+                        'cn':[permission1_renamed_ucase],
+                        'objectclass': objectclasses.permission,
+                        'member_privilege':[privilege1],
+                        'ipapermlocation': [admin_dn],
+                        'ipapermright':[u'write'],
+                        'memberof':[u'ipausers'],
+                        'attrs': [u'sn'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermissiontype': [u'SYSTEM', u'V2'],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r using --subtree' % permission1_renamed_ucase,
             command=('permission_find', [],
                      {'ipapermlocation': u'ldap:///%s' % admin_dn}),
@@ -1191,7 +1414,6 @@ class test_permission(Declarative):
                         'dn':permission1_renamed_ucase_dn,
                         'cn':[permission1_renamed_ucase],
                         'objectclass': objectclasses.permission,
-                        'member_privilege':[privilege1],
                         'ipapermlocation': [admin_dn],
                         'ipapermright':[u'write'],
                         'memberof':[u'ipausers'],
@@ -1213,8 +1435,9 @@ class test_permission(Declarative):
 
 
         dict(
-            desc='Search using --targetgroup',
-            command=('permission_find', [], {'targetgroup': u'ipausers'}),
+            desc='Search using --targetgroup with members',
+            command=('permission_find', [], {
+                'targetgroup': u'ipausers', 'no_members': False}),
             expected=dict(
                 count=1,
                 truncated=False,
@@ -1244,6 +1467,34 @@ class test_permission(Declarative):
 
 
         dict(
+            desc='Search using --targetgroup',
+            command=('permission_find', [], {'targetgroup': u'ipausers'}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 permission matched',
+                result=[
+                    {
+                        'dn': DN(('cn', 'System: Add User to default group'),
+                                 api.env.container_permission, api.env.basedn),
+                        'cn': [u'System: Add User to default group'],
+                        'objectclass': objectclasses.permission,
+                        'attrs': [u'member'],
+                        'targetgroup': [u'ipausers'],
+                        'ipapermright': [u'write'],
+                        'ipapermbindruletype': [u'permission'],
+                        'ipapermtarget': [DN(
+                            'cn=ipausers', api.env.container_group,
+                            api.env.basedn)],
+                        'ipapermlocation': [groups_dn],
+                        'ipapermdefaultattr': [u'member'],
+                        'ipapermissiontype': [u'V2', u'MANAGED', u'SYSTEM'],
+                    }
+                ],
+            ),
+        ),
+
+        dict(
             desc='Delete %r' % permission1_renamed_ucase,
             command=('permission_del', [permission1_renamed_ucase], {}),
             expected=dict(
diff --git a/ipatests/test_xmlrpc/test_privilege_plugin.py b/ipatests/test_xmlrpc/test_privilege_plugin.py
index ce9afe2fdc7183a8476edc47aa8f6f03b76f19d9..c80cfef7d21e6d850ac805d9fee8f49e3289f322 100644
--- a/ipatests/test_xmlrpc/test_privilege_plugin.py
+++ b/ipatests/test_xmlrpc/test_privilege_plugin.py
@@ -172,6 +172,25 @@ class test_privilege(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % privilege1,
+            command=('privilege_find', [privilege1], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 privilege matched',
+                result=[
+                    {
+                        'dn': privilege1_dn,
+                        'cn': [privilege1],
+                        'description': [u'privilege desc. 1'],
+                        'memberof_permission': [permission1],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % privilege1,
             command=('privilege_find', [privilege1], {}),
             expected=dict(
@@ -183,6 +202,24 @@ class test_privilege(Declarative):
                         'dn': privilege1_dn,
                         'cn': [privilege1],
                         'description': [u'privilege desc. 1'],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
+            desc='Search for %r with members' % privilege1,
+            command=('privilege_find', [privilege1], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 privilege matched',
+                result=[
+                    {
+                        'dn': privilege1_dn,
+                        'cn': [privilege1],
+                        'description': [u'privilege desc. 1'],
                         'memberof_permission': [permission1],
                     },
                 ],
@@ -202,7 +239,6 @@ class test_privilege(Declarative):
                         'dn': privilege1_dn,
                         'cn': [privilege1],
                         'description': [u'privilege desc. 1'],
-                        'memberof_permission': [permission1],
                     },
                 ],
             ),
@@ -281,8 +317,8 @@ class test_privilege(Declarative):
 
 
         dict(
-            desc='Search for %r' % privilege1,
-            command=('privilege_find', [privilege1], {}),
+            desc='Search for %r with memebers' % privilege1,
+            command=('privilege_find', [privilege1], {'no_members': False}),
             expected=dict(
                 count=1,
                 truncated=False,
@@ -300,6 +336,24 @@ class test_privilege(Declarative):
 
 
         dict(
+            desc='Search for %r' % privilege1,
+            command=('privilege_find', [privilege1], {}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 privilege matched',
+                result=[
+                    {
+                        'dn': privilege1_dn,
+                        'cn': [privilege1],
+                        'description': [u'privilege desc. 1'],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Update %r' % privilege1,
             command=(
                 'privilege_mod', [privilege1], dict(description=u'New desc 1')
diff --git a/ipatests/test_xmlrpc/test_role_plugin.py b/ipatests/test_xmlrpc/test_role_plugin.py
index d06daac6902cdf569920f908d99e5ee5c0cdfa43..2c368b3518cda3d11fadce69f8bdfc02edfcf719 100644
--- a/ipatests/test_xmlrpc/test_role_plugin.py
+++ b/ipatests/test_xmlrpc/test_role_plugin.py
@@ -292,6 +292,26 @@ class test_role(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % role1,
+            command=('role_find', [role1], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 role matched',
+                result=[
+                    {
+                        'dn': role1_dn,
+                        'cn': [role1],
+                        'description': [u'role desc 1'],
+                        'member_group': [group1],
+                        'memberof_privilege': [privilege1],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % role1,
             command=('role_find', [role1], {}),
             expected=dict(
@@ -303,6 +323,24 @@ class test_role(Declarative):
                         'dn': role1_dn,
                         'cn': [role1],
                         'description': [u'role desc 1'],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
+            desc='Search for %r with members' % search,
+            command=('role_find', [search], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 role matched',
+                result=[
+                    {
+                        'dn': role1_dn,
+                        'cn': [role1],
+                        'description': [u'role desc 1'],
                         'member_group': [group1],
                         'memberof_privilege': [privilege1],
                     },
@@ -323,8 +361,6 @@ class test_role(Declarative):
                         'dn': role1_dn,
                         'cn': [role1],
                         'description': [u'role desc 1'],
-                        'member_group': [group1],
-                        'memberof_privilege': [privilege1],
                     },
                 ],
             ),
@@ -350,6 +386,26 @@ class test_role(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % role1,
+            command=('role_find', [role1], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 role matched',
+                result=[
+                    {
+                        'dn': role1_dn,
+                        'cn': [role1],
+                        'description': [u'role desc 1'],
+                        'member_group': [group1],
+                        'memberof_privilege': [privilege1],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % role1,
             command=('role_find', [role1], {}),
             expected=dict(
@@ -361,9 +417,32 @@ class test_role(Declarative):
                         'dn': role1_dn,
                         'cn': [role1],
                         'description': [u'role desc 1'],
+                    },
+                ],
+            ),
+        ),
+
+
+        dict(
+            desc='Search for %r with members' % search,
+            command=('role_find', [search], {'no_members': False}),
+            expected=dict(
+                count=2,
+                truncated=False,
+                summary=u'2 roles matched',
+                result=[
+                    {
+                        'dn': role1_dn,
+                        'cn': [role1],
+                        'description': [u'role desc 1'],
                         'member_group': [group1],
                         'memberof_privilege': [privilege1],
                     },
+                    {
+                        'dn': role2_dn,
+                        'cn': [role2],
+                        'description': [u'role desc 2'],
+                    },
                 ],
             ),
         ),
@@ -381,8 +460,6 @@ class test_role(Declarative):
                         'dn': role1_dn,
                         'cn': [role1],
                         'description': [u'role desc 1'],
-                        'member_group': [group1],
-                        'memberof_privilege': [privilege1],
                     },
                     {
                         'dn': role2_dn,
diff --git a/ipatests/test_xmlrpc/test_service_plugin.py b/ipatests/test_xmlrpc/test_service_plugin.py
index 9bd082916509fd82555afb4380d314bcb80d44a5..663e1f36d4796cc236397735611e699fdcb571cd 100644
--- a/ipatests/test_xmlrpc/test_service_plugin.py
+++ b/ipatests/test_xmlrpc/test_service_plugin.py
@@ -251,6 +251,25 @@ class test_service(Declarative):
 
 
         dict(
+            desc='Search for %r with members' % service1,
+            command=('service_find', [service1], {'no_members': False}),
+            expected=dict(
+                count=1,
+                truncated=False,
+                summary=u'1 service matched',
+                result=[
+                    dict(
+                        dn=service1dn,
+                        krbprincipalname=[service1],
+                        managedby_host=[fqdn1],
+                        has_keytab=False,
+                    ),
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Search for %r' % service1,
             command=('service_find', [service1], {}),
             expected=dict(
@@ -261,7 +280,6 @@ class test_service(Declarative):
                     dict(
                         dn=service1dn,
                         krbprincipalname=[service1],
-                        managedby_host=[fqdn1],
                         has_keytab=False,
                     ),
                 ],
diff --git a/ipatests/test_xmlrpc/test_servicedelegation_plugin.py b/ipatests/test_xmlrpc/test_servicedelegation_plugin.py
index 02dc0800fdfe21fd5e1a972358cae6e1b0e48e6e..bf789758192967f104b4017121f983c1a88f1641 100644
--- a/ipatests/test_xmlrpc/test_servicedelegation_plugin.py
+++ b/ipatests/test_xmlrpc/test_servicedelegation_plugin.py
@@ -134,8 +134,8 @@ class test_servicedelegation(Declarative):
 
 
         dict(
-            desc='Search for all rules',
-            command=('servicedelegationrule_find', [], {}),
+            desc='Search for all rules with members',
+            command=('servicedelegationrule_find', [], {'no_members': False}),
             expected=dict(
                 summary=u'3 service delegation rules matched',
                 count=3,
@@ -163,6 +163,32 @@ class test_servicedelegation(Declarative):
 
 
         dict(
+            desc='Search for all rules',
+            command=('servicedelegationrule_find', [], {}),
+            expected=dict(
+                summary=u'3 service delegation rules matched',
+                count=3,
+                truncated=False,
+                result=[
+                    {
+                        'dn': get_servicedelegation_dn(u'ipa-http-delegation'),
+                        'cn': [u'ipa-http-delegation'],
+                        'memberprincipal': [princ1],
+                    },
+                    dict(
+                        dn=get_servicedelegation_dn(rule2),
+                        cn=[rule2],
+                    ),
+                    dict(
+                        dn=get_servicedelegation_dn(rule1),
+                        cn=[rule1],
+                    ),
+                ],
+            ),
+        ),
+
+
+        dict(
             desc='Create target %r' % target1,
             command=(
                 'servicedelegationtarget_add', [target1], {}
diff --git a/ipatests/test_xmlrpc/test_sudocmdgroup_plugin.py b/ipatests/test_xmlrpc/test_sudocmdgroup_plugin.py
index 3f5879c4d90ed9872b9287344583892405bebff3..be47de980a5b05a7f8d94cffb0a14d0ba3caf1f7 100644
--- a/ipatests/test_xmlrpc/test_sudocmdgroup_plugin.py
+++ b/ipatests/test_xmlrpc/test_sudocmdgroup_plugin.py
@@ -152,6 +152,11 @@ class TestSudoCmdGroupSCRUD(XMLRPC_test):
         sudocmdgroup1.ensure_exists()
         sudocmdgroup1.find()
 
+    def test_search_all(self, sudocmdgroup1):
+        """ Search for sudocmdgroup """
+        sudocmdgroup1.ensure_exists()
+        sudocmdgroup1.find(all=True)
+
     def test_create_another(self, sudocmdgroup2):
         """ Create a second sudocmdgroup """
         sudocmdgroup2.create()
diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py
index c576394dda5ed0647588f179da45a4e722f2469e..975b2b876ed566f334e59f0c6183ae1078a2866d 100644
--- a/ipatests/test_xmlrpc/test_user_plugin.py
+++ b/ipatests/test_xmlrpc/test_user_plugin.py
@@ -691,7 +691,7 @@ class TestManagers(XMLRPC_test):
         """ Find user by his manager's UID """
         command = user.make_find_command(manager=user2.uid)
         result = command()
-        user.check_find(result, expected_override=dict(manager=[user2.uid]))
+        user.check_find(result)
 
     def test_delete_both_user_and_manager(self, user, user2):
         """ Delete both user and its manager at once """
diff --git a/ipatests/test_xmlrpc/tracker/host_plugin.py b/ipatests/test_xmlrpc/tracker/host_plugin.py
index d8b59b98907dff955f415b6edb0ce34d74e54f19..d54901fa5f8e5d38619161826a3b5887f563b828 100644
--- a/ipatests/test_xmlrpc/tracker/host_plugin.py
+++ b/ipatests/test_xmlrpc/tracker/host_plugin.py
@@ -43,7 +43,10 @@ class HostTracker(Tracker):
     update_keys = retrieve_keys - {'dn'}
     managedby_keys = retrieve_keys - {'has_keytab', 'has_password'}
     allowedto_keys = retrieve_keys - {'has_keytab', 'has_password'}
-    find_keys = retrieve_keys - {'has_keytab', 'has_password'}
+    find_keys = retrieve_keys - {
+        'has_keytab', 'has_password', 'memberof_hostgroup',
+        'memberofindirect_hostgroup', 'managedby_host',
+    }
     find_all_keys = retrieve_all_keys - {'has_keytab', 'has_password'}
 
     def __init__(self, name, fqdn=None, default_version=None):
diff --git a/ipatests/test_xmlrpc/tracker/hostgroup_plugin.py b/ipatests/test_xmlrpc/tracker/hostgroup_plugin.py
index 77b43b9d37b8a0911cd6f0057b1a29b27194cb79..8b63c90b0e202155ffd5ba75e56631554a530bed 100644
--- a/ipatests/test_xmlrpc/tracker/hostgroup_plugin.py
+++ b/ipatests/test_xmlrpc/tracker/hostgroup_plugin.py
@@ -24,6 +24,15 @@ class HostGroupTracker(Tracker):
 
     add_member_keys = retrieve_keys | {u'member_host'}
 
+    find_keys = {
+        u'dn', u'cn', u'description',
+    }
+    find_all_keys = {
+        u'dn', u'cn', u'member_host', u'description', u'member_hostgroup',
+        u'memberindirect_host', u'ipauniqueid', u'objectclass',
+        u'mepmanagedentry',
+    }
+
     def __init__(self, name, description=u'HostGroup desc'):
         super(HostGroupTracker, self).__init__(default_version=None)
         self.cn = name
@@ -182,9 +191,9 @@ class HostGroupTracker(Tracker):
     def check_find(self, result, all=False, raw=False):
         """ Checks 'hostgroup_find' command result """
         if all:
-            expected = self.filter_attrs(self.retrieve_all_keys)
+            expected = self.filter_attrs(self.find_all_keys)
         else:
-            expected = self.filter_attrs(self.retrieve_keys)
+            expected = self.filter_attrs(self.find_keys)
 
         assert_deepequal(dict(
             count=1,
diff --git a/ipatests/test_xmlrpc/tracker/sudocmd_plugin.py b/ipatests/test_xmlrpc/tracker/sudocmd_plugin.py
index eb72e4ba24c21d0b44bdda92581639737093c016..003d39ac0fae82b2ba97247e1e6286205d45a882 100644
--- a/ipatests/test_xmlrpc/tracker/sudocmd_plugin.py
+++ b/ipatests/test_xmlrpc/tracker/sudocmd_plugin.py
@@ -18,6 +18,9 @@ class SudoCmdTracker(Tracker):
     create_keys = retrieve_all_keys
     update_keys = retrieve_keys - {u'dn'}
 
+    find_keys = {u'dn', u'sudocmd', u'description'}
+    find_all_keys = retrieve_all_keys
+
     def __init__(self, command, description="Test sudo command"):
         super(SudoCmdTracker, self).__init__(default_version=None)
         self.cmd = command
@@ -93,9 +96,9 @@ class SudoCmdTracker(Tracker):
     def check_find(self, result, all=False, raw=False):
         """ Checks 'sudocmd_find' command result """
         if all:
-            expected = self.filter_attrs(self.retrieve_all_keys)
+            expected = self.filter_attrs(self.find_all_keys)
         else:
-            expected = self.filter_attrs(self.retrieve_keys)
+            expected = self.filter_attrs(self.find_keys)
 
         assert_deepequal(dict(
             count=1,
diff --git a/ipatests/test_xmlrpc/tracker/sudocmdgroup_plugin.py b/ipatests/test_xmlrpc/tracker/sudocmdgroup_plugin.py
index 2de9bca787fcc8f13ecf33aece67640e406a5e57..2b354ef51e1337661ff764fb7138eb5bef4a7931 100644
--- a/ipatests/test_xmlrpc/tracker/sudocmdgroup_plugin.py
+++ b/ipatests/test_xmlrpc/tracker/sudocmdgroup_plugin.py
@@ -24,6 +24,11 @@ class SudoCmdGroupTracker(Tracker):
 
     add_member_keys = retrieve_keys | {u'member_sudocmd'}
 
+    find_keys = {
+        u'dn', u'cn', u'description', u'member_sudocmdgroup'}
+    find_all_keys = find_keys | {
+        u'ipauniqueid', u'objectclass', u'mepmanagedentry'}
+
     def __init__(self, name, description=u'SudoCmdGroup desc'):
         super(SudoCmdGroupTracker, self).__init__(default_version=None)
         self.cn = name
@@ -168,9 +173,9 @@ class SudoCmdGroupTracker(Tracker):
     def check_find(self, result, all=False, raw=False):
         """ Checks 'sudocmdgroup_find' command result """
         if all:
-            expected = self.filter_attrs(self.retrieve_all_keys)
+            expected = self.filter_attrs(self.find_all_keys)
         else:
-            expected = self.filter_attrs(self.retrieve_keys)
+            expected = self.filter_attrs(self.find_keys)
 
         assert_deepequal(dict(
             count=1,
diff --git a/ipatests/test_xmlrpc/tracker/user_plugin.py b/ipatests/test_xmlrpc/tracker/user_plugin.py
index 5acfc63cd62e28c7dd3ce1060bbf4fd262920f22..261ea69e1c713b61017cda7fb858340c070ab6e7 100644
--- a/ipatests/test_xmlrpc/tracker/user_plugin.py
+++ b/ipatests/test_xmlrpc/tracker/user_plugin.py
@@ -52,7 +52,8 @@ class UserTracker(Tracker):
     activate_keys = retrieve_keys
 
     find_keys = retrieve_keys - {
-        u'mepmanagedentry', u'memberof_group', u'has_keytab', u'has_password'
+        u'mepmanagedentry', u'memberof_group', u'has_keytab', u'has_password',
+        u'manager',
     }
     find_all_keys = retrieve_all_keys - {
         u'has_keytab', u'has_password'
-- 
2.5.5

From abb192cf8d4396da25b03f731c4fb56f44ca743e Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Fri, 8 Apr 2016 16:17:42 +0200
Subject: [PATCH 2/2] Performance: add membership cache

Membership cache temporarily keeps mappings between DN and primary_key.
This is beneficial for members that doesn't have primary keys as part of
DN and requires extra LDAP search.

https://fedorahosted.org/freeipa/ticket/4995
---
 ipalib/plugins/baseldap.py | 72 ++++++++++++++++++++++++++++++----------------
 1 file changed, 48 insertions(+), 24 deletions(-)

diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 9c77fd62e9a8d8c7147f5ba055f4a9f30ee8e559..da12619d601c6b49c08b5952335f8310866423f5 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -639,39 +639,59 @@ class LDAPObject(Object):
         oc = [x.lower() for x in classes]
         return objectclass.lower() in oc
 
-    def convert_attribute_members(self, entry_attrs, *keys, **options):
+    def convert_attribute_members(self, entry_attrs, container_cache=None,
+                                  member_cache=None, **options):
+        """
+        Method convert members attributes, please keep this method as fast as
+        possible
+
+        :param container_cache: dict containing LDAP objects, should be empty
+        dict before first usage, use only inside *-find methods otherwise
+        the cache has not effect
+        :param member_cache: dict containing members, should be empty dict
+        before first usage, use only inside *-find methods otherwise the cache
+        has no effect
+        """
         if options.get('raw', False):
             return
 
-        container_dns = {}
-        new_attrs = {}
+        if container_cache is None:
+            container_cache = {}
 
         for attr in self.attribute_members:
-            try:
-                value = entry_attrs.raw[attr]
-            except KeyError:
+            # performance: do not use exceptions here
+            if attr not in entry_attrs:
                 continue
+
+            value = entry_attrs.raw[attr]
             del entry_attrs[attr]
 
             for member in value:
                 memberdn = DN(member)
                 for ldap_obj_name in self.attribute_members[attr]:
                     ldap_obj = self.api.Object[ldap_obj_name]
-                    try:
-                        container_dn = container_dns[ldap_obj_name]
-                    except KeyError:
+
+                    # performance: do not use exceptions here
+                    if ldap_obj_name in container_cache:
+                        container_dn = container_cache[ldap_obj_name]
+                    else:
                         container_dn = DN(ldap_obj.container_dn, api.env.basedn)
-                        container_dns[ldap_obj_name] = container_dn
+                        container_cache[ldap_obj_name] = container_dn
 
                     if memberdn.endswith(container_dn):
-                        new_value = ldap_obj.get_primary_key_from_dn(memberdn)
                         new_attr_name = '%s_%s' % (attr, ldap_obj.name)
-                        try:
-                            new_attr = new_attrs[new_attr_name]
-                        except KeyError:
-                            new_attr = entry_attrs.setdefault(new_attr_name, [])
-                            new_attrs[new_attr_name] = new_attr
+
+                        if member_cache is not None and member in member_cache:
+                            val = member_cache[member]
+                            new_attr = entry_attrs.setdefault(attr, [])
+                            new_attr.append(val)
+                            break
+
+                        new_value = ldap_obj.get_primary_key_from_dn(memberdn)
+                        new_attr = entry_attrs.setdefault(new_attr_name, [])
                         new_attr.append(new_value)
+                        if member_cache is not None:
+                            member_cache[member] = new_value
                         break
 
     def get_indirect_members(self, entry_attrs, attrs_list):
@@ -1226,7 +1246,7 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
             entry_attrs.dn = callback(
                 self, ldap, entry_attrs.dn, entry_attrs, *keys, **options)
 
-        self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+        self.obj.convert_attribute_members(entry_attrs, **options)
 
         dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
@@ -1330,7 +1350,7 @@ class LDAPRetrieve(LDAPQuery):
             entry_attrs.dn = callback(
                 self, ldap, entry_attrs.dn, entry_attrs, *keys, **options)
 
-        self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+        self.obj.convert_attribute_members(entry_attrs, **options)
 
         dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
@@ -1479,7 +1499,7 @@ class LDAPUpdate(LDAPQuery, crud.Update):
             entry_attrs.dn = callback(
                 self, ldap, entry_attrs.dn, entry_attrs, *keys, **options)
 
-        self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+        self.obj.convert_attribute_members(entry_attrs, **options)
 
         entry_attrs = entry_to_dict(entry_attrs, **options)
 
@@ -1711,7 +1731,7 @@ class LDAPAddMember(LDAPModMember):
                 self, ldap, completed, failed, entry_attrs.dn, entry_attrs,
                 *keys, **options)
 
-        self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+        self.obj.convert_attribute_members(entry_attrs, **options)
 
         dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
@@ -1812,7 +1832,7 @@ class LDAPRemoveMember(LDAPModMember):
                 self, ldap, completed, failed, entry_attrs.dn, entry_attrs,
                 *keys, **options)
 
-        self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+        self.obj.convert_attribute_members(entry_attrs, **options)
 
         dn = entry_attrs.dn
         entry_attrs = entry_to_dict(entry_attrs, **options)
@@ -2033,9 +2053,12 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
                 entries.sort(key=sort_key)
 
         if not options.get('raw', False):
+            container_cache = {}
+            member_cache = {}
             for e in entries:
                 self.obj.get_indirect_members(e, attrs_list)
-                self.obj.convert_attribute_members(e, *args, **options)
+                self.obj.convert_attribute_members(
+                    e, container_cache, member_cache, **options)
 
         for (i, e) in enumerate(entries):
             entries[i] = entry_to_dict(e, **options)
@@ -2055,6 +2078,7 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
 
         return result
 
+
     def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
         assert isinstance(base_dn, DN)
         return (filters, base_dn, scope)
@@ -2158,7 +2182,7 @@ class LDAPAddReverseMember(LDAPModReverseMember):
 
         # Update the member data.
         entry_attrs = ldap.get_entry(dn, ['*'])
-        self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+        self.obj.convert_attribute_members(entry_attrs, **options)
 
         for callback in self.get_callbacks('post'):
             (completed, entry_attrs.dn) = callback(
@@ -2257,7 +2281,7 @@ class LDAPRemoveReverseMember(LDAPModReverseMember):
 
         # Update the member data.
         entry_attrs = ldap.get_entry(dn, ['*'])
-        self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+        self.obj.convert_attribute_members(entry_attrs, **options)
 
         for callback in self.get_callbacks('post'):
             (completed, entry_attrs.dn) = callback(
-- 
2.5.5

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to