From d80c23f40978fdf0e92a141da85ca9a7ed77efc2 Mon Sep 17 00:00:00 2001 From: Crag Wolfe Date: Sun, 28 Aug 2016 01:54:50 -0400 Subject: [PATCH] Add resource_properties_data data migration Prepare for the future when both resources and events refer to properties data in this table, rather than storing duplicate copies. Change-Id: Idb7ed0ddd76d2780993a677114f8e10ccce56862 --- .../versions/079_resource_properties_data.py | 55 +++++++++++++++++++ heat/db/sqlalchemy/models.py | 20 +++++++ heat/tests/db/test_migrations.py | 23 ++++++++ 3 files changed, 98 insertions(+) create mode 100644 heat/db/sqlalchemy/migrate_repo/versions/079_resource_properties_data.py diff --git a/heat/db/sqlalchemy/migrate_repo/versions/079_resource_properties_data.py b/heat/db/sqlalchemy/migrate_repo/versions/079_resource_properties_data.py new file mode 100644 index 0000000000..5744506549 --- /dev/null +++ b/heat/db/sqlalchemy/migrate_repo/versions/079_resource_properties_data.py @@ -0,0 +1,55 @@ +# +# 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 migrate.changeset import constraint +import sqlalchemy + +from heat.db.sqlalchemy import types + + +def upgrade(migrate_engine): + meta = sqlalchemy.MetaData(bind=migrate_engine) + + resource_properties_data = sqlalchemy.Table( + 'resource_properties_data', meta, + sqlalchemy.Column('id', sqlalchemy.Integer, + primary_key=True, + nullable=False), + sqlalchemy.Column('data', types.Json), + sqlalchemy.Column('encrypted', sqlalchemy.Boolean), + sqlalchemy.Column('created_at', sqlalchemy.DateTime), + sqlalchemy.Column('updated_at', sqlalchemy.DateTime), + mysql_engine='InnoDB', + mysql_charset='utf8' + ) + resource_properties_data.create() + + resource = sqlalchemy.Table('resource', meta, autoload=True) + rsrc_prop_data_id = sqlalchemy.Column('rsrc_prop_data_id', + sqlalchemy.Integer) + rsrc_prop_data_id.create(resource) + res_fkey = constraint.ForeignKeyConstraint( + columns=[resource.c.rsrc_prop_data_id], + refcolumns=[resource_properties_data.c.id], + name='rsrc_rsrc_prop_data_ref') + res_fkey.create() + + event = sqlalchemy.Table('event', meta, autoload=True) + rsrc_prop_data_id = sqlalchemy.Column('rsrc_prop_data_id', + sqlalchemy.Integer) + rsrc_prop_data_id.create(event) + ev_fkey = constraint.ForeignKeyConstraint( + columns=[event.c.rsrc_prop_data_id], + refcolumns=[resource_properties_data.c.id], + name='ev_rsrc_prop_data_ref') + ev_fkey.create() diff --git a/heat/db/sqlalchemy/models.py b/heat/db/sqlalchemy/models.py index 411455e7c8..a9a5fd126f 100644 --- a/heat/db/sqlalchemy/models.py +++ b/heat/db/sqlalchemy/models.py @@ -183,6 +183,16 @@ class UserCreds(BASE, HeatBase): cascade_backrefs=False) +class ResourcePropertiesData(BASE, HeatBase): + """Represents resource properties data, current or older""" + + __tablename__ = 'resource_properties_data' + + id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) + data = sqlalchemy.Column('data', types.Json) + encrypted = sqlalchemy.Column('encrypted', sqlalchemy.Boolean) + + class Event(BASE, HeatBase): """Represents an event generated by the heat engine.""" @@ -204,6 +214,11 @@ class Event(BASE, HeatBase): _resource_status_reason = sqlalchemy.Column( 'resource_status_reason', sqlalchemy.String(255)) resource_type = sqlalchemy.Column(sqlalchemy.String(255)) + rsrc_prop_data_id = sqlalchemy.Column(sqlalchemy.Integer, + sqlalchemy.ForeignKey( + 'resource_properties_data.id')) + rsrc_prop_data = relationship(ResourcePropertiesData, + backref=backref('event')) resource_properties = sqlalchemy.Column(sqlalchemy.PickleType) @property @@ -259,6 +274,11 @@ class Resource(BASE, HeatBase, StateAware): cascade="all", passive_deletes=True, backref=backref('resource')) + rsrc_prop_data_id = sqlalchemy.Column(sqlalchemy.Integer, + sqlalchemy.ForeignKey( + 'resource_properties_data.id')) + rsrc_prop_data = relationship(ResourcePropertiesData, + backref=backref('resource')) # Override timestamp column to store the correct value: it should be the # time the create/update call was issued, not the time the DB entry is diff --git a/heat/tests/db/test_migrations.py b/heat/tests/db/test_migrations.py index d037c6b122..d90c85d203 100644 --- a/heat/tests/db/test_migrations.py +++ b/heat/tests/db/test_migrations.py @@ -710,6 +710,29 @@ class HeatMigrationsCheckers(test_migrations.WalkVersionsMixin, self.assertEqual('resource', fk['referred_table']) self.assertEqual(['id'], fk['referred_columns']) + def _check_079(self, engine, data): + self.assertColumnExists(engine, 'resource', + 'rsrc_prop_data_id') + self.assertColumnExists(engine, 'event', + 'rsrc_prop_data_id') + column_list = [('id', False), + ('data', True), + ('encrypted', True), + ('updated_at', True), + ('created_at', True)] + + for column in column_list: + self.assertColumnExists(engine, + 'resource_properties_data', column[0]) + if not column[1]: + self.assertColumnIsNotNullable(engine, + 'resource_properties_data', + column[0]) + else: + self.assertColumnIsNullable(engine, + 'resource_properties_data', + column[0]) + class TestHeatMigrationsMySQL(HeatMigrationsCheckers, test_base.MySQLOpportunisticTestCase):