15
15
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
16
# License for the specific language governing permissions and limitations
17
17
# under the License.
18
"""Fake LDAP server for test harness, backs to ReDIS.
18
"""Fake LDAP server for test harness.
20
20
This class does very little error checking, and knows nothing about ldap
21
21
class definitions. It implements the minimum emulation of the python ldap
29
from nova import flags
32
flags.DEFINE_string('redis_host', '127.0.0.1',
33
'Host that redis is running on.')
34
flags.DEFINE_integer('redis_port', 6379,
35
'Port that redis is running on.')
36
flags.DEFINE_integer('redis_db', 0, 'Multiple DB keeps tests away')
40
31
def __init__(self):
41
32
if hasattr(self.__class__, '_instance'):
42
raise Exception('Attempted to instantiate singleton')
33
raise Exception(_('Attempted to instantiate singleton'))
46
37
if not hasattr(cls, '_instance'):
47
inst = redis.Redis(host=FLAGS.redis_host,
48
port=FLAGS.redis_port,
38
cls._instance = _StorageDict()
51
39
return cls._instance
42
class _StorageDict(dict):
43
def keys(self, pat=None):
44
ret = super(_StorageDict, self).keys()
46
ret = fnmatch.filter(ret, pat)
49
def delete(self, key):
58
def hgetall(self, key):
59
"""Returns the hash for the given key; creates
60
the hash if the key doesn't exist."""
67
def hget(self, key, field):
68
hashdict = self.hgetall(key)
70
return hashdict[field]
73
return hashdict[field]
75
def hset(self, key, field, val):
76
hashdict = self.hgetall(key)
79
def hmset(self, key, value_dict):
80
hashdict = self.hgetall(key)
81
for field, val in value_dict.items():
55
86
SCOPE_ONELEVEL = 1 # Not implemented
184
213
def add_s(self, dn, attr):
185
214
"""Add an object with the specified attributes at dn."""
186
key = "%s%s" % (self.__redis_prefix, dn)
215
key = "%s%s" % (self.__prefix, dn)
188
216
value_dict = dict([(k, _to_json(v)) for k, v in attr])
189
Redis.instance().hmset(key, value_dict)
217
Store.instance().hmset(key, value_dict)
191
219
def delete_s(self, dn):
192
220
"""Remove the ldap object at specified dn."""
193
Redis.instance().delete("%s%s" % (self.__redis_prefix, dn))
221
Store.instance().delete("%s%s" % (self.__prefix, dn))
195
223
def modify_s(self, dn, attrs):
196
224
"""Modify the object at dn using the attribute list.
201
229
([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
204
redis = Redis.instance()
205
key = "%s%s" % (self.__redis_prefix, dn)
232
store = Store.instance()
233
key = "%s%s" % (self.__prefix, dn)
207
235
for cmd, k, v in attrs:
208
values = _from_json(redis.hget(key, k))
236
values = _from_json(store.hget(key, k))
209
237
if cmd == MOD_ADD:
211
239
elif cmd == MOD_REPLACE:
215
values = redis.hset(key, k, _to_json(values))
243
values = store.hset(key, k, _to_json(values))
217
245
def search_s(self, dn, scope, query=None, fields=None):
218
246
"""Search for all matching objects under dn using the query.
227
255
if scope != SCOPE_BASE and scope != SCOPE_SUBTREE:
228
256
raise NotImplementedError(str(scope))
229
redis = Redis.instance()
257
store = Store.instance()
230
258
if scope == SCOPE_BASE:
231
keys = ["%s%s" % (self.__redis_prefix, dn)]
259
keys = ["%s%s" % (self.__prefix, dn)]
233
keys = redis.keys("%s*%s" % (self.__redis_prefix, dn))
261
keys = store.keys("%s*%s" % (self.__prefix, dn))
236
# get the attributes from redis
237
attrs = redis.hgetall(key)
238
# turn the values from redis into lists
265
# get the attributes from the store
266
attrs = store.hgetall(key)
267
# turn the values from the store into lists
239
268
# pylint: disable-msg=E1103
240
269
attrs = dict([(k, _from_json(v))
241
270
for k, v in attrs.iteritems()])
244
273
# filter the attributes by fields
245
274
attrs = dict([(k, v) for k, v in attrs.iteritems()
246
275
if not fields or k in fields])
247
objects.append((key[len(self.__redis_prefix):], attrs))
276
objects.append((key[len(self.__prefix):], attrs))
248
277
# pylint: enable-msg=E1103
249
278
if objects == []:
250
279
raise NO_SUCH_OBJECT()
254
def __redis_prefix(self): # pylint: disable-msg=R0201
255
"""Get the prefix to use for all redis keys."""
283
def __prefix(self): # pylint: disable-msg=R0201
284
"""Get the prefix to use for all keys."""