summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVishvananda Ishaya <vishvananda@gmail.com>2010-06-27 23:19:14 -0700
committerVishvananda Ishaya <vishvananda@gmail.com>2010-06-27 23:19:14 -0700
commit973e45e62df73138d53600bc44a51ac1be409e07 (patch)
tree96d09cdab542319a9c337ca48ac7d557a4bd0e74
parent715d33de15beb594c8d6271929a957ce7f5f2e2a (diff)
downloadnova-973e45e62df73138d53600bc44a51ac1be409e07.tar.gz
nova-973e45e62df73138d53600bc44a51ac1be409e07.tar.xz
nova-973e45e62df73138d53600bc44a51ac1be409e07.zip
Make fakeldap use redis
-rw-r--r--nova/auth/fakeldap.py132
1 files changed, 74 insertions, 58 deletions
diff --git a/nova/auth/fakeldap.py b/nova/auth/fakeldap.py
index 27dde314d..0e95972f2 100644
--- a/nova/auth/fakeldap.py
+++ b/nova/auth/fakeldap.py
@@ -21,37 +21,31 @@
Fake LDAP server for test harnesses.
"""
-import logging
+import json
from nova import datastore
-SCOPE_SUBTREE = 1
+SCOPE_SUBTREE = 2
MOD_ADD = 0
MOD_DELETE = 1
-SUBS = {
- 'groupOfNames': ['novaProject']
-}
-
class NO_SUCH_OBJECT(Exception):
pass
def initialize(uri):
- return FakeLDAP(uri)
+ return FakeLDAP()
class FakeLDAP(object):
- def __init__(self, _uri):
- self.keeper = datastore.Keeper('fakeldap')
- if self.keeper['objects'] is None:
- self.keeper['objects'] = {}
def simple_bind_s(self, dn, password):
+ """This method is ignored, but provided for compatibility"""
pass
def unbind_s(self):
+ """This method is ignored, but provided for compatibility"""
pass
def _paren_groups(self, source):
@@ -67,6 +61,7 @@ class FakeLDAP(object):
count -= 1
if count == 0:
result.append(source[start:pos+1])
+ return result
def _match_query(self, query, attrs):
inner = query[1:-1]
@@ -83,63 +78,84 @@ class FakeLDAP(object):
return self._match(k, v, attrs)
def _subs(self, v):
- if v in SUBS:
- return [v] + SUBS[v]
+ subs = {
+ 'groupOfNames': ['novaProject']
+ }
+ if v in subs:
+ return [v] + subs[v]
return [v]
def _match(self, k, v, attrs):
if attrs.has_key(k):
for v in self._subs(v):
- if (v in attrs[k]):
+ if v in attrs[k]:
return True
return False
+
def search_s(self, dn, scope, query=None, fields=None):
- #logging.debug("searching for %s" % dn)
- filtered = {}
- d = self.keeper['objects'] or {}
- for cn, attrs in d.iteritems():
- if cn[-len(dn):] == dn:
- filtered[cn] = attrs
- objects = filtered
- if query:
- objects = {}
- for cn, attrs in filtered.iteritems():
- if self._match_query(query, attrs):
- objects[cn] = attrs
- if objects == {}:
+ """search for all matching objects under dn using the query
+ only SCOPE_SUBTREE is supported.
+ """
+ if scope != SCOPE_SUBTREE:
+ raise NotImplementedError(str(scope))
+ redis = datastore.Redis.instance()
+ keys = redis.keys(self._redis_prefix + '*' + dn)
+ objects = []
+ for key in keys:
+ # get the attributes from redis
+ attrs = redis.hgetall(key)
+ # turn the values from redis into lists
+ attrs = dict([(k, self._from_json(v))
+ for k, v in attrs.iteritems()])
+ # filter the objects by query
+ if not query or self._match_query(query, attrs):
+ # filter the attributes by fields
+ attrs = dict([(k, v) for k, v in attrs.iteritems()
+ if not fields or k in fields])
+ objects.append((key[len(self._redis_prefix):], attrs))
+ if objects == []:
raise NO_SUCH_OBJECT()
- return objects.items()
-
- def add_s(self, cn, attr):
- #logging.debug("adding %s" % cn)
- stored = {}
- for k, v in attr:
- if type(v) is list:
- stored[k] = v
- else:
- stored[k] = [v]
- d = self.keeper['objects']
- d[cn] = stored
- self.keeper['objects'] = d
-
- def delete_s(self, cn):
- logging.debug("deleting %s" % cn)
- d = self.keeper['objects']
- del d[cn]
- self.keeper['objects'] = d
-
- def modify_s(self, cn, attr):
- logging.debug("modifying %s" % cn)
- d = self.keeper['objects']
- for cmd, k, v in attr:
- logging.debug("command %s" % cmd)
+ return objects
+
+ @property
+ def _redis_prefix(self):
+ return 'ldap:'
+
+ def _from_json(self, encoded):
+ """Convert attribute values from json representation."""
+ # return as simple strings instead of unicode strings
+ return [str(x) for x in json.loads(encoded)]
+
+ def _to_json(self, unencoded):
+ """Convert attribute values into json representation."""
+ # all values are returned as lists from ldap
+ return json.dumps(list(unencoded))
+
+ def add_s(self, dn, attr):
+ """Add an object with the specified attributes at dn."""
+ key = self._redis_prefix + dn
+
+ value_dict = dict([(k, self._to_json(v)) for k, v in attr])
+ datastore.Redis.instance().hmset(key, value_dict)
+
+ def delete_s(self, dn):
+ """Remove the ldap object at specified dn."""
+ datastore.Redis.instance().delete(self._redis_prefix + dn)
+
+ def modify_s(self, dn, attrs):
+ """Modify the object at dn using the attribute list.
+ attr is a list of tuples in the following form:
+ ([MOD_ADD | MOD_DELETE], attribute, value)
+ """
+ redis = datastore.Redis.instance()
+ key = self._redis_prefix + dn
+
+ for cmd, k, v in attrs:
+ values = self._from_json(redis.hget(key, k))
if cmd == MOD_ADD:
- d[cn][k].append(v)
+ values.append(v)
else:
- d[cn][k].remove(v)
- self.keeper['objects'] = d
-
-
-
+ values.remove(v)
+ values = redis.hset(key, k, self._to_json(values))