[Freeipa-devel] [PATCH] group search improvements
Kevin McCarthy
kmccarth at redhat.com
Tue Sep 18 22:53:52 UTC 2007
This patch adds the same functionality user search has to group search:
- async search with results in the event of size/time limits
- return value indicating timeout
- configurable search fields.
This code is very ripe for re-factoring as there is now significant
overlap between group and user search. I didn't want to do it quite
yet, as there's some more I want to do with search (field specification)
and I think that will be a good time to re-factor.
-Kevin
-------------- next part --------------
# HG changeset patch
# User Kevin McCarthy <kmccarth at redhat.com>
# Date 1190156196 25200
# Node ID 4002a364c5bdd0be267d88cb2ea2a25ea65c0eef
# Parent 88832dc9643b967ffed0aa4377512490accfe0e4
Implement asynchronous search for groups.
Use the filter generation code to search on multiple fields.
diff -r 88832dc9643b -r 4002a364c5bd ipa-python/ipaclient.py
--- a/ipa-python/ipaclient.py Tue Sep 18 14:58:30 2007 -0700
+++ b/ipa-python/ipaclient.py Tue Sep 18 15:56:36 2007 -0700
@@ -158,13 +158,14 @@ class IPAClient:
result = self.transport.add_group(group_dict, group_container)
return result
- def find_groups(self, criteria, sattrs=None):
+ def find_groups(self, criteria, sattrs=None, searchlimit=0):
"""Find groups whose cn matches the criteria. Wildcards are
acceptable. Returns a list of Group objects."""
- result = self.transport.find_groups(criteria, sattrs)
-
- groups = []
- for attrs in result:
+ result = self.transport.find_groups(criteria, sattrs, searchlimit)
+ counter = result[0]
+
+ groups = [counter]
+ for attrs in result[1:]:
if attrs is not None:
groups.append(group.Group(attrs))
diff -r 88832dc9643b -r 4002a364c5bd ipa-python/rpcclient.py
--- a/ipa-python/rpcclient.py Tue Sep 18 14:58:30 2007 -0700
+++ b/ipa-python/rpcclient.py Tue Sep 18 15:56:36 2007 -0700
@@ -275,7 +275,7 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- def find_groups (self, criteria, sattrs=None):
+ def find_groups (self, criteria, sattrs=None, searchlimit=0):
"""Return a list containing a Group object for each group that matches
the criteria."""
@@ -284,7 +284,7 @@ class RPCClient:
# None values are not allowed in XML-RPC
if sattrs is None:
sattrs = "__NONE__"
- result = server.find_groups(criteria, sattrs)
+ result = server.find_groups(criteria, sattrs, searchlimit)
except xmlrpclib.Fault, fault:
raise ipaerror.gen_exception(fault.faultCode, fault.faultString)
except socket.error, (value, msg):
diff -r 88832dc9643b -r 4002a364c5bd ipa-server/ipa-gui/ipagui/controllers.py
--- a/ipa-server/ipa-gui/ipagui/controllers.py Tue Sep 18 14:58:30 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/controllers.py Tue Sep 18 15:56:36 2007 -0700
@@ -551,11 +551,11 @@ class Root(controllers.RootController):
if criteria != None and len(criteria) > 0:
try:
groups = client.find_groups(criteria.encode('utf-8'))
- # counter = groups[0]
- # groups = groups[1:]
- # if counter == -1:
- # turbogears.flash("These results are truncated.<br />" +
- # "Please refine your search and try again.")
+ counter = groups[0]
+ groups = groups[1:]
+ if counter == -1:
+ turbogears.flash("These results are truncated.<br />" +
+ "Please refine your search and try again.")
except ipaerror.IPAError, e:
turbogears.flash("Find groups failed: " + str(e))
raise turbogears.redirect("/grouplist")
diff -r 88832dc9643b -r 4002a364c5bd ipa-server/xmlrpc-server/funcs.py
--- a/ipa-server/xmlrpc-server/funcs.py Tue Sep 18 14:58:30 2007 -0700
+++ b/ipa-server/xmlrpc-server/funcs.py Tue Sep 18 15:56:36 2007 -0700
@@ -603,25 +603,72 @@ class IPAServer:
finally:
self.releaseConnection(conn)
- def find_groups (self, criteria, sattrs=None, opts=None):
+ def find_groups (self, criteria, sattrs=None, searchlimit=0, opts=None):
"""Return a list containing a User object for each
existing group that matches the criteria.
"""
+ # Assume the list of fields to search will come from a central
+ # configuration repository. A good format for that would be
+ # a comma-separated list of fields
+ search_fields_conf_str = "cn,description"
+ search_fields = string.split(search_fields_conf_str, ",")
+
criteria = self.__safe_filter(criteria)
-
- filter = "(&(cn=%s)(objectClass=posixGroup))" % criteria
- conn = self.getConnection(opts)
- try:
- results = conn.getList(self.basedn, self.scope, filter, sattrs)
- except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
- results = []
- finally:
- self.releaseConnection(conn)
-
- groups = []
- for u in results:
+ criteria_words = re.split(r'\s+', criteria)
+ criteria_words = filter(lambda value:value!="", criteria_words)
+ if len(criteria_words) == 0:
+ return [0]
+
+ (exact_match_filter, partial_match_filter) = self.__generate_match_filters(
+ search_fields, criteria_words)
+
+ #
+ # further constrain search to just the objectClass
+ # TODO - need to parameterize this into generate_match_filters,
+ # and work it into the field-specification search feature
+ #
+ exact_match_filter = "(&(objectClass=posixGroup)%s)" % exact_match_filter
+ partial_match_filter = "(&(objectClass=posixGroup)%s)" % partial_match_filter
+
+ #
+ # TODO - copy/paste from find_users. needs to be refactored
+ #
+ conn = self.getConnection(opts)
+ try:
+ try:
+ exact_results = conn.getListAsync(self.basedn, self.scope,
+ exact_match_filter, sattrs, 0, None, None, -1, searchlimit)
+ except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+ exact_results = [0]
+
+ try:
+ partial_results = conn.getListAsync(self.basedn, self.scope,
+ partial_match_filter, sattrs, 0, None, None, -1, searchlimit)
+ except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+ partial_results = [0]
+ finally:
+ self.releaseConnection(conn)
+
+ exact_counter = exact_results[0]
+ partial_counter = partial_results[0]
+
+ exact_results = exact_results[1:]
+ partial_results = partial_results[1:]
+
+ # Remove exact matches from the partial_match list
+ exact_dns = set(map(lambda e: e.dn, exact_results))
+ partial_results = filter(lambda e: e.dn not in exact_dns,
+ partial_results)
+
+ if (exact_counter == -1) or (partial_counter == -1):
+ counter = -1
+ else:
+ counter = len(exact_results) + len(partial_results)
+
+ groups = [counter]
+ for u in exact_results + partial_results:
groups.append(self.convert_entry(u))
-
+
return groups
def add_user_to_group(self, user, group, opts=None):
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 2228 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/freeipa-devel/attachments/20070918/c56a2405/attachment.bin>
More information about the Freeipa-devel
mailing list