summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-03-14 03:03:37 +0000
committerGerrit Code Review <review@openstack.org>2013-03-14 03:03:37 +0000
commitf6b3e2e8cbba08e241c3fc7c067858641a28c65c (patch)
tree0cd723f15c1fc79c55ede04a6f1b4d03e01b5b19
parent5ad291857ed669dfaad77a5b3d534f5fe8589377 (diff)
parente551104d7c08f35d4cbf02e0c86e15c31a25d974 (diff)
Merge "Migrate roles from metadata to user_project_metadata"
-rw-r--r--keystone/common/sql/migrate_repo/versions/020_migrate_metadata_table_roles.py104
-rw-r--r--tests/test_sql_upgrade.py136
2 files changed, 236 insertions, 4 deletions
diff --git a/keystone/common/sql/migrate_repo/versions/020_migrate_metadata_table_roles.py b/keystone/common/sql/migrate_repo/versions/020_migrate_metadata_table_roles.py
new file mode 100644
index 00000000..4d0f9dfc
--- /dev/null
+++ b/keystone/common/sql/migrate_repo/versions/020_migrate_metadata_table_roles.py
@@ -0,0 +1,104 @@
+import json
+import uuid
+
+import sqlalchemy as sql
+from sqlalchemy import orm
+
+from keystone import config
+from keystone import exception
+
+
+CONF = config.CONF
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ user_table = sql.Table('user', meta, autoload=True)
+ role_table = sql.Table('role', meta, autoload=True)
+ project_table = sql.Table('project', meta, autoload=True)
+ new_metadata_table = sql.Table('user_project_metadata',
+ meta,
+ autoload=True)
+
+ conn = migrate_engine.connect()
+
+ old_metadata_table = sql.Table('metadata', meta, autoload=True)
+ session = sql.orm.sessionmaker(bind=migrate_engine)()
+
+ for metadata in session.query(old_metadata_table):
+ if not config.CONF.member_role_id in metadata.data:
+ data = json.loads(metadata.data)
+ data['roles'].append(config.CONF.member_role_id)
+ else:
+ data = metadata.data
+
+ r = session.query(new_metadata_table).filter_by(
+ user_id=metadata.user_id,
+ project_id=metadata.tenant_id).first()
+
+ if r is not None:
+ # roles should be the union of the two role lists
+ old_roles = data['roles']
+ new_roles = json.loads(r.data)['roles']
+ data['roles'] = list(set(old_roles) | set(new_roles))
+ q = new_metadata_table.update().where(
+ new_metadata_table.c.user_id == metadata.user_id and
+ new_metadata_table.c.project_id == metadata.tenant_id).values(
+ data=json.dumps(data))
+ else:
+ q = new_metadata_table.insert().values(
+ user_id=metadata.user_id,
+ project_id=metadata.tenant_id,
+ data=json.dumps(data))
+
+ conn.execute(q)
+
+ session.close()
+ old_metadata_table.drop()
+
+
+def downgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ user_table = sql.Table('user', meta, autoload=True)
+ project_table = sql.Table('project', meta, autoload=True)
+
+ metadata_table = sql.Table(
+ 'metadata',
+ meta,
+ sql.Column(
+ 'user_id',
+ sql.String(64),
+ sql.ForeignKey('user.id'),
+ primary_key=True),
+ sql.Column(
+ 'tenant_id',
+ sql.String(64),
+ primary_key=True),
+ sql.Column('data',
+ sql.Text()))
+ metadata_table.create(migrate_engine, checkfirst=True)
+
+ user_project_metadata_table = sql.Table(
+ 'user_project_metadata',
+ meta,
+ autoload=True)
+
+ metadata_table = sql.Table(
+ 'metadata',
+ meta,
+ autoload=True)
+
+ session = sql.orm.sessionmaker(bind=migrate_engine)()
+
+ for metadata in session.query(user_project_metadata_table):
+ if 'roles' in metadata:
+ roles = json.loads(metadata.data)
+ ins = (metadata_table.insert()
+ .values(user_id=metadata.user_id,
+ tenant_id=metadata.project_id))
+
+ session.close()
diff --git a/tests/test_sql_upgrade.py b/tests/test_sql_upgrade.py
index 62c69cc9..1ba9b419 100644
--- a/tests/test_sql_upgrade.py
+++ b/tests/test_sql_upgrade.py
@@ -35,7 +35,6 @@ import sqlalchemy
from keystone.common import sql
from keystone.common.sql import migration
from keystone import config
-from keystone import exception
from keystone import test
import default_fixtures
@@ -440,6 +439,137 @@ class SqlUpgradeTests(test.TestCase):
self.assertTableColumns('user_domain_metadata',
['user_id', 'domain_id', 'data'])
+ def test_metadata_table_migration(self):
+ # Scaffolding
+ session = self.Session()
+
+ self.upgrade(16)
+ domain_table = sqlalchemy.Table('domain', self.metadata, autoload=True)
+ user_table = sqlalchemy.Table('user', self.metadata, autoload=True)
+ role_table = sqlalchemy.Table('role', self.metadata, autoload=True)
+ project_table = sqlalchemy.Table(
+ 'project', self.metadata, autoload=True)
+ metadata_table = sqlalchemy.Table(
+ 'metadata', self.metadata, autoload=True)
+
+ # Create a Domain
+ domain = {'id': uuid.uuid4().hex,
+ 'name': uuid.uuid4().hex,
+ 'enabled': True}
+ self.engine.execute(domain_table.insert().values(domain))
+
+ # Create a Project
+ project = {'id': uuid.uuid4().hex,
+ 'name': uuid.uuid4().hex,
+ 'domain_id': domain['id'],
+ 'extra': "{}"}
+ self.engine.execute(project_table.insert().values(project))
+
+ # Create another Project
+ project2 = {'id': uuid.uuid4().hex,
+ 'name': uuid.uuid4().hex,
+ 'domain_id': domain['id'],
+ 'extra': "{}"}
+ self.engine.execute(project_table.insert().values(project2))
+
+ # Create a User
+ user = {'id': uuid.uuid4().hex,
+ 'name': uuid.uuid4().hex,
+ 'domain_id': domain['id'],
+ 'password': uuid.uuid4().hex,
+ 'enabled': True,
+ 'extra': json.dumps({})}
+ self.engine.execute(user_table.insert().values(user))
+
+ # Create a Role
+ role = {'id': uuid.uuid4().hex,
+ 'name': uuid.uuid4().hex}
+ self.engine.execute(role_table.insert().values(role))
+
+ # And another role
+ role2 = {'id': uuid.uuid4().hex,
+ 'name': uuid.uuid4().hex}
+ self.engine.execute(role_table.insert().values(role2))
+
+ # Grant Role to User
+ role_grant = {'user_id': user['id'],
+ 'tenant_id': project['id'],
+ 'data': json.dumps({"roles": [role['id']]})}
+ self.engine.execute(metadata_table.insert().values(role_grant))
+
+ role_grant = {'user_id': user['id'],
+ 'tenant_id': project2['id'],
+ 'data': json.dumps({"roles": [role2['id']]})}
+ self.engine.execute(metadata_table.insert().values(role_grant))
+
+ session.commit()
+
+ self.upgrade(17)
+
+ user_project_metadata_table = sqlalchemy.Table(
+ 'user_project_metadata', self.metadata, autoload=True)
+
+ # Test user in project has role
+ r = session.execute('select data from metadata where user_id="%s"'
+ 'and tenant_id="%s"' %
+ (user['id'], project['id']))
+ test_project1 = json.loads(r.fetchone()['data'])
+ self.assertEqual(len(test_project1['roles']), 1)
+ self.assertIn(role['id'], test_project1['roles'])
+
+ # Test user in project2 has role2
+ r = session.execute('select data from metadata where user_id="%s"'
+ ' and tenant_id="%s"' %
+ (user['id'], project2['id']))
+ test_project2 = json.loads(r.fetchone()['data'])
+ self.assertEqual(len(test_project2['roles']), 1)
+ self.assertIn(role2['id'], test_project2['roles'])
+
+ # Test for user in project has role in user_project_metadata
+ # Migration 17 does not properly migrate this data, so this should
+ # be None.
+ r = session.execute('select data from user_project_metadata where '
+ 'user_id="%s" and project_id="%s"' %
+ (user['id'], project['id']))
+ self.assertIsNone(r.fetchone())
+
+ # Create a conflicting user-project in user_project_metadata with
+ # a different role
+ data = json.dumps({"roles": [role2['id']]})
+ role_grant = {'user_id': user['id'],
+ 'project_id': project['id'],
+ 'data': data}
+ cmd = user_project_metadata_table.insert().values(role_grant)
+ self.engine.execute(cmd)
+ # End Scaffolding
+
+ # Migrate to 20
+ self.upgrade(20)
+
+ # The user-project pairs should have all roles from the previous
+ # metadata table in addition to any roles currently in
+ # user_project_metadata
+ r = session.execute('select data from user_project_metadata '
+ 'where user_id="%s" and project_id="%s"' %
+ (user['id'], project['id']))
+ role_ids = json.loads(r.fetchone()['data'])['roles']
+ self.assertEqual(len(role_ids), 3)
+ self.assertIn(CONF.member_role_id, role_ids)
+ self.assertIn(role['id'], role_ids)
+ self.assertIn(role2['id'], role_ids)
+
+ # pairs that only existed in old metadata table should be in
+ # user_project_metadata
+ r = session.execute('select data from user_project_metadata where '
+ 'user_id="%s" and project_id="%s"' %
+ (user['id'], project2['id']))
+ role_ids = json.loads(r.fetchone()['data'])['roles']
+ self.assertEqual(len(role_ids), 2)
+ self.assertIn(CONF.member_role_id, role_ids)
+ self.assertIn(role2['id'], role_ids)
+
+ self.assertTableDoesNotExist('metadata')
+
def test_upgrade_default_roles(self):
def count_member_roles():
session = self.Session()
@@ -673,9 +803,7 @@ class SqlUpgradeTests(test.TestCase):
try:
temp_metadata = sqlalchemy.MetaData()
temp_metadata.bind = self.engine
- table = sqlalchemy.Table(table_name,
- temp_metadata,
- autoload=True)
+ sqlalchemy.Table(table_name, temp_metadata, autoload=True)
except sqlalchemy.exc.NoSuchTableError:
pass
else: