apidb: Compact Rocky database migrations

Specific changes include:

- Add 'disabled' column to 'cell_mappings' table (058)
- Add 'generation' column to 'consumers' table (059)
- Add 'rules' column to 'instance_group_policy' table (060)
- Add 'queued_for_delete' column to 'instance_mappings' table (061)

Note that we need to explicitly disable constraints for 'Boolean' fields
sqlalchemy since these weren't added by sqlachemy-migrate.

Change-Id: Id1c970c3d52c7cc672d00cb0486bfe49d69531b7
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2020-10-23 11:36:13 +01:00
parent 86b423f9f3
commit 6665bd8cb9
12 changed files with 15 additions and 257 deletions

View File

@ -1,22 +0,0 @@
# 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.
# This is a placeholder for backports.
# Do not use this number for new work. New work starts after
# all the placeholders.
#
# See this for more information:
# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
def upgrade(migrate_engine):
pass

View File

@ -1,22 +0,0 @@
# 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.
# This is a placeholder for backports.
# Do not use this number for new work. New work starts after
# all the placeholders.
#
# See this for more information:
# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
def upgrade(migrate_engine):
pass

View File

@ -1,22 +0,0 @@
# 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.
# This is a placeholder for backports.
# Do not use this number for new work. New work starts after
# all the placeholders.
#
# See this for more information:
# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
def upgrade(migrate_engine):
pass

View File

@ -1,22 +0,0 @@
# 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.
# This is a placeholder for backports.
# Do not use this number for new work. New work starts after
# all the placeholders.
#
# See this for more information:
# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
def upgrade(migrate_engine):
pass

View File

@ -1,22 +0,0 @@
# 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.
# This is a placeholder for backports.
# Do not use this number for new work. New work starts after
# all the placeholders.
#
# See this for more information:
# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
def upgrade(migrate_engine):
pass

View File

@ -1,26 +0,0 @@
# 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 import Boolean
from sqlalchemy import Column
from sqlalchemy import MetaData
from sqlalchemy import Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
cell_mappings = Table('cell_mappings', meta, autoload=True)
if not hasattr(cell_mappings.c, 'disabled'):
cell_mappings.create_column(Column('disabled', Boolean, default=False))

View File

@ -1,29 +0,0 @@
# 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 import Column
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import Table
from sqlalchemy import text
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
consumers = Table("consumers", meta, autoload=True)
if not hasattr(consumers.c, "generation"):
# This is adding a column to an existing table, so the server_default
# bit will make existing rows 0 for that column.
consumers.create_column(Column("generation", Integer, default=0,
server_default=text("0"), nullable=False))

View File

@ -1,26 +0,0 @@
# 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 import Column
from sqlalchemy import MetaData
from sqlalchemy import Table
from sqlalchemy import Text
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
policies = Table('instance_group_policy', meta, autoload=True)
if not hasattr(policies.c, 'rules'):
policies.create_column(Column('rules', Text))

View File

@ -1,27 +0,0 @@
# 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 import Boolean
from sqlalchemy import Column
from sqlalchemy import MetaData
from sqlalchemy import Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
instance_mappings = Table('instance_mappings', meta, autoload=True)
if not hasattr(instance_mappings.c, 'queued_for_delete'):
instance_mappings.create_column(Column('queued_for_delete', Boolean,
default=False))

View File

@ -25,6 +25,7 @@ from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy import Text
from sqlalchemy import text
from sqlalchemy import Unicode
from nova.db.sqlalchemy.api_models import MediumText
@ -49,6 +50,9 @@ def upgrade(migrate_engine):
Column('name', String(length=255)),
Column('transport_url', Text()),
Column('database_connection', Text()),
# NOTE(stephenfin): These were originally added by sqlalchemy-migrate
# which did not generate the constraints
Column('disabled', Boolean(create_constraint=False), default=False),
UniqueConstraint('uuid', name='uniq_cell_mappings0uuid'),
Index('uuid_idx', 'uuid'),
mysql_engine='InnoDB',
@ -77,6 +81,11 @@ def upgrade(migrate_engine):
Column('instance_uuid', String(length=36), nullable=False),
Column('cell_id', Integer, nullable=True),
Column('project_id', String(length=255), nullable=False),
# NOTE(stephenfin): These were originally added by sqlalchemy-migrate
# which did not generate the constraints
Column(
'queued_for_delete', Boolean(create_constraint=False),
default=False),
UniqueConstraint(
'instance_uuid', name='uniq_instance_mappings0instance_uuid'),
Index('instance_uuid_idx', 'instance_uuid'),
@ -336,6 +345,9 @@ def upgrade(migrate_engine):
Column('uuid', String(length=36), nullable=False),
Column('project_id', Integer, nullable=False),
Column('user_id', Integer, nullable=False),
Column(
'generation', Integer, default=0, server_default=text('0'),
nullable=False),
Index('consumers_project_id_uuid_idx', 'project_id', 'uuid'),
Index(
'consumers_project_id_user_id_uuid_idx', 'project_id', 'user_id',
@ -453,6 +465,7 @@ def upgrade(migrate_engine):
Column(
'group_id', Integer, ForeignKey('instance_groups.id'),
nullable=False),
Column('rules', Text),
Index('instance_group_policy_policy_idx', 'policy'),
mysql_engine='InnoDB',
mysql_charset='utf8',

View File

@ -30,7 +30,7 @@ from nova.i18n import _
INIT_VERSION = {}
INIT_VERSION['main'] = 401
INIT_VERSION['api'] = 51
INIT_VERSION['api'] = 60
_REPOSITORY = {}
LOG = logging.getLogger(__name__)

View File

@ -45,7 +45,6 @@ from nova.db.sqlalchemy.api_migrations import migrate_repo
from nova.db.sqlalchemy import api_models
from nova.db.sqlalchemy import migration as sa_migration
from nova import test
from nova.test import uuids
from nova.tests import fixtures as nova_fixtures
@ -171,7 +170,6 @@ class NovaAPIMigrationsWalk(test_migrations.WalkVersionsMixin):
return self.engine
def _skippable_migrations(self):
queens_placeholders = list(range(53, 58))
# We forgot to add the rocky placeholders
stein_placeholders = list(range(63, 68))
train_placeholders = list(range(68, 73))
@ -180,8 +178,7 @@ class NovaAPIMigrationsWalk(test_migrations.WalkVersionsMixin):
special_cases = [
self.INIT_VERSION + 1, # initial change
]
return (queens_placeholders +
stein_placeholders +
return (stein_placeholders +
train_placeholders +
ussuri_placeholders +
victoria_placeholders +
@ -218,40 +215,6 @@ class NovaAPIMigrationsWalk(test_migrations.WalkVersionsMixin):
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
db_utils.get_table, engine, table_name)
def _check_058(self, engine, data):
self.assertColumnExists(engine, 'cell_mappings', 'disabled')
def _pre_upgrade_059(self, engine):
# Add a fake consumers table record to verify that generation is
# added with a default value of 0.
projects = db_utils.get_table(engine, 'projects')
project_id = projects.insert().execute(
dict(external_id=uuids.project_external_id)
).inserted_primary_key[0]
users = db_utils.get_table(engine, 'users')
user_id = users.insert().execute(
dict(external_id=uuids.user_external_id)
).inserted_primary_key[0]
consumers = db_utils.get_table(engine, 'consumers')
fake_consumer = dict(
uuid=uuids.consumer_uuid, project_id=project_id, user_id=user_id)
consumers.insert().execute(fake_consumer)
def _check_059(self, engine, data):
self.assertColumnExists(engine, "consumers", "generation")
# Assert we have one existing entry and it's generation value is 0.
consumers = db_utils.get_table(engine, 'consumers')
result = consumers.select().execute().fetchall()
self.assertEqual(1, len(result))
self.assertEqual(0, result[0]['generation'])
def _check_060(self, engine, data):
self.assertColumnExists(engine, 'instance_group_policy', 'rules')
def _check_061(self, engine, data):
self.assertColumnExists(engine, 'instance_mappings',
'queued_for_delete')
def _check_062(self, engine, data):
self.assertColumnExists(engine, 'instance_mappings', 'user_id')
self.assertIndexExists(engine, 'instance_mappings',