From 5f8a616b15b70ddba6a64689b547521c91b95c84 Mon Sep 17 00:00:00 2001 From: Anton Arefiev Date: Wed, 18 Mar 2015 14:59:59 +0200 Subject: [PATCH] Fix 033 add encryption unique key migration SQLite doesn't support 'drop constraint' statament. So it notifies: SAWarning: Table 'encryption' specifies columns 'volume_type_id' as primary_key=True, not matching locally specified columns 'encryption_id'; setting the current primary key columns to 'encryption_id'. This warning may become an exception in a future release. Add new strategy for sqlite upgrade: table is renamed to temporary name, new table is created followed by INSERT statements, and renamed to original one. Change-Id: I723fdadb946f6944dde03954409899a9ddc3ee0e Closes-Bug: #1431374 --- .../versions/033_add_encryption_unique_key.py | 96 ++++++++++++------- tools/lintstack.py | 5 +- 2 files changed, 67 insertions(+), 34 deletions(-) diff --git a/cinder/db/sqlalchemy/migrate_repo/versions/033_add_encryption_unique_key.py b/cinder/db/sqlalchemy/migrate_repo/versions/033_add_encryption_unique_key.py index a37fa114b29..3c347d4e2fa 100644 --- a/cinder/db/sqlalchemy/migrate_repo/versions/033_add_encryption_unique_key.py +++ b/cinder/db/sqlalchemy/migrate_repo/versions/033_add_encryption_unique_key.py @@ -13,8 +13,8 @@ import uuid from migrate import PrimaryKeyConstraint, ForeignKeyConstraint -from sqlalchemy import Column -from sqlalchemy import MetaData, String, Table +from sqlalchemy import Column, MetaData, Table +from sqlalchemy import String, Integer, Boolean, DateTime def upgrade(migrate_engine): @@ -24,45 +24,42 @@ def upgrade(migrate_engine): encryptions = Table('encryption', meta, autoload=True) - encryption_id_column_kwargs = {} - if migrate_engine.name == 'ibm_db_sa': - # NOTE(junxiebj): DB2 10.5 doesn't support primary key - # constraints over nullable columns, so we have to - # make the column non-nullable in the DB2 case. - encryption_id_column_kwargs['nullable'] = False - encryption_id = Column('encryption_id', String(36), - **encryption_id_column_kwargs) - encryptions.create_column(encryption_id) + # NOTE: SQLite doesn't support 'drop constraint' statament + if migrate_engine.name == 'sqlite': + _upgrade_sqlite(meta, encryptions) + else: + encryption_id_column_kwargs = {} + if migrate_engine.name == 'ibm_db_sa': + # NOTE(junxiebj): DB2 10.5 doesn't support primary key + # constraints over nullable columns, so we have to + # make the column non-nullable in the DB2 case. + encryption_id_column_kwargs['nullable'] = False + encryption_id = Column('encryption_id', String(36), + **encryption_id_column_kwargs) + encryptions.create_column(encryption_id) - encryption_items = list(encryptions.select().execute()) + encryption_items = list(encryptions.select().execute()) - for item in encryption_items: - encryptions.update().\ - where(encryptions.c.volume_type_id == item['volume_type_id']).\ - values(encryption_id=str(uuid.uuid4())).execute() + for item in encryption_items: + encryptions.update().\ + where(encryptions.c.volume_type_id == item['volume_type_id']).\ + values(encryption_id=str(uuid.uuid4())).execute() - # NOTE (e0ne): need to drop FK first for MySQL - if migrate_engine.name == 'mysql': - ref_table = Table('volume_types', meta, autoload=True) - params = {'columns': [encryptions.c['volume_type_id']], - 'refcolumns': [ref_table.c['id']], - 'name': 'encryption_ibfk_1'} - volume_type_fk = ForeignKeyConstraint(**params) - volume_type_fk.drop() + # NOTE (e0ne): need to drop FK first for MySQL + if migrate_engine.name == 'mysql': + ref_table = Table('volume_types', meta, autoload=True) + params = {'columns': [encryptions.c['volume_type_id']], + 'refcolumns': [ref_table.c['id']], + 'name': 'encryption_ibfk_1'} + volume_type_fk = ForeignKeyConstraint(**params) + volume_type_fk.drop() - try: volume_type_pk = PrimaryKeyConstraint('volume_type_id', table=encryptions) volume_type_pk.drop() - except Exception: - # NOTE (e0ne): SQLite doesn't support 'drop constraint' statament - if migrate_engine.url.get_dialect().name.startswith('sqlite'): - pass - else: - raise - pkey = PrimaryKeyConstraint(encryptions.columns.encryption_id) - pkey.create() + pkey = PrimaryKeyConstraint(encryptions.columns.encryption_id) + pkey.create() def downgrade(migrate_engine): @@ -84,3 +81,36 @@ def downgrade(migrate_engine): 'name': 'encryption_ibfk_1'} volume_type_fk = ForeignKeyConstraint(**params) volume_type_fk.create() + + +def _upgrade_sqlite(meta, encryptions): + new_encryptions = Table( + 'encryption_33', meta, + Column('created_at', DateTime(timezone=False)), + Column('updated_at', DateTime(timezone=False)), + Column('deleted_at', DateTime(timezone=False)), + Column('deleted', Boolean(create_constraint=True, name=None)), + Column('cipher', String(255)), + Column('key_size', Integer), + Column('provider', String(255)), + Column('control_location', String(255)), + Column('encryption_id', String(36), primary_key=True), + Column('volume_type_id', String(36)) + ) + new_encryptions.create() + encryption_items = list(encryptions.select().execute()) + for item in encryption_items: + new_encryptions.insert().\ + values(created_at=item['created_at'], + updated_at=item['updated_at'], + deleted_at=item['deleted_at'], + deleted=item['deleted'], + cipher=item['cipher'], + key_size=item['key_size'], + provider=item['provider'], + control_location=item['control_location'], + encryption_id=str(uuid.uuid4()), + volume_type_id=item['volume_type_id']).execute() + + encryptions.drop() + new_encryptions.rename('encryption') diff --git a/tools/lintstack.py b/tools/lintstack.py index 51bf094eba2..27c3c5a83c7 100755 --- a/tools/lintstack.py +++ b/tools/lintstack.py @@ -37,11 +37,14 @@ ignore_codes = ["E1103"] # Note(xyang): the fourth and fifth error messages are for the code [E1101]. # They should be ignored because 'sha256' and 'sha224' are functions in # 'hashlib'. +# Note(aarefiev): the sixth error message is for SQLAlchemy rename calls in +# DB migration(033_add_encryption_unique_key). ignore_messages = ["An attribute affected in cinder.tests", "No name 'urllib' in module '_MovedItems'", "No value passed for parameter 'dml'", "Module 'hashlib' has no 'sha256' member", - "Module 'hashlib' has no 'sha224' member"] + "Module 'hashlib' has no 'sha224' member", + "Instance of 'Table' has no 'rename' member"] # Note(maoy): we ignore all errors in openstack.common because it should be # checked elsewhere. We also ignore cinder.tests for now due to high false # positive rate.