still wip, got migration mostly working

This commit is contained in:
termie 2012-01-05 15:17:22 -08:00
parent 775b8ed734
commit 119808d602
12 changed files with 287 additions and 6 deletions

View File

@ -0,0 +1 @@
from keystonelight.backends.sql.core import *

View File

@ -27,6 +27,9 @@ class JsonBlob(sql_types.TypeDecorator):
class DictBase(object):
def to_dict(self):
return dict(self.iteritems())
def __setitem__(self, key, value):
setattr(self, key, value)
@ -37,7 +40,7 @@ class DictBase(object):
return getattr(self, key, default)
def __iter__(self):
self._i = iter(object_mapper(self).columns)
self._i = iter(sqlalchemy.orm.object_mapper(self).columns)
return self
def next(self):
@ -186,7 +189,7 @@ 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 models.Tenant(**tenant_ref)
return tenant_ref
def get_tenant_by_name(self, tenant_name):
tenant_ref = self.db.get('tenant_name-%s' % tenant_name)
@ -195,7 +198,7 @@ class SqlIdentity(SqlBase):
def get_user(self, user_id):
session = self.get_session()
user_ref = session.query(User).filter_by(id=user_id).first()
return models.User(**user_ref)
return user_ref
def get_user_by_name(self, user_name):
user_ref = self.db.get('user_name-%s' % user_name)
@ -261,6 +264,7 @@ class SqlIdentity(SqlBase):
def create_user(self, id, user):
session = self.get_session()
session.add(User(**user))
session.flush()
#self.db.set('user-%s' % id, user)
#self.db.set('user_name-%s' % user['name'], user)
#user_list = set(self.db.get('user_list', []))

View File

@ -0,0 +1,4 @@
This is a database migration repository.
More information at
http://code.google.com/p/sqlalchemy-migrate/

View File

@ -0,0 +1,5 @@
#!/usr/bin/env python
from migrate.versioning.shell import main
if __name__ == '__main__':
main(debug='False')

View File

@ -0,0 +1,25 @@
[db_settings]
# Used to identify which repository this database is versioned under.
# You can use the name of your project.
repository_id=keystone
# The name of the database table used to track the schema version.
# This name shouldn't already be used by your project.
# If this is changed once a database is under version control, you'll need to
# change the table name in each database too.
version_table=migrate_version
# When committing a change script, Migrate will attempt to generate the
# sql for all supported databases; normally, if one of them fails - probably
# because you don't have that database installed - it is ignored and the
# commit continues, perhaps ending successfully.
# Databases in this list MUST compile successfully during a commit, or the
# entire commit will fail. List the databases your application will actually
# be using to ensure your updates to that database work properly.
# This must be a list; example: ['postgres','sqlite']
required_dbs=[]
# When creating new change scripts, Migrate will stamp the new script with
# a version number. By default this is latest_version + 1. You can set this
# to 'true' to tell Migrate to use the UTC timestamp instead.
use_timestamp_numbering=False

View File

@ -0,0 +1,14 @@
from sqlalchemy import *
from migrate import *
from keystonelight.backends import sql
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine; bind
# migrate_engine to your metadata
sql.Base.metadata.create_all(migrate_engine)
def downgrade(migrate_engine):
# Operations to reverse the above upgrade go here.
pass

View File

@ -0,0 +1,74 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import sys
import sqlalchemy
from migrate.versioning import api as versioning_api
try:
from migrate.versioning import exceptions as versioning_exceptions
except ImportError:
try:
# python-migration changed location of exceptions after 1.6.3
# See LP Bug #717467
from migrate import exceptions as versioning_exceptions
except ImportError:
sys.exit("python-migrate is not installed. Exiting.")
def db_sync(options, version=None):
if version is not None:
try:
version = int(version)
except ValueError:
raise Exception("version should be an integer")
current_version = db_version(options)
repo_path = _find_migrate_repo()
if version is None or version > current_version:
return versioning_api.upgrade(
options.get('sql_connection'), repo_path, version)
else:
return versioning_api.downgrade(
options.get('sql_connection'), repo_path, version)
def db_version(options):
repo_path = _find_migrate_repo()
try:
return versioning_api.db_version(
options.get('sql_connection'), repo_path)
except versioning_exceptions.DatabaseNotControlledError:
return db_version_control(options, 0)
def db_version_control(options, version=None):
repo_path = _find_migrate_repo()
versioning_api.version_control(
options.get('sql_connection'), repo_path, version)
return version
def _find_migrate_repo():
"""Get the path for the migrate repository."""
path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'migrate_repo')
assert os.path.exists(path)
return path

View File

@ -22,7 +22,7 @@ catalog.RegionOne.compute.internalURL = http://localhost:$(compute_port)s/v1.1/$
catalog.RegionOne.compute.name = 'Compute Service'
# for sql backends
sql_connection = sqlite:///:memory:
sql_connection = sqlite:///bla.db
sql_idle_timeout = 200
sql_min_pool_size = 5
sql_max_pool_size = 10

View File

