~tr3buchet/nova/lock

« back to all changes in this revision

Viewing changes to nova/auth/fakeldap.py

  • Committer: Vishvananda Ishaya
  • Date: 2010-12-22 20:59:53 UTC
  • mto: This revision was merged to the branch mainline in revision 482.
  • Revision ID: vishvananda@gmail.com-20101222205953-j2j5t0qjwlcd0t2s
merge trunk and upgrade to cheetah templating

Show diffs side-by-side

added added

removed removed

Lines of Context:
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.
19
19
 
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
23
23
 
24
24
"""
25
25
 
 
26
import fnmatch
26
27
import json
27
 
import redis
28
 
 
29
 
from nova import flags
30
 
 
31
 
FLAGS = flags.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')
37
 
 
38
 
 
39
 
class Redis(object):
 
28
 
 
29
 
 
30
class Store(object):
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'))
43
34
 
44
35
    @classmethod
45
36
    def instance(cls):
46
37
        if not hasattr(cls, '_instance'):
47
 
            inst = redis.Redis(host=FLAGS.redis_host,
48
 
                               port=FLAGS.redis_port,
49
 
                               db=FLAGS.redis_db)
50
 
            cls._instance = inst
 
38
            cls._instance = _StorageDict()
51
39
        return cls._instance
52
40
 
53
41
 
 
42
class _StorageDict(dict):
 
43
    def keys(self, pat=None):
 
44
        ret = super(_StorageDict, self).keys()
 
45
        if pat is not None:
 
46
            ret = fnmatch.filter(ret, pat)
 
47
        return ret
 
48
 
 
49
    def delete(self, key):
 
50
        try:
 
51
            del self[key]
 
52
        except KeyError:
 
53
            pass
 
54
 
 
55
    def flushdb(self):
 
56
        self.clear()
 
57
 
 
58
    def hgetall(self, key):
 
59
        """Returns the hash for the given key; creates
 
60
        the hash if the key doesn't exist."""
 
61
        try:
 
62
            return self[key]
 
63
        except KeyError:
 
64
            self[key] = {}
 
65
            return self[key]
 
66
 
 
67
    def hget(self, key, field):
 
68
        hashdict = self.hgetall(key)
 
69
        try:
 
70
            return hashdict[field]
 
71
        except KeyError:
 
72
            hashdict[field] = {}
 
73
            return hashdict[field]
 
74
 
 
75
    def hset(self, key, field, val):
 
76
        hashdict = self.hgetall(key)
 
77
        hashdict[field] = val
 
78
 
 
79
    def hmset(self, key, value_dict):
 
80
        hashdict = self.hgetall(key)
 
81
        for field, val in value_dict.items():
 
82
            hashdict[field] = val
 
83
 
 
84
 
54
85
SCOPE_BASE = 0
55
86
SCOPE_ONELEVEL = 1  # Not implemented
56
87
SCOPE_SUBTREE = 2
169
200
 
170
201
 
171
202
class FakeLDAP(object):
172
 
    #TODO(vish): refactor this class to use a wrapper instead of accessing
173
 
    #            redis directly
174
203
    """Fake LDAP connection."""
175
204
 
176
205
    def simple_bind_s(self, dn, password):
183
212
 
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)
187
 
 
 
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)
190
218
 
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))
194
222
 
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)
202
230
 
203
231
        """
204
 
        redis = Redis.instance()
205
 
        key = "%s%s" % (self.__redis_prefix, dn)
 
232
        store = Store.instance()
 
233
        key = "%s%s" % (self.__prefix, dn)
206
234
 
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:
210
238
                values.append(v)
211
239
            elif cmd == MOD_REPLACE:
212
240
                values = [v]
213
241
            else:
214
242
                values.remove(v)
215
 
            values = redis.hset(key, k, _to_json(values))
 
243
            values = store.hset(key, k, _to_json(values))
216
244
 
217
245
    def search_s(self, dn, scope, query=None, fields=None):
218
246
        """Search for all matching objects under dn using the query.
226
254
        """
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)]
232
260
        else:
233
 
            keys = redis.keys("%s*%s" % (self.__redis_prefix, dn))
 
261
            keys = store.keys("%s*%s" % (self.__prefix, dn))
 
262
 
234
263
        objects = []
235
264
        for key in keys:
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()
251
280
        return objects
252
281
 
253
282
    @property
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."""
256
285
        return 'ldap:'