diff --git a/glance/db/sqlalchemy/migrate_repo/versions/012_id_to_uuid.py b/glance/db/sqlalchemy/migrate_repo/versions/012_id_to_uuid.py index 23097294e9..76048f2e09 100644 --- a/glance/db/sqlalchemy/migrate_repo/versions/012_id_to_uuid.py +++ b/glance/db/sqlalchemy/migrate_repo/versions/012_id_to_uuid.py @@ -41,11 +41,12 @@ def upgrade(migrate_engine): t_images = _get_table('images', meta) t_image_members = _get_table('image_members', meta) t_image_properties = _get_table('image_properties', meta) - if migrate_engine.url.get_dialect().name == "sqlite": + dialect = migrate_engine.url.get_dialect().name + if dialect == "sqlite": _upgrade_sqlite(t_images, t_image_members, t_image_properties) _update_all_ids_to_uuids(t_images, t_image_members, t_image_properties) else: - _upgrade_other(t_images, t_image_members, t_image_properties) + _upgrade_other(t_images, t_image_members, t_image_properties, dialect) def downgrade(migrate_engine): @@ -57,12 +58,13 @@ def downgrade(migrate_engine): t_images = _get_table('images', meta) t_image_members = _get_table('image_members', meta) t_image_properties = _get_table('image_properties', meta) - - if migrate_engine.url.get_dialect().name == "sqlite": + dialect = migrate_engine.url.get_dialect().name + if dialect == "sqlite": _update_all_uuids_to_ids(t_images, t_image_members, t_image_properties) _downgrade_sqlite(t_images, t_image_members, t_image_properties) else: - _downgrade_other(t_images, t_image_members, t_image_properties) + _downgrade_other(t_images, t_image_members, t_image_properties, + dialect) def _upgrade_sqlite(t_images, t_image_members, t_image_properties): @@ -205,13 +207,13 @@ def _downgrade_sqlite(t_images, t_image_members, t_image_properties): _sqlite_table_swap(t_image_members, t_image_properties, t_images) -def _upgrade_other(t_images, t_image_members, t_image_properties): +def _upgrade_other(t_images, t_image_members, t_image_properties, dialect): """ Upgrade 011 -> 012 with logic for non-SQLite databases. """ foreign_keys = _get_foreign_keys(t_images, t_image_members, - t_image_properties) + t_image_properties, dialect) for fk in foreign_keys: fk.drop() @@ -226,13 +228,13 @@ def _upgrade_other(t_images, t_image_members, t_image_properties): fk.create() -def _downgrade_other(t_images, t_image_members, t_image_properties): +def _downgrade_other(t_images, t_image_members, t_image_properties, dialect): """ Downgrade 012 -> 011 with logic for non-SQLite databases. """ foreign_keys = _get_foreign_keys(t_images, t_image_members, - t_image_properties) + t_image_properties, dialect) for fk in foreign_keys: fk.drop() @@ -265,23 +267,29 @@ def _get_table(table_name, metadata): return sqlalchemy.Table(table_name, metadata, autoload=True) -def _get_foreign_keys(t_images, t_image_members, t_image_properties): +def _get_foreign_keys(t_images, t_image_members, t_image_properties, dialect): """Retrieve and return foreign keys for members/properties tables.""" foreign_keys = [] if t_image_members.foreign_keys: img_members_fk_name = list(t_image_members.foreign_keys)[0].name - - fk1 = migrate.ForeignKeyConstraint([t_image_members.c.image_id], - [t_images.c.id], - name=img_members_fk_name) + if dialect == 'mysql': + fk1 = migrate.ForeignKeyConstraint([t_image_members.c.image_id], + [t_images.c.id], + name=img_members_fk_name) + else: + fk1 = migrate.ForeignKeyConstraint([t_image_members.c.image_id], + [t_images.c.id]) foreign_keys.append(fk1) if t_image_properties.foreign_keys: img_properties_fk_name = list(t_image_properties.foreign_keys)[0].name - - fk2 = migrate.ForeignKeyConstraint([t_image_properties.c.image_id], - [t_images.c.id], - name=img_properties_fk_name) + if dialect == 'mysql': + fk2 = migrate.ForeignKeyConstraint([t_image_properties.c.image_id], + [t_images.c.id], + name=img_properties_fk_name) + else: + fk2 = migrate.ForeignKeyConstraint([t_image_properties.c.image_id], + [t_images.c.id]) foreign_keys.append(fk2) return foreign_keys diff --git a/glance/tests/unit/test_migrations.py b/glance/tests/unit/test_migrations.py index 9a5bbdd3ca..e3b94d8efa 100644 --- a/glance/tests/unit/test_migrations.py +++ b/glance/tests/unit/test_migrations.py @@ -64,6 +64,8 @@ def _get_connect_string(backend, """ if backend == "mysql": backend = "mysql+mysqldb" + elif backend == "postgres": + backend = "postgresql+psycopg2" return ("%(backend)s://%(user)s:%(passwd)s@localhost/%(database)s" % locals()) @@ -268,6 +270,29 @@ class TestMigrations(utils.BaseTestCase): self.assertEqual(count, 0, "%d non InnoDB tables created" % count) connection.close() + def test_postgresql_connect_fail(self): + """ + Test that we can trigger a postgres connection failure and we fail + gracefully to ensure we don't break people without postgres + """ + if _is_backend_avail('postgresql', user="openstack_cifail"): + self.fail("Shouldn't have connected") + + def test_postgresql_opportunistically(self): + # Test postgresql database migration walk + if not _is_backend_avail('postgres'): + self.skipTest("postgresql not available") + # add this to the global lists to make reset work with it, it's removed + # automatically in tearDown so no need to clean it up here. + connect_string = _get_connect_string("postgres") + engine = sqlalchemy.create_engine(connect_string) + self.engines["postgresqlcitest"] = engine + self.test_databases["postgresqlcitest"] = connect_string + + # build a fully populated postgresql database with all the tables + self._reset_databases() + self._walk_versions(engine, False, False) + def _walk_versions(self, engine=None, snake_walk=False, downgrade=True, initial_version=None): # Determine latest version script from the repo, then diff --git a/tools/test-requires b/tools/test-requires index 75f9577b3e..73ae00c13f 100644 --- a/tools/test-requires +++ b/tools/test-requires @@ -19,5 +19,6 @@ testtools>=0.9.22 # Optional packages that should be installed when testing MySQL-python +psycopg2 pysendfile==2.0.0 xattr>=0.6.0