diff --git a/etc/glance-api.conf b/etc/glance-api.conf index 6a6bbdd8f0..12eca9121a 100644 --- a/etc/glance-api.conf +++ b/etc/glance-api.conf @@ -550,6 +550,16 @@ scrubber_datadir = /var/lib/glance/scrubber # Base directory that the Image Cache uses image_cache_dir = /var/lib/glance/image-cache/ + +# =============== Manager Options ================================= + +# DEPRECATED. TO BE REMOVED IN THE JUNO RELEASE. +# Whether or not to enforce that all DB tables have charset utf8. +# If your database tables do not have charset utf8 you will +# need to convert before this option is removed. This option is +# only relevant if your database engine is MySQL. +#db_enforce_mysql_charset = True + [keystone_authtoken] auth_host = 127.0.0.1 auth_port = 35357 diff --git a/glance/cmd/manage.py b/glance/cmd/manage.py index 6213c44e88..3ca6b8d894 100755 --- a/glance/cmd/manage.py +++ b/glance/cmd/manage.py @@ -48,7 +48,22 @@ from glance.openstack.common.db.sqlalchemy import migration from glance.openstack.common import log from glance.openstack.common import strutils + +LOG = log.getLogger(__name__) + +manager_opts = [ + cfg.BoolOpt('db_enforce_mysql_charset', + default=True, + help=_('DEPRECATED. TO BE REMOVED IN THE JUNO RELEASE. ' + 'Whether or not to enforce that all DB tables have ' + 'charset utf8. If your database tables do not have ' + 'charset utf8 you will need to convert before this ' + 'option is removed. This option is only relevant if ' + 'your database engine is MySQL.')) +] + CONF = cfg.CONF +CONF.register_opts(manager_opts) CONF.import_group("database", "glance.openstack.common.db.options") @@ -66,6 +81,15 @@ class DbCommands(object): def __init__(self): pass + def _need_sanity_check(self): + if not CONF.db_enforce_mysql_charset: + LOG.warning(_('Warning: ' + 'The db_enforce_mysql_charset option is now ' + 'deprecated and will be removed in the Juno ' + 'release. Please migrate DB manually e.g. ' + 'convert data of all tables to UTF-8 charset.')) + return CONF.db_enforce_mysql_charset + def version(self): """Print database's current migration level""" print(migration.db_version(db_api.get_engine(), @@ -77,14 +101,16 @@ class DbCommands(object): """Upgrade the database's migration level""" migration.db_sync(db_api.get_engine(), db_migration.MIGRATE_REPO_PATH, - version) + version, + sanity_check=self._need_sanity_check()) @args('--version', metavar='', help='Database version') def downgrade(self, version=None): """Downgrade the database's migration level""" migration.db_sync(db_api.get_engine(), db_migration.MIGRATE_REPO_PATH, - version) + version, + sanity_check=self._need_sanity_check()) @args('--version', metavar='', help='Database version') def version_control(self, version=None): @@ -101,13 +127,14 @@ class DbCommands(object): Place a database under migration control and upgrade/downgrade it, creating first if necessary. """ - if current_version is not None: + if current_version not in (None, 'None'): migration.db_version_control(db_api.get_engine(), db_migration.MIGRATE_REPO_PATH, - current_version) + version=current_version) migration.db_sync(db_api.get_engine(), db_migration.MIGRATE_REPO_PATH, - version) + version, + sanity_check=self._need_sanity_check()) class DbLegacyCommands(object): diff --git a/glance/tests/unit/test_manage.py b/glance/tests/unit/test_manage.py index 4336446149..6f11d91028 100644 --- a/glance/tests/unit/test_manage.py +++ b/glance/tests/unit/test_manage.py @@ -32,16 +32,17 @@ class TestManageBase(testtools.TestCase): def clear_conf(): manage.CONF.reset() manage.CONF.unregister_opt(manage.command_opt) + manage.CONF.db_enforce_mysql_charset = True self.addCleanup(clear_conf) self.patcher = mock.patch('glance.db.sqlalchemy.api.get_engine') self.patcher.start() self.addCleanup(self.patcher.stop) - def _main_test_helper(self, argv, func_name=None, *exp_args): + def _main_test_helper(self, argv, func_name=None, *exp_args, **exp_kwargs): self.useFixture(fixtures.MonkeyPatch('sys.argv', argv)) manage.main() - func_name.assert_called_once_with(*exp_args) + func_name.assert_called_once_with(*exp_args, **exp_kwargs) class TestLegacyManage(TestManageBase): @@ -60,14 +61,16 @@ class TestLegacyManage(TestManageBase): glance.openstack.common.db.sqlalchemy. migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, None) + db_migration.MIGRATE_REPO_PATH, None, + sanity_check=True) def test_legacy_db_upgrade(self): migration.db_sync = mock.Mock() self._main_test_helper(['glance.cmd.manage', 'db_upgrade'], migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, None) + db_migration.MIGRATE_REPO_PATH, None, + sanity_check=True) def test_legacy_db_version_control(self): migration.db_version_control = mock.Mock() @@ -81,21 +84,51 @@ class TestLegacyManage(TestManageBase): self._main_test_helper(['glance.cmd.manage', 'db_sync', '20'], migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, '20') + db_migration.MIGRATE_REPO_PATH, '20', + sanity_check=True) def test_legacy_db_upgrade_version(self): migration.db_sync = mock.Mock() self._main_test_helper(['glance.cmd.manage', 'db_upgrade', '20'], migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, '20') + db_migration.MIGRATE_REPO_PATH, '20', + sanity_check=True) def test_legacy_db_downgrade_version(self): migration.db_sync = mock.Mock() self._main_test_helper(['glance.cmd.manage', 'db_downgrade', '20'], migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, '20') + db_migration.MIGRATE_REPO_PATH, '20', + sanity_check=True) + + def test_legacy_db_sync_version_without_sanity_check(self): + migration.db_sync = mock.Mock() + manage.CONF.db_enforce_mysql_charset = False + self._main_test_helper(['glance.cmd.manage', 'db_sync', '20'], + migration.db_sync, + db_api.get_engine(), + db_migration.MIGRATE_REPO_PATH, '20', + sanity_check=False) + + def test_legacy_db_upgrade_version_without_sanity_check(self): + migration.db_sync = mock.Mock() + manage.CONF.db_enforce_mysql_charset = False + self._main_test_helper(['glance.cmd.manage', 'db_upgrade', '40'], + migration.db_sync, + db_api.get_engine(), + db_migration.MIGRATE_REPO_PATH, '40', + sanity_check=False) + + def test_legacy_db_downgrade_version_without_sanity_check(self): + migration.db_sync = mock.Mock() + manage.CONF.db_enforce_mysql_charset = False + self._main_test_helper(['glance.cmd.manage', 'db_downgrade', '20'], + migration.db_sync, + db_api.get_engine(), + db_migration.MIGRATE_REPO_PATH, '20', + sanity_check=False) class TestManage(TestManageBase): @@ -112,14 +145,16 @@ class TestManage(TestManageBase): self._main_test_helper(['glance.cmd.manage', 'db', 'sync'], migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, None) + db_migration.MIGRATE_REPO_PATH, None, + sanity_check=True) def test_db_upgrade(self): migration.db_sync = mock.Mock() self._main_test_helper(['glance.cmd.manage', 'db', 'upgrade'], migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, None) + db_migration.MIGRATE_REPO_PATH, None, + sanity_check=True) def test_db_version_control(self): migration.db_version_control = mock.Mock() @@ -133,18 +168,48 @@ class TestManage(TestManageBase): self._main_test_helper(['glance.cmd.manage', 'db', 'sync', '20'], migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, u'20') + db_migration.MIGRATE_REPO_PATH, '20', + sanity_check=True) def test_db_upgrade_version(self): migration.db_sync = mock.Mock() self._main_test_helper(['glance.cmd.manage', 'db', 'upgrade', '20'], migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, '20') + db_migration.MIGRATE_REPO_PATH, '20', + sanity_check=True) def test_db_downgrade_version(self): migration.db_sync = mock.Mock() self._main_test_helper(['glance.cmd.manage', 'db', 'downgrade', '20'], migration.db_sync, db_api.get_engine(), - db_migration.MIGRATE_REPO_PATH, '20') + db_migration.MIGRATE_REPO_PATH, '20', + sanity_check=True) + + def test_db_sync_version_without_sanity_check(self): + migration.db_sync = mock.Mock() + manage.CONF.db_enforce_mysql_charset = False + self._main_test_helper(['glance.cmd.manage', 'db', 'sync', '20'], + migration.db_sync, + db_api.get_engine(), + db_migration.MIGRATE_REPO_PATH, u'20', + sanity_check=False) + + def test_db_upgrade_version_without_sanity_check(self): + migration.db_sync = mock.Mock() + manage.CONF.db_enforce_mysql_charset = False + self._main_test_helper(['glance.cmd.manage', 'db', 'upgrade', '40'], + migration.db_sync, + db_api.get_engine(), + db_migration.MIGRATE_REPO_PATH, '40', + sanity_check=False) + + def test_db_downgrade_version_without_sanity_check(self): + migration.db_sync = mock.Mock() + manage.CONF.db_enforce_mysql_charset = False + self._main_test_helper(['glance.cmd.manage', 'db', 'downgrade', '20'], + migration.db_sync, + db_api.get_engine(), + db_migration.MIGRATE_REPO_PATH, '20', + sanity_check=False)