From 6a89a53c8f5430eb86bff731592ca272fa089c83 Mon Sep 17 00:00:00 2001 From: Wayne Okuma Date: Wed, 8 Oct 2014 08:17:20 -0700 Subject: [PATCH] Metadef schema column name is a reserved word in MySQL The metadef_properties and metadef_objects tables both have a column named schema. Unfortunately, schema is a reserved word in some relational database products, including MySQL and PostgreSQL. The metadef_properties.schema and metadef_objects.schema columns should be renamed to a non reserved word. Change-Id: I9c1b497d2b09b9282a83bd8c19c32edfa4dd159f Closes-Bug: 1378968 --- glance/db/__init__.py | 8 +- glance/db/simple/api.py | 30 ++++--- glance/db/sqlalchemy/metadata.py | 8 +- .../036_rename_metadef_schema_columns.py | 34 ++++++++ glance/db/sqlalchemy/models_metadef.py | 4 +- glance/tests/functional/db/base_metadef.py | 12 +-- glance/tests/unit/test_db_metadef.py | 4 +- glance/tests/unit/test_migrations.py | 84 +++++++++++++++++++ .../tests/unit/v2/test_metadef_resources.py | 4 +- 9 files changed, 152 insertions(+), 36 deletions(-) create mode 100644 glance/db/sqlalchemy/migrate_repo/versions/036_rename_metadef_schema_columns.py diff --git a/glance/db/__init__.py b/glance/db/__init__.py index 0bfd0779ac..0cc5e37be7 100644 --- a/glance/db/__init__.py +++ b/glance/db/__init__.py @@ -507,7 +507,7 @@ class MetadefObjectRepo(object): # Convert the persisted json schema to a dict of PropertyTypes property_types = {} - json_props = metadata_object['schema'] + json_props = metadata_object['json_schema'] for id in json_props: property_types[id] = fromjson(PropertyType, json_props[id]) @@ -539,7 +539,7 @@ class MetadefObjectRepo(object): 'name': metadata_object.name, 'required': required_str, 'description': metadata_object.description, - 'schema': db_schema + 'json_schema': db_schema } return db_metadata_object @@ -694,14 +694,14 @@ class MetadefPropertyRepo(object): namespace=namespace_entity, property_id=property['id'], name=property['name'], - schema=property['schema'] + schema=property['json_schema'] ) def _format_metadef_property_to_db(self, property): db_metadata_object = { 'name': property.name, - 'schema': property.schema + 'json_schema': property.schema } return db_metadata_object diff --git a/glance/db/simple/api.py b/glance/db/simple/api.py index 6c164a3b6e..b045b14b71 100644 --- a/glance/db/simple/api.py +++ b/glance/db/simple/api.py @@ -1101,10 +1101,10 @@ def metadef_namespace_get_by_id(context, namespace_id): namespace = next(namespace for namespace in DATA['metadef_namespaces'] if namespace['id'] == namespace_id) except StopIteration: - msg = "No namespace found with id %s" % namespace_id - LOG.debug(msg) - raise exception.MetadefRecordNotFound( - record_type='namespace', id=namespace_id) + msg = (_("Metadata definition namespace not found for id=%s") + % namespace_id) + LOG.warn(msg) + raise exception.MetadefNamespaceNotFound(msg) if not _is_namespace_visible(context, namespace): msg = ("Forbidding request, metadata definition namespace=%s" @@ -1235,11 +1235,10 @@ def metadef_object_get_by_id(context, namespace_name, object_id): object['id'] == object_id): return object else: - msg = ("No metadata definition object found with id %s" + msg = (_("Metadata definition object not found for id=%s") % object_id) - LOG.debug(msg) - raise exception.MetadefRecordNotFound(record_type='object', - id=object_id) + LOG.warn(msg) + raise exception.MetadefObjectNotFound(msg) @log_call @@ -1266,7 +1265,7 @@ def metadef_object_create(context, namespace_name, values): object_values = copy.deepcopy(values) object_name = object_values['name'] required_attributes = ['name'] - allowed_attributes = ['name', 'description', 'schema', 'required'] + allowed_attributes = ['name', 'description', 'json_schema', 'required'] namespace = metadef_namespace_get(context, namespace_name) @@ -1384,7 +1383,7 @@ def metadef_property_create(context, namespace_name, values): property_values = copy.deepcopy(values) property_name = property_values['name'] required_attributes = ['name'] - allowed_attributes = ['name', 'description', 'schema', 'required'] + allowed_attributes = ['name', 'description', 'json_schema', 'required'] namespace = metadef_namespace_get(context, namespace_name) @@ -1485,11 +1484,10 @@ def metadef_property_get_by_id(context, namespace_name, property_id): property['id'] == property_id): return property else: - msg = ("No metadata definition property found with id=%s" + msg = (_("Metadata definition property not found for id=%s") % property_id) - LOG.debug(msg) - raise exception.MetadefRecordNotFound(record_type='property', - id=property_id) + LOG.warn(msg) + raise exception.MetadefPropertyNotFound(msg) @log_call @@ -1692,7 +1690,7 @@ def _format_property(values): 'id': _get_metadef_id(), 'namespace_id': None, 'name': None, - 'schema': None + 'json_schema': None } property.update(values) return property @@ -1722,7 +1720,7 @@ def _format_object(values): 'namespace_id': None, 'name': None, 'description': None, - 'schema': None, + 'json_schema': None, 'required': None, 'created_at': dt, 'updated_at': dt diff --git a/glance/db/sqlalchemy/metadata.py b/glance/db/sqlalchemy/metadata.py index b31c3913b0..accfac4651 100644 --- a/glance/db/sqlalchemy/metadata.py +++ b/glance/db/sqlalchemy/metadata.py @@ -200,7 +200,7 @@ def _populate_metadata(meta, metadata_path=None): values = { 'name': property, 'namespace_id': namespace_id, - 'schema': json.dumps(schema), + 'json_schema': json.dumps(schema), 'created_at': timeutils.utcnow() } _insert_data_to_db(metadef_properties_table, values) @@ -210,7 +210,7 @@ def _populate_metadata(meta, metadata_path=None): 'name': object.get('name', None), 'description': object.get('description', None), 'namespace_id': namespace_id, - 'schema': json.dumps(object.get('properties', None)), + 'json_schema': json.dumps(object.get('properties', None)), 'created_at': timeutils.utcnow() } _insert_data_to_db(metadef_objects_table, values) @@ -287,7 +287,7 @@ def _export_data_to_file(meta, path): objects.append({ "name": object['name'], "description": object['description'], - "properties": json.loads(object['schema']) + "properties": json.loads(object['json_schema']) }) values.update({ 'objects': objects @@ -296,7 +296,7 @@ def _export_data_to_file(meta, path): properties = {} for property in db_properties: properties.update({ - property['name']: json.loads(property['schema']) + property['name']: json.loads(property['json_schema']) }) values.update({ 'properties': properties diff --git a/glance/db/sqlalchemy/migrate_repo/versions/036_rename_metadef_schema_columns.py b/glance/db/sqlalchemy/migrate_repo/versions/036_rename_metadef_schema_columns.py new file mode 100644 index 0000000000..ad62f2c565 --- /dev/null +++ b/glance/db/sqlalchemy/migrate_repo/versions/036_rename_metadef_schema_columns.py @@ -0,0 +1,34 @@ +# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# +# 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. + +from sqlalchemy.schema import MetaData +from sqlalchemy.schema import Table + + +def upgrade(migrate_engine): + meta = MetaData(bind=migrate_engine) + metadef_objects = Table('metadef_objects', meta, autoload=True) + metadef_objects.c.schema.alter(name='json_schema') + + metadef_properties = Table('metadef_properties', meta, autoload=True) + metadef_properties.c.schema.alter(name='json_schema') + + +def downgrade(migrate_engine): + meta = MetaData(bind=migrate_engine) + metadef_objects = Table('metadef_objects', meta, autoload=True) + metadef_objects.c.json_schema.alter(name='schema') + + metadef_properties = Table('metadef_properties', meta, autoload=True) + metadef_properties.c.json_schema.alter(name='schema') diff --git a/glance/db/sqlalchemy/models_metadef.py b/glance/db/sqlalchemy/models_metadef.py index ced963d85f..6a3ce3504b 100644 --- a/glance/db/sqlalchemy/models_metadef.py +++ b/glance/db/sqlalchemy/models_metadef.py @@ -89,7 +89,7 @@ class MetadefObject(BASE_DICT, GlanceMetadefBase): name = Column(String(80), nullable=False) description = Column(Text()) required = Column(Text()) - schema = Column(JSONEncodedDict(), default={}) + json_schema = Column(JSONEncodedDict(), default={}) class MetadefProperty(BASE_DICT, GlanceMetadefBase): @@ -103,7 +103,7 @@ class MetadefProperty(BASE_DICT, GlanceMetadefBase): namespace_id = Column(Integer(), ForeignKey('metadef_namespaces.id'), nullable=False) name = Column(String(80), nullable=False) - schema = Column(JSONEncodedDict(), default={}) + json_schema = Column(JSONEncodedDict(), default={}) class MetadefNamespaceResourceType(BASE_DICT, GlanceMetadefBase): diff --git a/glance/tests/functional/db/base_metadef.py b/glance/tests/functional/db/base_metadef.py index 00fd700e70..85bb90200d 100644 --- a/glance/tests/functional/db/base_metadef.py +++ b/glance/tests/functional/db/base_metadef.py @@ -60,7 +60,7 @@ def build_object_fixture(**kwargs): 'name': u'test-object-name', 'description': u'test-object-description', 'required': u'fake-required-properties-list', - 'schema': u'{fake-schema}' + 'json_schema': u'{fake-schema}' } object.update(kwargs) return object @@ -71,7 +71,7 @@ def build_property_fixture(**kwargs): property = { 'namespace_id': 1, 'name': u'test-property-name', - 'schema': u'{fake-schema}' + 'json_schema': u'{fake-schema}' } property.update(kwargs) return property @@ -244,7 +244,7 @@ class MetadefPropertyTests(object): self.assertEqual(len(found), 2) def test_property_update(self): - delta = {'name': u'New-name', 'schema': u'new-schema'} + delta = {'name': u'New-name', 'json_schema': u'new-schema'} fixture_ns = build_namespace_fixture() created_ns = self.db_api.metadef_namespace_create( @@ -263,7 +263,7 @@ class MetadefPropertyTests(object): self.context, created_ns['namespace'], created_prop['id'], delta_dict) self.assertEqual(delta['name'], updated['name']) - self.assertEqual(delta['schema'], updated['schema']) + self.assertEqual(delta['json_schema'], updated['json_schema']) def test_property_delete(self): fixture_ns = build_namespace_fixture() @@ -354,7 +354,7 @@ class MetadefObjectTests(object): self.assertEqual(len(found), 2) def test_object_update(self): - delta = {'name': u'New-name', 'schema': u'new-schema', + delta = {'name': u'New-name', 'json_schema': u'new-schema', 'required': u'new-required'} fixture_ns = build_namespace_fixture() @@ -374,7 +374,7 @@ class MetadefObjectTests(object): self.context, created_ns['namespace'], created_object['id'], delta_dict) self.assertEqual(delta['name'], updated['name']) - self.assertEqual(delta['schema'], updated['schema']) + self.assertEqual(delta['json_schema'], updated['json_schema']) def test_object_delete(self): fixture_ns = build_namespace_fixture() diff --git a/glance/tests/unit/test_db_metadef.py b/glance/tests/unit/test_db_metadef.py index 81226aaf68..f4f4dd171e 100644 --- a/glance/tests/unit/test_db_metadef.py +++ b/glance/tests/unit/test_db_metadef.py @@ -62,7 +62,7 @@ def _db_namespace_fixture(**kwargs): def _db_property_fixture(name, **kwargs): property = { 'name': name, - 'schema': {"type": "string", "title": "title"}, + 'json_schema': {"type": "string", "title": "title"}, } property.update(kwargs) return property @@ -72,7 +72,7 @@ def _db_object_fixture(name, **kwargs): obj = { 'name': name, 'description': None, - 'schema': {}, + 'json_schema': {}, 'required': '[]', } obj.update(kwargs) diff --git a/glance/tests/unit/test_migrations.py b/glance/tests/unit/test_migrations.py index a79a12166e..b905857f2e 100644 --- a/glance/tests/unit/test_migrations.py +++ b/glance/tests/unit/test_migrations.py @@ -1132,6 +1132,90 @@ class MigrationsMixin(test_migrations.WalkVersionsMixin): db_utils.get_table, engine, 'metadef_namespace_resource_types') + def _pre_upgrade_036(self, engine): + meta = sqlalchemy.MetaData() + meta.bind = engine + + # metadef_objects + table = sqlalchemy.Table("metadef_objects", meta, autoload=True) + expected_cols = [u'id', + u'namespace_id', + u'name', + u'description', + u'required', + u'schema', + u'created_at', + u'updated_at'] + col_data = [col.name for col in table.columns] + self.assertEqual(expected_cols, col_data) + + # metadef_properties + table = sqlalchemy.Table("metadef_properties", meta, autoload=True) + expected_cols = [u'id', + u'namespace_id', + u'name', + u'schema', + u'created_at', + u'updated_at'] + col_data = [col.name for col in table.columns] + self.assertEqual(expected_cols, col_data) + + def _check_036(self, engine, data): + meta = sqlalchemy.MetaData() + meta.bind = engine + + # metadef_objects + table = sqlalchemy.Table("metadef_objects", meta, autoload=True) + expected_cols = [u'id', + u'namespace_id', + u'name', + u'description', + u'required', + u'json_schema', + u'created_at', + u'updated_at'] + col_data = [col.name for col in table.columns] + self.assertEqual(expected_cols, col_data) + + # metadef_properties + table = sqlalchemy.Table("metadef_properties", meta, autoload=True) + expected_cols = [u'id', + u'namespace_id', + u'name', + u'json_schema', + u'created_at', + u'updated_at'] + col_data = [col.name for col in table.columns] + self.assertEqual(expected_cols, col_data) + + def _post_downgrade_036(self, engine): + meta = sqlalchemy.MetaData() + meta.bind = engine + + # metadef_objects + table = sqlalchemy.Table("metadef_objects", meta, autoload=True) + expected_cols = [u'id', + u'namespace_id', + u'name', + u'description', + u'required', + u'schema', + u'created_at', + u'updated_at'] + col_data = [col.name for col in table.columns] + self.assertEqual(expected_cols, col_data) + + # metadef_properties + table = sqlalchemy.Table("metadef_properties", meta, autoload=True) + expected_cols = [u'id', + u'namespace_id', + u'name', + u'schema', + u'created_at', + u'updated_at'] + col_data = [col.name for col in table.columns] + self.assertEqual(expected_cols, col_data) + class TestMysqlMigrations(test_base.MySQLOpportunisticTestCase, MigrationsMixin): diff --git a/glance/tests/unit/v2/test_metadef_resources.py b/glance/tests/unit/v2/test_metadef_resources.py index 9334fe239b..c695f0bae2 100644 --- a/glance/tests/unit/v2/test_metadef_resources.py +++ b/glance/tests/unit/v2/test_metadef_resources.py @@ -73,7 +73,7 @@ def _db_namespace_fixture(namespace, **kwargs): def _db_property_fixture(name, **kwargs): obj = { 'name': name, - 'schema': {"type": "string", "title": "title"}, + 'json_schema': {"type": "string", "title": "title"}, } obj.update(kwargs) return obj @@ -83,7 +83,7 @@ def _db_object_fixture(name, **kwargs): obj = { 'name': name, 'description': None, - 'schema': {}, + 'json_schema': {}, 'required': '[]', } obj.update(kwargs)