Fix normalize identity sql ugrade for Mysql and postgresql

Change-Id: Idf374a748f8ed2add5310b504806ffabfa64bed9
This commit is contained in:
Adam Young 2013-02-08 20:32:35 -05:00
parent 1f258c4d18
commit 329b00d6db
4 changed files with 75 additions and 51 deletions

View File

@ -17,10 +17,11 @@
from sqlalchemy import Column, MetaData, String, Table, Text, types
from sqlalchemy.orm import sessionmaker
from keystone import config
#sqlite doesn't support dropping columns. Copy to a new table instead
def downgrade_user_table(meta, migrate_engine):
def downgrade_user_table_with_copy(meta, migrate_engine):
maker = sessionmaker(bind=migrate_engine)
session = maker()
session.execute("ALTER TABLE user RENAME TO orig_user;")
@ -43,7 +44,7 @@ def downgrade_user_table(meta, migrate_engine):
session.execute("drop table orig_user;")
def downgrade_tenant_table(meta, migrate_engine):
def downgrade_tenant_table_with_copy(meta, migrate_engine):
maker = sessionmaker(bind=migrate_engine)
session = maker()
session.execute("ALTER TABLE tenant RENAME TO orig_tenant;")
@ -66,17 +67,30 @@ def downgrade_tenant_table(meta, migrate_engine):
session.execute("drop table orig_tenant;")
def downgrade_user_table_with_column_drop(meta, migrate_engine):
user_table = Table('user', meta, autoload=True)
user_table.drop_column(Column('password', String(128)))
user_table.drop_column(Column('enabled', types.Boolean,
default=True))
def downgrade_tenant_table_with_column_drop(meta, migrate_engine):
tenant_table = Table('tenant', meta, autoload=True)
tenant_table.drop_column(Column('description', Text()))
tenant_table.drop_column(Column('enabled', types.Boolean))
def upgrade_user_table(meta, migrate_engine):
user_table = Table('user', meta, autoload=True)
user_table.create_column(Column("password", String(128)))
user_table.create_column(Column("enabled", types.Boolean,
user_table.create_column(Column('password', String(128)))
user_table.create_column(Column('enabled', types.Boolean,
default=True))
def upgrade_tenant_table(meta, migrate_engine):
tenant_table = Table('tenant', meta, autoload=True)
tenant_table.create_column(Column("description", Text()))
tenant_table.create_column(Column("enabled", types.Boolean))
tenant_table.create_column(Column('description', Text()))
tenant_table.create_column(Column('enabled', types.Boolean))
def upgrade(migrate_engine):
@ -89,5 +103,9 @@ def upgrade(migrate_engine):
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
downgrade_user_table(meta, migrate_engine)
downgrade_tenant_table(meta, migrate_engine)
if migrate_engine.name == 'sqlite':
downgrade_user_table_with_copy(meta, migrate_engine)
downgrade_tenant_table_with_copy(meta, migrate_engine)
else:
downgrade_user_table_with_column_drop(meta, migrate_engine)
downgrade_tenant_table_with_column_drop(meta, migrate_engine)

View File

@ -40,9 +40,11 @@ def downgrade_user_table(meta, migrate_engine):
extra = json.loads(user.extra)
extra['password'] = user.password
extra['enabled'] = '%r' % user.enabled
session.execute(
'UPDATE `user` SET `extra`=:extra WHERE `id`=:id',
{'id': user.id, 'extra': json.dumps(extra)})
values = {'extra': json.dumps(extra)}
update = user_table.update().\
where(user_table.c.id == user.id).\
values(values)
migrate_engine.execute(update)
session.commit()
@ -54,9 +56,11 @@ def downgrade_tenant_table(meta, migrate_engine):
extra = json.loads(tenant.extra)
extra['description'] = tenant.description
extra['enabled'] = '%r' % tenant.enabled
session.execute(
'UPDATE `tenant` SET `extra`=:extra WHERE `id`=:id',
{'id': tenant.id, 'extra': json.dumps(extra)})
values = {'extra': json.dumps(extra)}
update = tenant_table.update().\
where(tenant_table.c.id == tenant.id).\
values(values)
migrate_engine.execute(update)
session.commit()
@ -64,19 +68,15 @@ def upgrade_user_table(meta, migrate_engine):
user_table = Table('user', meta, autoload=True)
maker = sessionmaker(bind=migrate_engine)
session = maker()
for user in session.query(user_table).all():
extra = json.loads(user.extra)
password = extra.pop('password', None)
enabled = extra.pop('enabled', True)
session.execute(
'UPDATE `user` SET `password`=:password, `enabled`=:enabled, '
'`extra`=:extra WHERE `id`=:id',
{
'id': user.id,
'password': password,
'enabled': is_enabled(enabled),
'extra': json.dumps(extra)})
values = {'password': extra.pop('password', None),
'enabled': extra.pop('enabled', True),
'extra': json.dumps(extra)}
update = user_table.update().\
where(user_table.c.id == user.id).\
values(values)
migrate_engine.execute(update)
session.commit()
@ -87,16 +87,13 @@ def upgrade_tenant_table(meta, migrate_engine):
session = maker()
for tenant in session.query(tenant_table):
extra = json.loads(tenant.extra)
description = extra.pop('description', None)
enabled = extra.pop('enabled', True)
session.execute(
'UPDATE `tenant` SET `enabled`=:enabled, `extra`=:extra, '
'`description`=:description WHERE `id`=:id',
{
'id': tenant.id,
'description': description,
'enabled': is_enabled(enabled),
'extra': json.dumps(extra)})
values = {'description': extra.pop('description', None),
'enabled': extra.pop('enabled', True),
'extra': json.dumps(extra)}
update = tenant_table.update().\
where(tenant_table.c.id == tenant.id).\
values(values)
migrate_engine.execute(update)
session.commit()

View File

@ -1,7 +1,9 @@
[sql]
connection = sqlite://
#For a file based sqlite use
#connection = sqlite:////tmp/keystone.db
#To Test MySQL:
#connection = mysql://root:keystone@localhost/keystone?charset=utf8
#connection = mysql://keystone:keystone@localhost/keystone?charset=utf8
#To Test PostgreSQL:
#connection = postgresql://keystone:keystone@localhost/keystone?client_encoding=utf8
idle_timeout = 200

View File

@ -44,6 +44,11 @@ CONF = config.CONF
class SqlUpgradeTests(test.TestCase):
def initialize_sql(self):
self.metadata = sqlalchemy.MetaData()
self.metadata.bind = self.engine
def setUp(self):
super(SqlUpgradeTests, self).setUp()
self.config([test.etcdir('keystone.conf.sample'),
@ -51,18 +56,16 @@ class SqlUpgradeTests(test.TestCase):
test.testsdir('backend_sql.conf')])
# create and share a single sqlalchemy engine for testing
base = sql.Base()
self.engine = base.get_engine(allow_global_engine=False)
self.Session = base.get_sessionmaker(
engine=self.engine,
autocommit=False)
self.metadata = sqlalchemy.MetaData()
self.base = sql.Base()
self.engine = self.base.get_engine(allow_global_engine=False)
self.Session = self.base.get_sessionmaker(engine=self.engine,
autocommit=False)
# populate the engine with tables & fixtures
self.metadata.bind = self.engine
self.initialize_sql()
self.repo_path = migration._find_migrate_repo()
self.schema = versioning_api.ControlledSchema.create(self.engine,
self.repo_path, 0)
self.schema = versioning_api.ControlledSchema.create(
self.engine,
self.repo_path, 0)
# auto-detect the highest available schema version in the migrate_repo
self.max_version = self.schema.repository.version().version
@ -82,7 +85,7 @@ class SqlUpgradeTests(test.TestCase):
self.assertEqual(version, 0, "DB is at version 0")
def test_two_steps_forward_one_step_back(self):
"""You should be able to cleanly undo a re-apply all upgrades.
"""You should be able to cleanly undo and re-apply all upgrades.
Upgrades are run in the following order::
@ -97,6 +100,7 @@ class SqlUpgradeTests(test.TestCase):
def assertTableColumns(self, table_name, expected_cols):
"""Asserts that the table contains the expected set of columns."""
self.initialize_sql()
table = self.select_table(table_name)
actual_cols = [col.name for col in table.columns]
self.assertEqual(expected_cols, actual_cols, '%s table' % table_name)
@ -352,14 +356,17 @@ class SqlUpgradeTests(test.TestCase):
['user_id', 'domain_id', 'data'])
def populate_user_table(self):
user_table = sqlalchemy.Table('user',
self.metadata,
autoload=True)
session = self.Session()
insert = user_table.insert()
for user in default_fixtures.USERS:
extra = copy.deepcopy(user)
extra.pop('id')
extra.pop('name')
self.engine.execute("insert into user values ('%s', '%s', '%s')"
% (user['id'],
user['name'],
json.dumps(extra)))
user['extra'] = json.dumps(extra)
insert.execute(user)
def populate_tenant_table(self):
for tenant in default_fixtures.TENANTS: