From 402b3abf990d08d2af8331079d36a92d84d84b80 Mon Sep 17 00:00:00 2001 From: Nicolas Simonds Date: Wed, 10 Jun 2015 11:59:11 -0700 Subject: [PATCH] Use utf8_bin collation on the flavor extra-specs table in MySQL On the MySQL backend, change the collation type on flavor extra-specs to be utf8_bin, i.e., case-sensitive. Other backends (e.g., SQLite) are case-sensitive, and the code around extra-spec duplicate detection assumes this is universally true. This author is of the opinion that treating what is essentially user-input as case-sensitive is a good idea, so assume the code is correct, and fix the database. TrivialFix Change-Id: I64f1cc1b5c604085f879a25cbbd47c04b05e096d Closes-Bug: 1463948 --- .../298_mysql_extra_specs_binary_collation.py | 20 +++++++++++++++++++ nova/db/sqlalchemy/models.py | 1 + nova/tests/unit/db/test_migrations.py | 5 +++++ 3 files changed, 26 insertions(+) create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/298_mysql_extra_specs_binary_collation.py diff --git a/nova/db/sqlalchemy/migrate_repo/versions/298_mysql_extra_specs_binary_collation.py b/nova/db/sqlalchemy/migrate_repo/versions/298_mysql_extra_specs_binary_collation.py new file mode 100644 index 000000000000..4db7207bf678 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/298_mysql_extra_specs_binary_collation.py @@ -0,0 +1,20 @@ +# Copyright 2015 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +def upgrade(migrate_engine): + if migrate_engine.name == "mysql": + migrate_engine.execute("ALTER TABLE instance_type_extra_specs " + "CONVERT TO CHARACTER SET utf8 " + "COLLATE utf8_bin;") diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 8a3012243f24..29c7dc2e18e3 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -1022,6 +1022,7 @@ class InstanceTypeExtraSpecs(BASE, NovaBase): name=("uniq_instance_type_extra_specs0" "instance_type_id0key0deleted") ), + {'mysql_collate': 'utf8_bin'}, ) id = Column(Integer, primary_key=True) key = Column(String(255)) diff --git a/nova/tests/unit/db/test_migrations.py b/nova/tests/unit/db/test_migrations.py index 4475c2668a52..8fc057c20414 100644 --- a/nova/tests/unit/db/test_migrations.py +++ b/nova/tests/unit/db/test_migrations.py @@ -761,6 +761,11 @@ class NovaMigrationsCheckers(test_migrations.ModelsMigrationsSync, def _check_297(self, engine, data): self.assertColumnExists(engine, 'services', 'forced_down') + def _check_298(self, engine, data): + # NOTE(nic): This is a MySQL-specific migration, and is a no-op from + # the point-of-view of unit tests, since they use SQLite + pass + class TestNovaMigrationsSQLite(NovaMigrationsCheckers, test_base.DbTestCase,