keystoneclient tests working against sql backend

This commit is contained in:
termie 2012-01-06 23:10:18 -08:00
parent 4b4ada27ca
commit 13ec79bf48
5 changed files with 180 additions and 79 deletions

View File

@ -64,10 +64,12 @@ class KvsIdentity(object):
return role_ref
def list_users(self):
return self.db.get('user_list', [])
user_ids = self.db.get('user_list', [])
return [self.get_user(x) for x in user_ids]
def list_roles(self):
return self.db.get('role_list', [])
role_ids = self.db.get('role_list', [])
return [self.get_role(x) for x in role_ids]
# These should probably be part of the high-level API
def add_user_to_tenant(self, tenant_id, user_id):

View File

@ -63,11 +63,12 @@ class DictBase(object):
Includes attributes from joins.
"""
local = dict(self)
joined = dict([(k, v) for k, v in self.__dict__.iteritems()
if not k[0] == '_'])
local.update(joined)
return local.iteritems()
return dict([(k, getattr(self, k)) for k in self])
#local = dict(self)
#joined = dict([(k, v) for k, v in self.__dict__.iteritems()
# if not k[0] == '_'])
#local.update(joined)
#return local.iteritems()
# Tables
@ -75,13 +76,51 @@ class User(Base, DictBase):
__tablename__ = 'user'
id = sql.Column(sql.String(64), primary_key=True)
name = sql.Column(sql.String(64), unique=True)
password = sql.Column(sql.String(64))
#password = sql.Column(sql.String(64))
extra = sql.Column(JsonBlob())
@classmethod
def from_dict(cls, user_dict):
# shove any non-indexed properties into extra
extra = {}
for k, v in user_dict.copy().iteritems():
# TODO(termie): infer this somehow
if k not in ['id', 'name']:
extra[k] = user_dict.pop(k)
user_dict['extra'] = extra
return cls(**user_dict)
def to_dict(self):
extra_copy = self.extra.copy()
extra_copy['id'] = self.id
extra_copy['name'] = self.name
return extra_copy
class Tenant(Base, DictBase):
__tablename__ = 'tenant'
id = sql.Column(sql.String(64), primary_key=True)
name = sql.Column(sql.String(64), unique=True)
extra = sql.Column(JsonBlob())
@classmethod
def from_dict(cls, tenant_dict):
# shove any non-indexed properties into extra
extra = {}
for k, v in tenant_dict.copy().iteritems():
# TODO(termie): infer this somehow
if k not in ['id', 'name']:
extra[k] = tenant_dict.pop(k)
tenant_dict['extra'] = extra
return cls(**tenant_dict)
def to_dict(self):
extra_copy = self.extra.copy()
extra_copy['id'] = self.id
extra_copy['name'] = self.name
return extra_copy
class Role(Base, DictBase):
@ -143,7 +182,7 @@ class SqlBase(object):
engine_args = {
"pool_recycle": CONF.sql.idle_timeout,
"echo": False,
"echo": True,
}
if "sqlite" in connection_dict.drivername:
@ -177,6 +216,7 @@ class SqlIdentity(SqlBase):
raise AssertionError('Invalid tenant')
tenant_ref = self.get_tenant(tenant_id)
print 'ETESTSET', tenant_ref
if tenant_ref:
extras_ref = self.get_extras(user_id, tenant_id)
else:
@ -186,29 +226,37 @@ class SqlIdentity(SqlBase):
def get_tenant(self, tenant_id):
session = self.get_session()
tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()
return tenant_ref
if not tenant_ref:
return
return tenant_ref.to_dict()
def get_tenant_by_name(self, tenant_name):
session = self.get_session()
tenant_ref = session.query(Tenant).filter_by(name=tenant_name).first()
return tenant_ref
if not tenant_ref:
return
return tenant_ref.to_dict()
def get_user(self, user_id):
session = self.get_session()
user_ref = session.query(User).filter_by(id=user_id).first()
return user_ref
if not user_ref:
return
return user_ref.to_dict()
def get_user_by_name(self, user_name):
session = self.get_session()
user_ref = session.query(User).filter_by(name=user_name).first()
return user_ref
if not user_ref:
return
return user_ref.to_dict()
def get_extras(self, user_id, tenant_id):
session = self.get_session()
extras_ref = session.query(Extras)\
.filter_by(user_id=user_id)\
.filter_by(tenant_id=tenant_id)\
.first()
.filter_by(user_id=user_id)\
.filter_by(tenant_id=tenant_id)\
.first()
return getattr(extras_ref, 'data', None)
def get_role(self, role_id):
@ -219,7 +267,7 @@ class SqlIdentity(SqlBase):
def list_users(self):
session = self.get_session()
user_refs = session.query(User)
return list(user_refs)
return [x.to_dict() for x in user_refs]
def list_roles(self):
session = self.get_session()
@ -233,11 +281,13 @@ class SqlIdentity(SqlBase):
session.add(UserTenantMembership(user_id=user_id, tenant_id=tenant_id))
def remove_user_from_tenant(self, tenant_id, user_id):
user_ref = self.get_user(user_id)
tenants = set(user_ref.get('tenants', []))
tenants.remove(tenant_id)
user_ref['tenants'] = list(tenants)
self.update_user(user_id, user_ref)
session = self.get_session()
membership_ref = session.query(UserTenantMembership)\
.filter_by(user_id=user_id)\
.filter_by(tenant_id=tenant_id)\
.first()
with session.begin():
session.delete(membership_ref)
def get_tenants_for_user(self, user_id):
session = self.get_session()
@ -255,65 +305,84 @@ class SqlIdentity(SqlBase):
def add_role_to_user_and_tenant(self, user_id, tenant_id, role_id):
extras_ref = self.get_extras(user_id, tenant_id)
is_new = False
if not extras_ref:
is_new = True
extras_ref = {}
roles = set(extras_ref.get('roles', []))
roles.add(role_id)
extras_ref['roles'] = list(roles)
self.update_extras(user_id, tenant_id, extras_ref)
if not is_new:
self.update_extras(user_id, tenant_id, extras_ref)
else:
self.create_extras(user_id, tenant_id, extras_ref)
def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
extras_ref = self.get_extras(user_id, tenant_id)
is_new = False
if not extras_ref:
is_new = True
extras_ref = {}
roles = set(extras_ref.get('roles', []))
roles.remove(role_id)
extras_ref['roles'] = list(roles)
self.update_extras(user_id, tenant_id, extras_ref)
if not is_new:
self.update_extras(user_id, tenant_id, extras_ref)
else:
self.create_extras(user_id, tenant_id, extras_ref)
# CRUD
def create_user(self, id, user):
session = self.get_session()
with session.begin():
session.add(User(**user))
return user
user_ref = User.from_dict(user)
session.add(user_ref)
return user_ref.to_dict()
def update_user(self, id, user):
# get the old name and delete it too
old_user = self.db.get('user-%s' % id)
self.db.delete('user_name-%s' % old_user['name'])
self.db.set('user-%s' % id, user)
self.db.set('user_name-%s' % user['name'], user)
return user
session = self.get_session()
with session.begin():
user_ref = session.query(User).filter_by(id=id).first()
old_user_dict = user_ref.to_dict()
for k in user:
old_user_dict[k] = user[k]
new_user = User.from_dict(old_user_dict)
user_ref.name = new_user.name
user_ref.extra = new_user.extra
return user_ref
def delete_user(self, id):
old_user = self.db.get('user-%s' % id)
self.db.delete('user_name-%s' % old_user['name'])
self.db.delete('user-%s' % id)
user_list = set(self.db.get('user_list', []))
user_list.remove(id)
self.db.set('user_list', list(user_list))
return None
session = self.get_session()
user_ref = session.query(User).filter_by(id=id).first()
with session.begin():
session.delete(user_ref)
def create_tenant(self, id, tenant):
session = self.get_session()
with session.begin():
session.add(Tenant(**tenant))
return tenant
tenant_ref = Tenant.from_dict(tenant)
session.add(tenant_ref)
return tenant_ref.to_dict()
def update_tenant(self, id, tenant):
# get the old name and delete it too
old_tenant = self.db.get('tenant-%s' % id)
self.db.delete('tenant_name-%s' % old_tenant['name'])
self.db.set('tenant-%s' % id, tenant)
self.db.set('tenant_name-%s' % tenant['name'], tenant)
return tenant
session = self.get_session()
with session.begin():
tenant_ref = session.query(Tenant).filter_by(id=id).first()
old_tenant_dict = tenant_ref.to_dict()
for k in tenant:
old_tenant_dict[k] = tenant[k]
new_tenant = Tenant.from_dict(old_tenant_dict)
tenant_ref.name = new_tenant.name
tenant_ref.extra = new_tenant.extra
return tenant_ref
def delete_tenant(self, id):
old_tenant = self.db.get('tenant-%s' % id)
self.db.delete('tenant_name-%s' % old_tenant['name'])
self.db.delete('tenant-%s' % id)
return None
session = self.get_session()
tenant_ref = session.query(Tenant).filter_by(id=id).first()
with session.begin():
session.delete(tenant_ref)
def create_extras(self, user_id, tenant_id, extras):
session = self.get_session()
@ -322,8 +391,17 @@ class SqlIdentity(SqlBase):
return extras
def update_extras(self, user_id, tenant_id, extras):
self.db.set('extras-%s-%s' % (tenant_id, user_id), extras)
return extras
session = self.get_session()
with session.begin():
extras_ref = session.query(Extras)\
.filter_by(user_id=user_id)\
.filter_by(tenant_id=tenant_id)\
.first()
data = extras_ref.data.copy()
for k in extras:
data[k] = extras[k]
extras_ref.data = data
return extras_ref
def delete_extras(self, user_id, tenant_id):
self.db.delete('extras-%s-%s' % (tenant_id, user_id))
@ -336,15 +414,18 @@ class SqlIdentity(SqlBase):
return role
def update_role(self, id, role):
self.db.set('role-%s' % id, role)
return role
session = self.get_session()
with session.begin():
role_ref = session.query(Role).filter_by(id=id).first()
for k in role:
role_ref[k] = role[k]
return role_ref
def delete_role(self, id):
self.db.delete('role-%s' % id)
role_list = set(self.db.get('role_list', []))
role_list.remove(id)
self.db.set('role_list', list(role_list))
return None
session = self.get_session()
role_ref = session.query(Role).filter_by(id=id).first()
with session.begin():
session.delete(role_ref)
class SqlToken(SqlBase):

View File

@ -511,8 +511,10 @@ class KeystoneTenantController(service.BaseApplication):
assert token_ref is not None
user_ref = token_ref['user']
tenant_ids = self.identity_api.get_tenants_for_user(
context, user_ref['id'])
tenant_refs = []
for tenant_id in user_ref['tenants']:
for tenant_id in tenant_ids:
tenant_refs.append(self.identity_api.get_tenant(
context=context,
tenant_id=tenant_id))
@ -537,9 +539,9 @@ class KeystoneTenantController(service.BaseApplication):
return {'tenant': tenant}
# CRUD Extension
def create_tenant(self, context, **kw):
def create_tenant(self, context, tenant):
tenant_ref = self._normalize_dict(tenant)
self.assert_admin(context)
tenant_ref = kw.get('tenant')
tenant_id = (tenant_ref.get('id')
and tenant_ref.get('id')
or uuid.uuid4().hex)
@ -590,23 +592,21 @@ class KeystoneUserController(service.BaseApplication):
# NOTE(termie): i can't imagine that this really wants all the data
# about every single user in the system...
self.assert_admin(context)
user_list = self.identity_api.list_users(context)
return {'users': [{'id': x} for x in user_list]}
user_refs = self.identity_api.list_users(context)
return {'users': user_refs}
# CRUD extension
def create_user(self, context, user):
user = self._normalize_dict(user)
self.assert_admin(context)
tenant_id = user.get('tenantId')
tenants = []
if tenant_id:
tenants.append(tenant_id)
tenant_id = user.get('tenantId', None)
user_id = uuid.uuid4().hex
user_ref = user.copy()
#user_ref.pop('tenantId', None)
user_ref['id'] = user_id
user_ref['tenants'] = tenants
new_user_ref = self.identity_api.create_user(
context, user_id, user_ref)
if tenant_id:
self.identity_api.add_user_to_tenant(tenant_id, user_id)
return {'user': new_user_ref}
# NOTE(termie): this is really more of a patch than a put
@ -656,6 +656,8 @@ class KeystoneRoleController(service.BaseApplication):
return {'role': role_ref}
def create_role(self, context, role):
role = self._normalize_dict(role)
self.assert_admin(context)
role_id = uuid.uuid4().hex
role['id'] = role_id
role_ref = self.identity_api.create_role(context, role_id, role)
@ -669,8 +671,7 @@ class KeystoneRoleController(service.BaseApplication):
self.assert_admin(context)
roles = self.identity_api.list_roles(context)
# TODO(termie): probably inefficient at some point
return {'roles': [self.identity_api.get_role(context, x)
for x in roles]}
return {'roles': roles}
# COMPAT(diablo): CRUD extension
def get_role_refs(self, context, user_id):

View File

@ -47,6 +47,13 @@ URLMAP = HIGH_LEVEL_CALLS.copy()
URLMAP.update(LOW_LEVEL_CALLS)
class SmarterEncoder(json.JSONEncoder):
def default(self, obj):
if not isinstance(obj, dict) and hasattr(obj, 'iteritems'):
return dict(obj.iteritems())
return super(SmarterEncoder, self).default(obj)
class BaseApplication(wsgi.Application):
@webob.dec.wsgify
def __call__(self, req):
@ -76,11 +83,18 @@ class BaseApplication(wsgi.Application):
elif isinstance(result, webob.exc.WSGIHTTPException):
return result
return json.dumps(result)
return self._serialize(result)
def _serialize(self, result):
return json.dumps(result, cls=SmarterEncoder)
def _normalize_arg(self, arg):
return str(arg).replace(':', '_').replace('-', '_')
def _normalize_dict(self, d):
return dict([(self._normalize_arg(k), v)
for (k, v) in d.iteritems()])
def assert_admin(self, context):
if not context['is_admin']:
user_token_ref = self.token_api.get_token(
@ -88,6 +102,7 @@ class BaseApplication(wsgi.Application):
creds = user_token_ref['extras'].copy()
creds['user_id'] = user_token_ref['user'].get('id')
creds['tenant_id'] = user_token_ref['tenant'].get('id')
print creds
# Accept either is_admin or the admin role
assert self.policy_api.can_haz(context,
('is_admin:1', 'roles:admin'),

View File

@ -8,9 +8,12 @@ import time
from paste import deploy
from keystonelight import catalog
from keystonelight import config
from keystonelight import identity
from keystonelight import logging
from keystonelight import models
from keystonelight import token
from keystonelight import utils
from keystonelight import wsgi
@ -114,20 +117,19 @@ class TestCase(unittest.TestCase):
# TODO(termie): doing something from json, probably based on Django's
# loaddata will be much preferred.
for tenant in fixtures.TENANTS:
rv = self.identity_api.create_tenant(
tenant['id'], models.Tenant(**tenant))
rv = self.identity_api.create_tenant(tenant['id'], tenant)
setattr(self, 'tenant_%s' % tenant['id'], rv)
for user in fixtures.USERS:
user_copy = user.copy()
tenants = user_copy.pop('tenants')
rv = self.identity_api.create_user(user['id'], models.User(**user_copy))
rv = self.identity_api.create_user(user['id'], user_copy)
for tenant_id in tenants:
self.identity_api.add_user_to_tenant(tenant_id, user['id'])
setattr(self, 'user_%s' % user['id'], rv)
for role in fixtures.ROLES:
rv = self.identity_api.create_role(role['id'], models.Role(**role))
rv = self.identity_api.create_role(role['id'], role)
setattr(self, 'role_%s' % role['id'], rv)
for extras in fixtures.EXTRAS:
@ -137,7 +139,7 @@ class TestCase(unittest.TestCase):
del extras_ref['user_id']
del extras_ref['tenant_id']
rv = self.identity_api.create_extras(
extras['user_id'], extras['tenant_id'], models.Extras(**extras_ref))
extras['user_id'], extras['tenant_id'], extras_ref)
setattr(self,
'extras_%s%s' % (extras['user_id'], extras['tenant_id']), rv)