Skip to content

Commit a359753

Browse files
author
Balazs Gibizer
committed
Fix nova-manage db version
When nova switched to alembic implementation was added to nova-manage db version CLI to query the current db revision from alembic. However multiple mistake was made. The code called alembic_api.current[1] with an Engine object while that call expects a Config object instead. This leads to but/1943436. Also the same code expected that this call returns the revision. But that call just prints the revision to the standard output instead. So the implementations has been change from calling the alembic command API which is mostly created for CLI consumption to MigrationContext.get_current_revision() call that is intended to be used as a python API instead. [1] https://alembic.sqlalchemy.org/en/latest/api/commands.html#alembic.command.current Co-Authored-By: Sean Mooney <[email protected]> Closes-Bug: #1943436 Change-Id: I9fa7c03310c5bdb82e9a9c39727edb12eeae77f0
1 parent 166b173 commit a359753

File tree

4 files changed

+22
-36
lines changed

4 files changed

+22
-36
lines changed

nova/db/migration.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ def db_version(database='main', context=None):
170170

171171
alembic_version = None
172172
if _is_database_under_alembic_control(engine):
173-
alembic_version = alembic_api.current(engine)
173+
with engine.connect() as conn:
174+
m_context = alembic_migration.MigrationContext.configure(conn)
175+
alembic_version = m_context.get_current_revision()
174176

175177
return alembic_version or migrate_version

nova/tests/unit/db/api/test_migrations.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -244,18 +244,9 @@ def test_walk_versions(self):
244244
def test_db_version_alembic(self):
245245
migration.db_sync(database='api')
246246

247-
# FIXME(gibi): this is bug/1943436
248-
ex = self.assertRaises(
249-
AttributeError, migration.db_version, database='api')
250-
self.assertIn(
251-
"'Engine' object has no attribute 'get_main_option'",
252-
str(ex)
253-
)
254-
255-
# It should return the head of the migrations instead
256-
# head = alembic_script.ScriptDirectory.from_config(
257-
# self.config).get_current_head()
258-
# self.assertEqual(head, migration.db_version(database='api'))
247+
head = alembic_script.ScriptDirectory.from_config(
248+
self.config).get_current_head()
249+
self.assertEqual(head, migration.db_version(database='api'))
259250

260251

261252
class TestMigrationsWalkSQLite(

nova/tests/unit/db/main/test_migrations.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -287,18 +287,9 @@ def test_walk_versions(self):
287287
def test_db_version_alembic(self):
288288
migration.db_sync(database='main')
289289

290-
# FIXME(gibi): this is bug/1943436
291-
ex = self.assertRaises(
292-
AttributeError, migration.db_version, database='main')
293-
self.assertIn(
294-
"'Engine' object has no attribute 'get_main_option'",
295-
str(ex)
296-
)
297-
298-
# It should return the head of the migrations instead
299-
# head = alembic_script.ScriptDirectory.from_config(
300-
# self.config).get_current_head()
301-
# self.assertEqual(head, migration.db_version(database='main'))
290+
head = alembic_script.ScriptDirectory.from_config(
291+
self.config).get_current_head()
292+
self.assertEqual(head, migration.db_version(database='main'))
302293

303294

304295
class TestMigrationsWalkSQLite(

nova/tests/unit/db/test_migration.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import fixtures
1818
import mock
1919

20-
from alembic import command as alembic_api
2120
from alembic.runtime import migration as alembic_migration
2221
from migrate import exceptions as migrate_exceptions
2322
from migrate.versioning import api as migrate_api
@@ -151,7 +150,7 @@ def test_db_sync_with_existing_alembic_database(self):
151150
self._test_db_sync(has_migrate, has_alembic)
152151

153152

154-
@mock.patch.object(alembic_api, 'current')
153+
@mock.patch.object(alembic_migration.MigrationContext, 'configure')
155154
@mock.patch.object(migrate_api, 'db_version')
156155
@mock.patch.object(migration, '_is_database_under_alembic_control')
157156
@mock.patch.object(migration, '_is_database_under_migrate_control')
@@ -161,15 +160,15 @@ class TestDBVersion(test.NoDBTestCase):
161160

162161
def test_db_version_invalid_databse(
163162
self, mock_find_repo, mock_get_engine, mock_is_migrate,
164-
mock_is_alembic, mock_migrate_version, mock_alembic_version,
163+
mock_is_alembic, mock_migrate_version, mock_m_context_configure,
165164
):
166165
"""We only have two databases."""
167166
self.assertRaises(
168167
exception.Invalid, migration.db_version, database='invalid')
169168

170169
def test_db_version_migrate(
171170
self, mock_find_repo, mock_get_engine, mock_is_migrate,
172-
mock_is_alembic, mock_migrate_version, mock_alembic_version,
171+
mock_is_alembic, mock_migrate_version, mock_m_context_configure,
173172
):
174173
"""Database is controlled by sqlalchemy-migrate."""
175174
mock_is_migrate.return_value = True
@@ -184,30 +183,33 @@ def test_db_version_migrate(
184183
mock_is_alembic.assert_called_once()
185184
mock_migrate_version.assert_called_once_with(
186185
mock_get_engine.return_value, mock_find_repo.return_value)
187-
mock_alembic_version.assert_not_called()
186+
mock_m_context_configure.assert_not_called()
188187

189188
def test_db_version_alembic(
190189
self, mock_find_repo, mock_get_engine, mock_is_migrate,
191-
mock_is_alembic, mock_migrate_version, mock_alembic_version,
190+
mock_is_alembic, mock_migrate_version, mock_m_context_configure,
192191
):
193192
"""Database is controlled by alembic."""
194193
mock_is_migrate.return_value = False
195194
mock_is_alembic.return_value = True
196195

197196
ret = migration.db_version('main')
198-
self.assertEqual(mock_alembic_version.return_value, ret)
197+
mock_m_context = mock_m_context_configure.return_value
198+
self.assertEqual(
199+
mock_m_context.get_current_revision.return_value,
200+
ret
201+
)
199202

200203
mock_find_repo.assert_called_once_with('main')
201204
mock_get_engine.assert_called_once_with('main', context=None)
202205
mock_is_migrate.assert_called_once()
203206
mock_is_alembic.assert_called_once()
204207
mock_migrate_version.assert_not_called()
205-
mock_alembic_version.assert_called_once_with(
206-
mock_get_engine.return_value)
208+
mock_m_context_configure.assert_called_once()
207209

208210
def test_db_version_not_controlled(
209211
self, mock_find_repo, mock_get_engine, mock_is_migrate,
210-
mock_is_alembic, mock_migrate_version, mock_alembic_version,
212+
mock_is_alembic, mock_migrate_version, mock_m_context_configure,
211213
):
212214
"""Database is not controlled."""
213215
mock_is_migrate.return_value = False
@@ -221,7 +223,7 @@ def test_db_version_not_controlled(
221223
mock_is_migrate.assert_called_once()
222224
mock_is_alembic.assert_called_once()
223225
mock_migrate_version.assert_not_called()
224-
mock_alembic_version.assert_not_called()
226+
mock_m_context_configure.assert_not_called()
225227

226228

227229
class TestGetEngine(test.NoDBTestCase):

0 commit comments

Comments
 (0)