def expand(self, online_migration=True): """Run the expansion phase of a database migration.""" if online_migration: self._validate_engine(db_api.get_engine()) curr_heads = alembic_migrations.get_current_alembic_heads() expand_head = alembic_migrations.get_alembic_branch_head( db_migration.EXPAND_BRANCH) contract_head = alembic_migrations.get_alembic_branch_head( db_migration.CONTRACT_BRANCH) if not expand_head: sys.exit( _('Database expansion failed. Couldn\'t find head ' 'revision of expand branch.')) elif (contract_head in curr_heads): print(_('Database is up to date. No migrations needed.')) sys.exit() if expand_head not in curr_heads: self._sync(version=expand_head) curr_heads = alembic_migrations.get_current_alembic_heads() if expand_head not in curr_heads: sys.exit( _('Database expansion failed. Database expansion ' 'should have brought the database version up to ' '"%(e_rev)s" revision. But, current revisions are' ': %(curr_revs)s ') % { 'e_rev': expand_head, 'curr_revs': curr_heads }) else: print(_('Database expansion is up to date. No expansion needed.'))
def expand(self): """Run the expansion phase of a rolling upgrade procedure.""" engine = db_api.get_engine() if engine.engine.name != 'mysql': sys.exit( _('Rolling upgrades are currently supported only for ' 'MySQL')) expand_head = alembic_migrations.get_alembic_branch_head( db_migration.EXPAND_BRANCH) if not expand_head: sys.exit( _('Database expansion failed. Couldn\'t find head ' 'revision of expand branch.')) self.sync(version=expand_head) curr_heads = alembic_migrations.get_current_alembic_heads() if expand_head not in curr_heads: sys.exit( _('Database expansion failed. Database expansion should ' 'have brought the database version up to "%(e_rev)s" ' 'revision. But, current revisions are: %(curr_revs)s ') % { 'e_rev': expand_head, 'curr_revs': curr_heads })
def check(self): """Report any pending database upgrades. An exit code of 3 indicates db expand is needed, see stdout output. An exit code of 4 indicates db migrate is needed, see stdout output. An exit code of 5 indicates db contract is needed, see stdout output. """ engine = db_api.get_engine() self._validate_engine(engine) curr_heads = alembic_migrations.get_current_alembic_heads() expand_heads = alembic_migrations.get_alembic_branch_head( db_migration.EXPAND_BRANCH) contract_heads = alembic_migrations.get_alembic_branch_head( db_migration.CONTRACT_BRANCH) if (contract_heads in curr_heads): print(_('Database is up to date. No upgrades needed.')) sys.exit() elif ((not expand_heads) or (expand_heads not in curr_heads)): print( _('Your database is not up to date. ' 'Your first step is to run `glance-manage db expand`.')) sys.exit(3) elif data_migrations.has_pending_migrations(db_api.get_engine()): print( _('Your database is not up to date. ' 'Your next step is to run `glance-manage db migrate`.')) sys.exit(4) elif ((not contract_heads) or (contract_heads not in curr_heads)): print( _('Your database is not up to date. ' 'Your next step is to run `glance-manage db contract`.')) sys.exit(5)
def migrate(self, online_migration=True): """Run the data migration phase of a database migration.""" if online_migration: self._validate_engine(db_api.get_engine()) curr_heads = alembic_migrations.get_current_alembic_heads() contract_head = alembic_migrations.get_alembic_branch_head( db_migration.CONTRACT_BRANCH) if (contract_head in curr_heads): print(_('Database is up to date. No migrations needed.')) sys.exit() expand_head = alembic_migrations.get_alembic_branch_head( db_migration.EXPAND_BRANCH) if expand_head not in curr_heads: sys.exit( _('Data migration did not run. Data migration cannot be ' 'run before database expansion. Run database ' 'expansion first using "glance-manage db expand"')) if data_migrations.has_pending_migrations(db_api.get_engine()): rows_migrated = data_migrations.migrate(db_api.get_engine()) print(_('Migrated %s rows') % rows_migrated) else: print(_('Database migration is up to date. No migration needed.'))
def sync(self, version=None): """Perform a complete (offline) database migration""" global USE_TRIGGERS # This flags let's us bypass trigger setup & teardown for non-rolling # upgrades. We set this as a global variable immediately before handing # off to sqlalchemy-migrate, because we can't pass arguments directly # to migrations that depend on it. USE_TRIGGERS = False curr_heads = alembic_migrations.get_current_alembic_heads() contract = alembic_migrations.get_alembic_branch_head( db_migration.CONTRACT_BRANCH) if (contract in curr_heads): print(_('Database is up to date. No migrations needed.')) sys.exit() try: # NOTE(abhishekk): db_sync should not be used for online # migrations. self.expand(online_migration=False) self.migrate(online_migration=False) self.contract(online_migration=False) print(_('Database is synced successfully.')) except exception.GlanceException as e: sys.exit(_('Failed to sync database: ERROR: %s') % e)
def contract(self, online_migration=True): """Run the contraction phase of a database migration.""" if online_migration: self._validate_engine(db_api.get_engine()) curr_heads = alembic_migrations.get_current_alembic_heads() contract_head = alembic_migrations.get_alembic_branch_head( db_migration.CONTRACT_BRANCH) if not contract_head: sys.exit( _('Database contraction failed. Couldn\'t find head ' 'revision of contract branch.')) elif (contract_head in curr_heads): print(_('Database is up to date. No migrations needed.')) sys.exit() expand_head = alembic_migrations.get_alembic_branch_head( db_migration.EXPAND_BRANCH) if expand_head not in curr_heads: sys.exit( _('Database contraction did not run. Database ' 'contraction cannot be run before database expansion. ' 'Run database expansion first using ' '"glance-manage db expand"')) if data_migrations.has_pending_migrations(db_api.get_engine()): sys.exit( _('Database contraction did not run. Database ' 'contraction cannot be run before data migration is ' 'complete. Run data migration using "glance-manage db ' 'migrate".')) self._sync(version=contract_head) curr_heads = alembic_migrations.get_current_alembic_heads() if contract_head not in curr_heads: sys.exit( _('Database contraction failed. Database contraction ' 'should have brought the database version up to ' '"%(e_rev)s" revision. But, current revisions are: ' '%(curr_revs)s ') % { 'e_rev': expand_head, 'curr_revs': curr_heads })
def contract(self): """Run the contraction phase of a rolling upgrade procedure.""" engine = db_api.get_engine() if engine.engine.name != 'mysql': sys.exit( _('Rolling upgrades are currently supported only for ' 'MySQL')) contract_head = alembic_migrations.get_alembic_branch_head( db_migration.CONTRACT_BRANCH) if not contract_head: sys.exit( _('Database contraction failed. Couldn\'t find head ' 'revision of contract branch.')) curr_heads = alembic_migrations.get_current_alembic_heads() expand_head = alembic_migrations.get_alembic_branch_head( db_migration.EXPAND_BRANCH) if expand_head not in curr_heads: sys.exit( _('Database contraction did not run. Database ' 'contraction cannot be run before database expansion. ' 'Run database expansion first using ' '"glance-manage db expand"')) if data_migrations.has_pending_migrations(db_api.get_engine()): sys.exit( _('Database contraction did not run. Database ' 'contraction cannot be run before data migration is ' 'complete. Run data migration using "glance-manage db ' 'migrate".')) self.sync(version=contract_head) curr_heads = alembic_migrations.get_current_alembic_heads() if contract_head not in curr_heads: sys.exit( _('Database contraction failed. Database contraction ' 'should have brought the database version up to ' '"%(e_rev)s" revision. But, current revisions are: ' '%(curr_revs)s ') % { 'e_rev': expand_head, 'curr_revs': curr_heads })
def version(self): """Print database's current migration level""" current_heads = alembic_migrations.get_current_alembic_heads() if current_heads: # Migrations are managed by alembic for head in current_heads: print(head) else: # Migrations are managed by legacy versioning scheme print( _('Database is either not under migration control or under ' 'legacy migration control, please run ' '"glance-manage db sync" to place the database under ' 'alembic migration control.'))
def migrate(self): engine = db_api.get_engine() if engine.engine.name != 'mysql': sys.exit( _('Rolling upgrades are currently supported only for ' 'MySQL')) curr_heads = alembic_migrations.get_current_alembic_heads() expand_head = alembic_migrations.get_alembic_branch_head( db_migration.EXPAND_BRANCH) if expand_head not in curr_heads: sys.exit( _('Data migration did not run. Data migration cannot be ' 'run before database expansion. Run database ' 'expansion first using "glance-manage db expand"')) rows_migrated = data_migrations.migrate(db_api.get_engine()) print(_('Migrated %s rows') % rows_migrated)
def _sync(self, version): """ Place an existing database under migration control and upgrade it. """ alembic_migrations.place_database_under_alembic_control() a_config = alembic_migrations.get_alembic_config() alembic_command.upgrade(a_config, version) heads = alembic_migrations.get_current_alembic_heads() if heads is None: raise exception.GlanceException("Database sync failed") revs = ", ".join(heads) if version == 'heads': print(_("Upgraded database, current revision(s):"), revs) else: print( _('Upgraded database to: %(v)s, current revision(s): %(r)s') % { 'v': version, 'r': revs })