Add --check to keystone-manage db_sync command

This patch adds a new command to the db_sync upgrade commands. --check
will check the current state of the users upgrade repos and relay info
back to the user based on what version each command is currently at and
if the user has any outstanding db_sync commands left to run. It will
also notify the user if the db_sync commands were not upgraded in order

Closes-Bug: 1642212
Change-Id: I79d3640a780d624f14059fe311fafa0542c03357
This commit is contained in:
“Richard 2017-01-03 23:48:21 +00:00 committed by Richard Avelar
parent 2db574de6d
commit d5ce8ea0ed
5 changed files with 134 additions and 2 deletions

View File

@ -223,3 +223,27 @@ authenticate requests normally.
When this process completes, the database will no longer be able to support
the previous release.
Using db_sync check
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to check the current state of your rolling upgrades, you may run the
command ``keystone-manage db_sync --check``. This will inform you of any
outstanding actions you have left to take as well as any possible upgrades you
can make from your current version. Here are a list of possible return codes.
* A return code of ``0`` means you are currently up to date with the latest
migration script version and all ``db_sync`` commands are complete.
* A return code of ``1`` generally means something serious is wrong with your
database and operator intervention will be required.
* A return code of ``2`` means that an upgrade from your current database
version is available and your first step is to run ``keystone-manage
db_sync --expand``.
* A return code of ``3`` means that the expansion stage is complete, and the
next step is to run ``keystone-manage db_sync --migrate``.
* A return code of ``4`` means that the expansion and data migration stages are
complete, and the next step is to run ``keystone-manage db_sync --contract``.

View File

@ -19,6 +19,7 @@ import os
import sys
import uuid
import migrate
from oslo_config import cfg
from oslo_log import log
from oslo_log import versionutils
@ -445,15 +446,66 @@ class DbSync(BaseApp):
'that are no longer required. This command '
'should be run after all keystone nodes are '
'running the new release.'))
group.add_argument('--check', default=False, action='store_true',
help=('Check for outstanding database actions that '
'still need to be executed. This command can '
'be used to verify the condition of the '
'current database state.'))
return parser
@classmethod
def check_db_sync_status(self):
status = 0
expand_version = upgrades.get_db_version(repo='expand_repo')
migrate_version = upgrades.get_db_version(
repo='data_migration_repo')
contract_version = upgrades.get_db_version(repo='contract_repo')
repo = migrate.versioning.repository.Repository(
upgrades.find_repo('expand_repo'))
migration_script_version = int(max(repo.versions.versions))
if (contract_version > migrate_version or migrate_version >
expand_version):
LOG.info(_LI('Your database is out of sync. For more information '
'refer to https://docs.openstack.org/developer/'
'keystone/upgrading.html'))
status = 1
elif migration_script_version > expand_version:
LOG.info(_LI('Your database is not up to date. Your first step is '
'to run `keystone-manage db_sync --expand`.'))
status = 2
elif expand_version > migrate_version:
LOG.info(_LI('Expand version is ahead of migrate. Your next step '
'is to run `keystone-manage db_sync --migrate`.'))
status = 3
elif migrate_version > contract_version:
LOG.info(_LI('Migrate version is ahead of contract. Your next '
'step is to run `keystone-manage db_sync --contract`.'
))
status = 4
elif (migration_script_version == expand_version == migrate_version ==
contract_version):
LOG.info(_LI('All db_sync commands are upgraded to the same '
'version and up-to-date.'))
LOG.info(_LI('The latest installed migration script version is: '
'%(script)d.\nCurrent repository versions:\nExpand: '
'%(expand)d \nMigrate: %(migrate)d\nContract: '
'%(contract)d') % {'script': migration_script_version,
'expand': expand_version,
'migrate': migrate_version,
'contract': contract_version})
return status
@staticmethod
def main():
assert_not_extension(CONF.command.extension)
# It is possible to run expand and migrate at the same time,
# expand needs to run first however.
if CONF.command.expand and CONF.command.migrate:
if CONF.command.check:
sys.exit(DbSync.check_db_sync_status())
elif CONF.command.expand and CONF.command.migrate:
upgrades.expand_schema()
upgrades.migrate_data()
elif CONF.command.expand:

View File

@ -623,6 +623,7 @@ class CliDBSyncTestCase(unit.BaseTestCase):
class FakeConfCommand(object):
def __init__(self, parent):
self.extension = False
self.check = parent.command_check
self.expand = parent.command_expand
self.migrate = parent.command_migrate
self.contract = parent.command_contract
@ -636,6 +637,7 @@ class CliDBSyncTestCase(unit.BaseTestCase):
upgrades.expand_schema = mock.Mock()
upgrades.migrate_data = mock.Mock()
upgrades.contract_schema = mock.Mock()
self.command_check = False
self.command_expand = False
self.command_migrate = False
self.command_contract = False

View File

@ -41,16 +41,19 @@ WARNING::
import json
import uuid
import fixtures
import migrate
from migrate.versioning import repository
from migrate.versioning import script
import mock
from oslo_db import exception as db_exception
from oslo_db.sqlalchemy import test_base
from oslo_log import log
from sqlalchemy.engine import reflection
import sqlalchemy.exc
from testtools import matchers
from keystone.cmd import cli
from keystone.common import sql
from keystone.common.sql import upgrades
import keystone.conf
@ -1671,6 +1674,53 @@ class FullMigration(SqlMigrateBase, unit.TestCase):
self.assertTrue(1, expand)
self.assertTrue(1, migrate)
def test_db_sync_check(self):
checker = cli.DbSync()
latest_version = self.repos[EXPAND_REPO].max_version
# Assert the correct message is printed when expand is the first step
# that needs to run
self.expand(1)
log_info = self.useFixture(fixtures.FakeLogger(level=log.INFO))
status = checker.check_db_sync_status()
self.assertIn("keystone-manage db_sync --expand", log_info.output)
self.assertEqual(status, 2)
# Assert the correct message is printed when expand is farther than
# migrate
self.expand(latest_version)
log_info = self.useFixture(fixtures.FakeLogger(level=log.INFO))
status = checker.check_db_sync_status()
self.assertIn("keystone-manage db_sync --migrate", log_info.output)
self.assertEqual(status, 3)
# Assert the correct message is printed when migrate is farther than
# contract
self.migrate(latest_version)
log_info = self.useFixture(fixtures.FakeLogger(level=log.INFO))
status = checker.check_db_sync_status()
self.assertIn("keystone-manage db_sync --contract", log_info.output)
self.assertEqual(status, 4)
# Assert the correct message gets printed when all commands are on
# the same version
self.contract(latest_version)
log_info = self.useFixture(fixtures.FakeLogger(level=log.INFO))
status = checker.check_db_sync_status()
self.assertIn("All db_sync commands are upgraded", log_info.output)
self.assertEqual(status, 0)
def test_db_sync_check_out_of_sync(self):
checker = cli.DbSync()
# Assert we alert operator upgrades are out of sync
self.expand(3)
self.migrate(3)
self.contract(4)
log_info = self.useFixture(fixtures.FakeLogger(level=log.INFO))
status = checker.check_db_sync_status()
self.assertIn("Your database is out of sync", log_info.output)
self.assertEqual(status, 1)
def test_migration_002_password_created_at_not_nullable(self):
# upgrade each repository to 001
self.expand(1)

View File

@ -0,0 +1,4 @@
---
features:
- Added an option ``--check`` to ``keystone-manage db_sync``, the option will
allow a user to check the status of rolling upgrades in the database.