@ -11,8 +11,8 @@ class KvsIdentity(test.TestCase):
def setUp(self):
super(KvsIdentity, self).setUp()
self.options = self.appconfig('default')
self.identity_api = kvs.KvsIdentity(options=self.options, db={})
self.load_fixtures(default_fixtures)
#self.identity_api = kvs.KvsIdentity(options=self.options, db={})
#self.load_fixtures(default_fixtures)
def test_authenticate_bad_user(self):
self.assertRaises(AssertionError,

154
tests/test_backend_sql.py Normal file
View File

@ -0,0 +1,154 @@
import os
import uuid
from keystonelight import models
from keystonelight import test
from keystonelight.backends import sql
from keystonelight.backends.sql import migration
import test_backend_kvs
import default_fixtures
class SqlIdentity(test_backend_kvs.KvsIdentity):
def setUp(self):
super(SqlIdentity, self).setUp()
self.options = self.appconfig('default')
os.unlink('bla.db')
migration.db_sync(self.options, 1)
self.identity_api = sql.SqlIdentity(options=self.options)
self.load_fixtures(default_fixtures)
def test_authenticate_bad_user(self):
self.assertRaises(AssertionError,
self.identity_api.authenticate,
user_id=self.user_foo['id'] + 'WRONG',
tenant_id=self.tenant_bar['id'],
password=self.user_foo['password'])
def test_authenticate_bad_password(self):
self.assertRaises(AssertionError,
self.identity_api.authenticate,
user_id=self.user_foo['id'],
tenant_id=self.tenant_bar['id'],
password=self.user_foo['password'] + 'WRONG')
def test_authenticate_invalid_tenant(self):
self.assertRaises(AssertionError,
self.identity_api.authenticate,
user_id=self.user_foo['id'],
tenant_id=self.tenant_bar['id'] + 'WRONG',
password=self.user_foo['password'])
def test_authenticate_no_tenant(self):
user_ref, tenant_ref, extras_ref = self.identity_api.authenticate(
user_id=self.user_foo['id'],
password=self.user_foo['password'])
self.assertDictEquals(user_ref, self.user_foo)
self.assert_(tenant_ref is None)
self.assert_(not extras_ref)
def test_authenticate(self):
user_ref, tenant_ref, extras_ref = self.identity_api.authenticate(
user_id=self.user_foo['id'],
tenant_id=self.tenant_bar['id'],
password=self.user_foo['password'])
self.assertDictEquals(user_ref, self.user_foo)
self.assertDictEquals(tenant_ref, self.tenant_bar)
self.assertDictEquals(extras_ref, self.extras_foobar)
def test_get_tenant_bad_tenant(self):
tenant_ref = self.identity_api.get_tenant(
tenant_id=self.tenant_bar['id'] + 'WRONG')
self.assert_(tenant_ref is None)
def test_get_tenant(self):
tenant_ref = self.identity_api.get_tenant(tenant_id=self.tenant_bar['id'])
self.assertDictEquals(tenant_ref, self.tenant_bar)
def test_get_tenant_by_name_bad_tenant(self):
tenant_ref = self.identity_api.get_tenant(
tenant_id=self.tenant_bar['name'] + 'WRONG')
self.assert_(tenant_ref is None)
def test_get_tenant_by_name(self):
tenant_ref = self.identity_api.get_tenant_by_name(
tenant_name=self.tenant_bar['name'])
self.assertDictEquals(tenant_ref, self.tenant_bar)
def test_get_user_bad_user(self):
user_ref = self.identity_api.get_user(
user_id=self.user_foo['id'] + 'WRONG')
self.assert_(user_ref is None)
def test_get_user(self):
user_ref = self.identity_api.get_user(user_id=self.user_foo['id'])
self.assertDictEquals(user_ref, self.user_foo)
def test_get_extras_bad_user(self):
extras_ref = self.identity_api.get_extras(
user_id=self.user_foo['id'] + 'WRONG',
tenant_id=self.tenant_bar['id'])
self.assert_(extras_ref is None)
def test_get_extras_bad_tenant(self):
extras_ref = self.identity_api.get_extras(
user_id=self.user_foo['id'],
tenant_id=self.tenant_bar['id'] + 'WRONG')
self.assert_(extras_ref is None)
def test_get_extras(self):
extras_ref = self.identity_api.get_extras(
user_id=self.user_foo['id'],
tenant_id=self.tenant_bar['id'])
self.assertDictEquals(extras_ref, self.extras_foobar)
def test_get_role(self):
role_ref = self.identity_api.get_role(
role_id=self.role_keystone_admin['id'])
self.assertDictEquals(role_ref, self.role_keystone_admin)
class SqlToken(test_backend_kvs.KvsToken):
def setUp(self):
super(SqlToken, self).setUp()
self.token_api = sql.SqlToken(options=options)
self.load_fixtures(default_fixtures)
def test_token_crud(self):
token_id = uuid.uuid4().hex
data = {'id': token_id,
'a': 'b'}
data_ref = self.token_api.create_token(token_id, data)
self.assertDictEquals(data_ref, data)
new_data_ref = self.token_api.get_token(token_id)
self.assertEquals(new_data_ref, data)
self.token_api.delete_token(token_id)
deleted_data_ref = self.token_api.get_token(token_id)
self.assert_(deleted_data_ref is None)
class SqlCatalog(test_backend_kvs.KvsCatalog):
def setUp(self):
super(SqlCatalog, self).setUp()
self.catalog_api = sql.SqlCatalog(options=options)
self._load_fixtures()
def _load_fixtures(self):
self.catalog_foobar = self.catalog_api._create_catalog(
'foo', 'bar',
{'RegionFoo': {'service_bar': {'foo': 'bar'}}})
def test_get_catalog_bad_user(self):
catalog_ref = self.catalog_api.get_catalog('foo' + 'WRONG', 'bar')
self.assert_(catalog_ref is None)
def test_get_catalog_bad_tenant(self):
catalog_ref = self.catalog_api.get_catalog('foo', 'bar' + 'WRONG')
self.assert_(catalog_ref is None)
def test_get_catalog(self):
catalog_ref = self.catalog_api.get_catalog('foo', 'bar')
self.assertDictEquals(catalog_ref, self.catalog_foobar)