summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin McCarthy <kmccarth@redhat.com>2007-08-28 16:01:07 -0700
committerKevin McCarthy <kmccarth@redhat.com>2007-08-28 16:01:07 -0700
commite9bd8dee3b0350c08d16d57bfd008a72cb283c48 (patch)
treef02ea70f613862f2e668bbdb691c25295d3aba20
parentef2dc5cefa2f9ba94edea7cfce8913e3f25723bd (diff)
downloadfreeipa-e9bd8dee3b0350c08d16d57bfd008a72cb283c48.tar.gz
freeipa-e9bd8dee3b0350c08d16d57bfd008a72cb283c48.tar.xz
freeipa-e9bd8dee3b0350c08d16d57bfd008a72cb283c48.zip
Change user search to be asynchronous.
This way it returns results even if the search times out. The find_users() search now returns a counter as the first result, which is set to -1 if the results are partial.
-rw-r--r--ipa-python/ipaclient.py10
-rw-r--r--ipa-python/rpcclient.py5
-rw-r--r--ipa-server/ipa-gui/ipagui/controllers.py6
-rw-r--r--ipa-server/ipa-gui/ipagui/static/css/style.css2
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/userlist.kid4
-rw-r--r--ipa-server/ipaserver/ipaldap.py38
-rw-r--r--ipa-server/xmlrpc-server/funcs.py26
7 files changed, 74 insertions, 17 deletions
diff --git a/ipa-python/ipaclient.py b/ipa-python/ipaclient.py
index 9fd51db36..fcfb29f1d 100644
--- a/ipa-python/ipaclient.py
+++ b/ipa-python/ipaclient.py
@@ -94,12 +94,14 @@ class IPAClient:
return result
def find_users(self, criteria, sattrs=None):
- """Find users whose uid matches the criteria. Wildcards are
- acceptable. Returns a list of User objects."""
+ """Return a list: counter followed by a User object for each user that
+ matches the criteria. If the results are truncated, counter will
+ be set to -1"""
result = self.transport.find_users(criteria, sattrs)
+ counter = result[0]
- users = []
- for attrs in result:
+ users = [counter]
+ for attrs in result[1:]:
if attrs is not None:
users.append(user.User(attrs))
diff --git a/ipa-python/rpcclient.py b/ipa-python/rpcclient.py
index 7d41caee1..e0d6e2ee7 100644
--- a/ipa-python/rpcclient.py
+++ b/ipa-python/rpcclient.py
@@ -151,8 +151,9 @@ class RPCClient:
return ipautil.unwrap_binary_data(result)
def find_users (self, criteria, sattrs=None):
- """Return a list containing a User object for each user that matches
- the criteria."""
+ """Return a list: counter followed by a User object for each user that
+ matches the criteria. If the results are truncated, counter will
+ be set to -1"""
server = self.setup_server()
try:
diff --git a/ipa-server/ipa-gui/ipagui/controllers.py b/ipa-server/ipa-gui/ipagui/controllers.py
index ca2d15a2d..ebd0b20d6 100644
--- a/ipa-server/ipa-gui/ipagui/controllers.py
+++ b/ipa-server/ipa-gui/ipagui/controllers.py
@@ -140,10 +140,16 @@ class Root(controllers.RootController):
def userlist(self, **kw):
"""Retrieve a list of all users and display them in one huge list"""
users = None
+ counter = 0
uid = kw.get('uid')
if uid != None and len(uid) > 0:
try:
users = client.find_users(uid.encode('utf-8'))
+ counter = users[0]
+ users = users[1:]
+ if counter == -1:
+ turbogears.flash("These results are truncated.\n" +
+ "Please refine your search and try again.")
except ipaerror.IPAError, e:
turbogears.flash("User list failed: " + str(e))
raise turbogears.redirect("/userlist")
diff --git a/ipa-server/ipa-gui/ipagui/static/css/style.css b/ipa-server/ipa-gui/ipagui/static/css/style.css
index b5bd82807..152175e1f 100644
--- a/ipa-server/ipa-gui/ipagui/static/css/style.css
+++ b/ipa-server/ipa-gui/ipagui/static/css/style.css
@@ -129,7 +129,7 @@ body {
#status_block {
margin: 0 auto 0.5em auto;
padding: 15px 10px 15px 55px;
- background: #cec URL('../images/ok.png') left center no-repeat;
+ background: #cec;
border: 1px solid #9c9;
width: 450px;
font-size: 120%;
diff --git a/ipa-server/ipa-gui/ipagui/templates/userlist.kid b/ipa-server/ipa-gui/ipagui/templates/userlist.kid
index 1b4a1201a..c3b53272e 100644
--- a/ipa-server/ipa-gui/ipagui/templates/userlist.kid
+++ b/ipa-server/ipa-gui/ipagui/templates/userlist.kid
@@ -8,13 +8,13 @@
<body>
<div id="search">
<form action="${tg.url('/userlist')}" method="post">
- Search by login/name:
+ Search:
<input type="text" name="uid" />
<input type="submit" />
</form>
</div>
<div py:if='users != None'>
- <h2>Results</h2>
+ <h2>${len(users)} results returned:</h2>
<table py:if='len(users) > 0' border="1">
<tr>
<th>
diff --git a/ipa-server/ipaserver/ipaldap.py b/ipa-server/ipaserver/ipaldap.py
index f626f2f3a..4d0630eef 100644
--- a/ipa-server/ipaserver/ipaldap.py
+++ b/ipa-server/ipaserver/ipaldap.py
@@ -300,6 +300,44 @@ class IPAdmin(SimpleLDAPObject):
return all_users
+ def getListAsync(self,*args):
+ """This version performs an asynchronous search, to allow
+ results even if we hit a limit.
+
+ It returns a list: counter followed by the results.
+ If the results are truncated, counter will be set to -1.
+ """
+
+ sctrl = self.__get_server_controls__()
+ if sctrl is not None:
+ self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
+
+ entries = []
+ partial = 0
+
+ try:
+ msgid = self.search_ext(*args)
+ type, result_list = self.result(msgid, 0)
+ while result_list:
+ for result in result_list:
+ entries.append(result)
+ type, result_list = self.result(msgid, 0)
+ except (ldap.ADMINLIMIT_EXCEEDED, ldap.SIZELIMIT_EXCEEDED), e:
+ partial = 1
+ except ldap.LDAPError, e:
+ raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e)
+
+ if not entries:
+ raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND,
+ "no such entry for " + str(args))
+
+ if partial == 1:
+ counter = -1
+ else:
+ counter = len(entries)
+
+ return [counter] + entries
+
def addEntry(self,*args):
"""This wraps the add function. It assumes that the entry is already
populated with all of the desired objectclasses and attributes"""
diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py
index a0af41d42..fd95470b0 100644
--- a/ipa-server/xmlrpc-server/funcs.py
+++ b/ipa-server/xmlrpc-server/funcs.py
@@ -372,9 +372,8 @@ class IPAServer:
return users
def find_users (self, criteria, sattrs=None, opts=None):
- """Return a list containing a User object for each
- existing user that matches the criteria.
- """
+ """Returns a list: counter followed by the results.
+ If the results are truncated, counter will be set to -1."""
global _LDAPPool
if opts:
@@ -400,25 +399,36 @@ class IPAServer:
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
try:
try:
- exact_results = m1.getList(self.basedn, self.scope,
+ exact_results = m1.getListAsync(self.basedn, self.scope,
exact_match_filter, sattrs)
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
- exact_results = []
+ exact_results = [0]
try:
- partial_results = m1.getList(self.basedn, self.scope,
+ partial_results = m1.getListAsync(self.basedn, self.scope,
partial_match_filter, sattrs)
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
- partial_results = []
+ partial_results = [0]
finally:
_LDAPPool.releaseConn(m1)
+ 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)
- users = []
+ if (exact_counter == -1) or (partial_counter == -1):
+ counter = -1
+ else:
+ counter = len(exact_results) + len(partial_results)
+
+ users = [counter]
for u in exact_results + partial_results:
users.append(self.convert_entry(u))