예제 #1
0
    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)
예제 #2
0
    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.'))
예제 #3
0
    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.'))
예제 #4
0
    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
                  })
예제 #5
0
    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)
예제 #6
0
    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
                  })
예제 #7
0
    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
                  })
예제 #8
0
    def test_sync(self):
        """Test DB sync which internally calls EMC"""
        self._db_command(db_method='sync')
        contract_head = alembic_migrations.get_alembic_branch_head(
            db_migration.CONTRACT_BRANCH)

        cmd = ("sqlite3 {0} \"SELECT version_num FROM alembic_version\""
               ).format(self.db_filepath)
        exitcode, out, err = execute(cmd, raise_error=True)
        self.assertEqual(contract_head, out.rstrip().decode("utf-8"))
예제 #9
0
    def test_sync(self):
        """Test DB sync which internally calls EMC"""
        self._db_command(db_method='sync')
        contract_head = alembic_migrations.get_alembic_branch_head(
            db_migration.CONTRACT_BRANCH)

        cmd = (
            "sqlite3 {0} \"SELECT version_num FROM alembic_version\"").format(
                self.db_filepath)
        exitcode, out, err = execute(cmd, raise_error=True)
        self.assertEqual(contract_head, out.rstrip().decode("utf-8"))
예제 #10
0
    def test_expand(self):
        """Test DB expand"""
        self._db_command(db_method='expand')
        expand_head = alembic_migrations.get_alembic_branch_head(
            db_migration.EXPAND_BRANCH)

        cmd = ("sqlite3 {0} \"SELECT version_num FROM alembic_version\""
               ).format(self.db_filepath)
        exitcode, out, err = execute(cmd, raise_error=True)
        self.assertEqual(expand_head, out.rstrip().decode("utf-8"))
        exitcode, out, err = self._db_command(db_method='expand')
        self.assertIn('Database expansion is up to date. '
                      'No expansion needed.', str(out))
예제 #11
0
    def test_expand(self):
        """Test DB expand"""
        self._db_command(db_method='expand')
        expand_head = alembic_migrations.get_alembic_branch_head(
            db_migration.EXPAND_BRANCH)

        cmd = (
            "sqlite3 {0} \"SELECT version_num FROM alembic_version\"").format(
                self.db_filepath)
        exitcode, out, err = execute(cmd, raise_error=True)
        self.assertEqual(expand_head, out.rstrip().decode("utf-8"))
        exitcode, out, err = self._db_command(db_method='expand')
        self.assertIn(
            'Database expansion is up to date. '
            'No expansion needed.', out)
예제 #12
0
    def test_contract(self):
        """Test DB contract"""
        self._db_command(db_method='expand')
        if data_migrations.has_pending_migrations(db_api.get_engine()):
            self._db_command(db_method='migrate')
        self._db_command(db_method='contract')
        contract_head = alembic_migrations.get_alembic_branch_head(
            db_migration.CONTRACT_BRANCH)

        cmd = (
            "sqlite3 {0} \"SELECT version_num FROM alembic_version\"").format(
                self.db_filepath)
        exitcode, out, err = execute(cmd, raise_error=True)
        self.assertEqual(contract_head, out.rstrip().decode("utf-8"))
        exitcode, out, err = self._db_command(db_method='contract')
        self.assertIn('Database is up to date. No migrations needed.', out)
예제 #13
0
    def test_contract(self):
        """Test DB contract"""
        self._db_command(db_method='expand')
        if data_migrations.has_pending_migrations(db_api.get_engine()):
            self._db_command(db_method='migrate')
        self._db_command(db_method='contract')
        contract_head = alembic_migrations.get_alembic_branch_head(
            db_migration.CONTRACT_BRANCH)

        cmd = ("sqlite3 {0} \"SELECT version_num FROM alembic_version\""
               ).format(self.db_filepath)
        exitcode, out, err = execute(cmd, raise_error=True)
        self.assertEqual(contract_head, out.rstrip().decode("utf-8"))
        exitcode, out, err = self._db_command(db_method='contract')
        self.assertIn('Database is up to date. No migrations needed.',
                      str(out))
예제 #14
0
    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)
예제 #15
0
    def test_migrate(self):
        """Test DB migrate"""
        self._db_command(db_method='expand')
        if data_migrations.has_pending_migrations(db_api.get_engine()):
            self._db_command(db_method='migrate')
        expand_head = alembic_migrations.get_alembic_branch_head(
            db_migration.EXPAND_BRANCH)

        cmd = (
            "sqlite3 {0} \"SELECT version_num FROM alembic_version\"").format(
                self.db_filepath)
        exitcode, out, err = execute(cmd, raise_error=True)
        self.assertEqual(expand_head, out.rstrip().decode("utf-8"))
        self.assertEqual(
            False, data_migrations.has_pending_migrations(db_api.get_engine()))
        if data_migrations.has_pending_migrations(db_api.get_engine()):
            exitcode, out, err = self._db_command(db_method='migrate')
            self.assertIn(
                'Database migration is up to date. No migration '
                'needed.', str(out))