apidb: Compact Ocata database migrations

Specific changes include:

- Add 'resource_classes' table (026)
- Add 'quota_classes', 'quota_usages', 'quotas', 'project_user_quotas',
  'reservations' and 'resource_classes' tables (027)
- Alter type of 'instance' column of 'build_requests' table to
  'MediumText' (028)
- Add 'placement_aggregates' table (029)

Note that migration 030 included a check to ensure cell mappings were
created when upgrading existing deployments. Since users will now be
required to upgrade to at Ocata before running migrations, this is no
longer necessary. The check was never executed for new deployments,
as noted in the migration itself:

  NOTE(danms): We need to be careful here if this is a new
  installation, which can't possibly have any mappings. Check
  to see if any flavors are defined to determine if we are
  upgrading an existing system. If not, then don't obsess over
  the lack of mappings.

Change-Id: Ibf82b5e8f46b89f8c7dcdc1925bf48d581cdc3f6
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2020-10-22 15:56:56 +01:00
parent 302f2bc4f7
commit 743693c740
14 changed files with 111 additions and 615 deletions

View File

@ -1,23 +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,23 +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,23 +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,23 +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,23 +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,36 +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 migrate import UniqueConstraint
from sqlalchemy import Column
from sqlalchemy import DateTime
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
resource_classes = Table('resource_classes', meta,
Column('id', Integer, primary_key=True, nullable=False),
Column('name', String(length=255), nullable=False),
Column('created_at', DateTime),
Column('updated_at', DateTime),
UniqueConstraint('name', name='uniq_resource_classes0name'),
mysql_engine='InnoDB',
mysql_charset='latin1'
)
resource_classes.create(checkfirst=True)

View File

@ -1,124 +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.
"""API Database migrations for quotas"""
from migrate import UniqueConstraint
from sqlalchemy import Column
from sqlalchemy import DateTime
from sqlalchemy import ForeignKey
from sqlalchemy import Index
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
quota_classes = Table('quota_classes', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('class_name', String(length=255)),
Column('resource', String(length=255)),
Column('hard_limit', Integer),
Index('quota_classes_class_name_idx', 'class_name'),
mysql_engine='InnoDB',
mysql_charset='utf8'
)
quota_classes.create(checkfirst=True)
quota_usages = Table('quota_usages', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('project_id', String(length=255)),
Column('resource', String(length=255), nullable=False),
Column('in_use', Integer, nullable=False),
Column('reserved', Integer, nullable=False),
Column('until_refresh', Integer),
Column('user_id', String(length=255)),
Index('quota_usages_project_id_idx', 'project_id'),
Index('quota_usages_user_id_idx', 'user_id'),
mysql_engine='InnoDB',
mysql_charset='utf8'
)
quota_usages.create(checkfirst=True)
quotas = Table('quotas', meta,
Column('id', Integer, primary_key=True, nullable=False),
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('project_id', String(length=255)),
Column('resource', String(length=255), nullable=False),
Column('hard_limit', Integer),
UniqueConstraint('project_id', 'resource',
name='uniq_quotas0project_id0resource'),
mysql_engine='InnoDB',
mysql_charset='utf8'
)
quotas.create(checkfirst=True)
uniq_name = "uniq_project_user_quotas0user_id0project_id0resource"
project_user_quotas = Table('project_user_quotas', meta,
Column('id', Integer, primary_key=True,
nullable=False),
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('user_id',
String(length=255),
nullable=False),
Column('project_id',
String(length=255),
nullable=False),
Column('resource',
String(length=255),
nullable=False),
Column('hard_limit', Integer, nullable=True),
UniqueConstraint('user_id', 'project_id', 'resource',
name=uniq_name),
Index('project_user_quotas_project_id_idx',
'project_id'),
Index('project_user_quotas_user_id_idx',
'user_id'),
mysql_engine='InnoDB',
mysql_charset='utf8',
)
project_user_quotas.create(checkfirst=True)
reservations = Table('reservations', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('uuid', String(length=36), nullable=False),
Column('usage_id', Integer, ForeignKey('quota_usages.id'),
nullable=False),
Column('project_id', String(length=255)),
Column('resource', String(length=255)),
Column('delta', Integer, nullable=False),
Column('expire', DateTime),
Column('user_id', String(length=255)),
Index('reservations_project_id_idx', 'project_id'),
Index('reservations_uuid_idx', 'uuid'),
Index('reservations_expire_idx', 'expire'),
Index('reservations_user_id_idx', 'user_id'),
mysql_engine='InnoDB',
mysql_charset='utf8'
)
reservations.create(checkfirst=True)

View File

@ -1,24 +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 MetaData
from sqlalchemy import Table
from nova.db.sqlalchemy import api_models
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
build_requests = Table('build_requests', meta, autoload=True)
build_requests.c.instance.alter(type=api_models.MediumText())

View File

@ -1,37 +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.
"""API Database migrations for placement_aggregates"""
from migrate import UniqueConstraint
from sqlalchemy import Column
from sqlalchemy import DateTime
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
placement_aggregates = Table('placement_aggregates', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('uuid', String(length=36), index=True),
UniqueConstraint('uuid', name='uniq_placement_aggregates0uuid'),
mysql_engine='InnoDB',
mysql_charset='latin1'
)
placement_aggregates.create(checkfirst=True)

View File

@ -174,7 +174,7 @@ def upgrade(migrate_engine):
'locked_by',
Enum('owner', 'admin', name='build_requests0locked_by')),
Column('instance_uuid', String(length=36)),
Column('instance', Text()),
Column('instance', MediumText()),
Column('block_device_mappings', MediumText()),
UniqueConstraint(
'instance_uuid', name='uniq_build_requests0instance_uuid'),
@ -201,6 +201,16 @@ def upgrade(migrate_engine):
mysql_charset='utf8'
)
resource_classes = Table('resource_classes', meta,
Column('id', Integer, primary_key=True, nullable=False),
Column('name', String(length=255), nullable=False),
Column('created_at', DateTime),
Column('updated_at', DateTime),
UniqueConstraint('name', name='uniq_resource_classes0name'),
mysql_engine='InnoDB',
mysql_charset='latin1'
)
nameargs = {}
if migrate_engine.name == 'mysql':
nameargs['collation'] = 'utf8_bin'
@ -281,6 +291,16 @@ def upgrade(migrate_engine):
mysql_charset='latin1'
)
placement_aggregates = Table('placement_aggregates', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('uuid', String(length=36), index=True),
UniqueConstraint('uuid', name='uniq_placement_aggregates0uuid'),
mysql_engine='InnoDB',
mysql_charset='latin1'
)
aggregates = Table('aggregates', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
@ -365,6 +385,87 @@ def upgrade(migrate_engine):
mysql_charset='utf8',
)
quota_classes = Table('quota_classes', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('class_name', String(length=255)),
Column('resource', String(length=255)),
Column('hard_limit', Integer),
Index('quota_classes_class_name_idx', 'class_name'),
mysql_engine='InnoDB',
mysql_charset='utf8',
)
quota_usages = Table('quota_usages', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('project_id', String(length=255)),
Column('resource', String(length=255), nullable=False),
Column('in_use', Integer, nullable=False),
Column('reserved', Integer, nullable=False),
Column('until_refresh', Integer),
Column('user_id', String(length=255)),
Index('quota_usages_project_id_idx', 'project_id'),
Index('quota_usages_user_id_idx', 'user_id'),
mysql_engine='InnoDB',
mysql_charset='utf8',
)
quotas = Table('quotas', meta,
Column('id', Integer, primary_key=True, nullable=False),
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('project_id', String(length=255)),
Column('resource', String(length=255), nullable=False),
Column('hard_limit', Integer),
UniqueConstraint(
'project_id', 'resource', name='uniq_quotas0project_id0resource'),
mysql_engine='InnoDB',
mysql_charset='utf8',
)
project_user_quotas = Table('project_user_quotas', meta,
Column('id', Integer, primary_key=True, nullable=False),
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('user_id', String(length=255), nullable=False),
Column('project_id', String(length=255), nullable=False),
Column('resource', String(length=255), nullable=False),
Column('hard_limit', Integer, nullable=True),
UniqueConstraint(
'user_id', 'project_id', 'resource',
name='uniq_project_user_quotas0user_id0project_id0resource'),
Index(
'project_user_quotas_project_id_idx', 'project_id'),
Index(
'project_user_quotas_user_id_idx', 'user_id'),
mysql_engine='InnoDB',
mysql_charset='utf8',
)
reservations = Table('reservations', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('id', Integer, primary_key=True, nullable=False),
Column('uuid', String(length=36), nullable=False),
Column(
'usage_id', Integer, ForeignKey('quota_usages.id'),
nullable=False),
Column('project_id', String(length=255)),
Column('resource', String(length=255)),
Column('delta', Integer, nullable=False),
Column('expire', DateTime),
Column('user_id', String(length=255)),
Index('reservations_project_id_idx', 'project_id'),
Index('reservations_uuid_idx', 'uuid'),
Index('reservations_expire_idx', 'expire'),
Index('reservations_user_id_idx', 'user_id'),
mysql_engine='InnoDB',
mysql_charset='utf8',
)
tables = [
cell_mappings,
host_mappings,
@ -375,16 +476,23 @@ def upgrade(migrate_engine):
request_specs,
build_requests,
keypairs,
resource_classes,
resource_providers,
inventories,
allocations,
resource_provider_aggregates,
placement_aggregates,
aggregates,
aggregate_hosts,
aggregate_metadata,
groups,
group_policy,
group_member,
quota_classes,
quota_usages,
quotas,
project_user_quotas,
reservations,
]
for table in tables:
table.create(checkfirst=True)

View File

@ -1,59 +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 oslo_log import log as logging
from sqlalchemy import MetaData, Table, func, select
from nova import exception
from nova.i18n import _
from nova import objects
LOG = logging.getLogger(__name__)
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
flavors = Table('flavors', meta, autoload=True)
count = select([func.count()]).select_from(flavors).scalar()
if count == 0:
# NOTE(danms): We need to be careful here if this is a new
# installation, which can't possibly have any mappings. Check
# to see if any flavors are defined to determine if we are
# upgrading an existing system. If not, then don't obsess over
# the lack of mappings
return
cell_mappings = Table('cell_mappings', meta, autoload=True)
count = select([func.count()]).select_from(cell_mappings).scalar()
# Two mappings are required at a minimum, cell0 and your first cell
if count < 2:
msg = _('Cell mappings are not created, but required for Ocata. '
'Please run nova-manage cell_v2 simple_cell_setup before '
'continuing.')
raise exception.ValidationError(detail=msg)
count = select([func.count()]).select_from(cell_mappings).where(
cell_mappings.c.uuid == objects.CellMapping.CELL0_UUID).scalar()
if count != 1:
msg = _('A mapping for Cell0 was not found, but is required for '
'Ocata. Please run nova-manage cell_v2 simple_cell_setup '
'before continuing.')
raise exception.ValidationError(detail=msg)
host_mappings = Table('host_mappings', meta, autoload=True)
count = select([func.count()]).select_from(host_mappings).scalar()
if count == 0:
LOG.warning('No host mappings were found, but are required for Ocata. '
'Please run nova-manage cell_v2 simple_cell_setup before '
'continuing.')

View File

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

View File

@ -172,7 +172,6 @@ class NovaAPIMigrationsWalk(test_migrations.WalkVersionsMixin):
return self.engine
def _skippable_migrations(self):
newton_placeholders = list(range(21, 26))
ocata_placeholders = list(range(31, 41))
pike_placeholders = list(range(45, 50))
queens_placeholders = list(range(53, 58))
@ -183,10 +182,8 @@ class NovaAPIMigrationsWalk(test_migrations.WalkVersionsMixin):
victoria_placeholders = list(range(78, 83))
special_cases = [
self.INIT_VERSION + 1, # initial change
30, # Enforcement migration, no changes to test
]
return (newton_placeholders +
ocata_placeholders +
return (ocata_placeholders +
pike_placeholders +
queens_placeholders +
stein_placeholders +
@ -226,119 +223,6 @@ class NovaAPIMigrationsWalk(test_migrations.WalkVersionsMixin):
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
db_utils.get_table, engine, table_name)
def _check_026(self, engine, data):
self.assertColumnExists(engine, 'resource_classes', 'id')
self.assertColumnExists(engine, 'resource_classes', 'name')
def _check_027(self, engine, data):
# quota_classes
for column in ['created_at',
'updated_at',
'id',
'class_name',
'resource',
'hard_limit']:
self.assertColumnExists(engine, 'quota_classes', column)
self.assertIndexExists(engine, 'quota_classes',
'quota_classes_class_name_idx')
# quota_usages
for column in ['created_at',
'updated_at',
'id',
'project_id',
'resource',
'in_use',
'reserved',
'until_refresh',
'user_id']:
self.assertColumnExists(engine, 'quota_usages', column)
self.assertIndexExists(engine, 'quota_usages',
'quota_usages_project_id_idx')
self.assertIndexExists(engine, 'quota_usages',
'quota_usages_user_id_idx')
# quotas
for column in ['created_at',
'updated_at',
'id',
'project_id',
'resource',
'hard_limit']:
self.assertColumnExists(engine, 'quotas', column)
self.assertUniqueConstraintExists(engine, 'quotas',
['project_id', 'resource'])
# project_user_quotas
for column in ['created_at',
'updated_at',
'id',
'user_id',
'project_id',
'resource',
'hard_limit']:
self.assertColumnExists(engine, 'project_user_quotas', column)
self.assertUniqueConstraintExists(engine, 'project_user_quotas',
['user_id', 'project_id', 'resource'])
self.assertIndexExists(engine, 'project_user_quotas',
'project_user_quotas_project_id_idx')
self.assertIndexExists(engine, 'project_user_quotas',
'project_user_quotas_user_id_idx')
# reservations
for column in ['created_at',
'updated_at',
'id',
'uuid',
'usage_id',
'project_id',
'resource',
'delta',
'expire',
'user_id']:
self.assertColumnExists(engine, 'reservations', column)
self.assertIndexExists(engine, 'reservations',
'reservations_project_id_idx')
self.assertIndexExists(engine, 'reservations',
'reservations_uuid_idx')
self.assertIndexExists(engine, 'reservations',
'reservations_expire_idx')
self.assertIndexExists(engine, 'reservations',
'reservations_user_id_idx')
# Ensure the foreign key still exists
inspector = reflection.Inspector.from_engine(engine)
# There should only be one foreign key here
fk = inspector.get_foreign_keys('reservations')[0]
self.assertEqual('quota_usages', fk['referred_table'])
self.assertEqual(['id'], fk['referred_columns'])
def _pre_upgrade_028(self, engine):
build_requests = db_utils.get_table(engine, 'build_requests')
fake_build_req = {'id': 2021,
'project_id': 'fake_proj_id',
'instance': '{"uuid": "foo", "name": "bar"}'}
build_requests.insert().execute(fake_build_req)
def _check_028(self, engine, data):
build_requests = db_utils.get_table(engine, 'build_requests')
if engine.name == 'mysql':
self.assertIsInstance(build_requests.c.block_device_mappings.type,
sqlalchemy.dialects.mysql.MEDIUMTEXT)
fake_build_req = build_requests.select(
build_requests.c.id == 2021).execute().first()
self.assertEqual('{"uuid": "foo", "name": "bar"}',
fake_build_req.instance)
def _check_029(self, engine, data):
for column in ['created_at', 'updated_at', 'id', 'uuid']:
self.assertColumnExists(engine, 'placement_aggregates', column)
def _check_041(self, engine, data):
self.assertColumnExists(engine, 'traits', 'id')
self.assertUniqueConstraintExists(engine, 'traits', ['name'])

View File

@ -12,23 +12,15 @@
# License for the specific language governing permissions and limitations
# under the License.
import importlib
from migrate import exceptions as versioning_exceptions
from migrate import UniqueConstraint
from migrate.versioning import api as versioning_api
import mock
from oslo_db.sqlalchemy import utils as db_utils
from oslo_utils.fixture import uuidsentinel
import sqlalchemy
from nova import context
from nova.db.sqlalchemy import api as db_api
from nova.db.sqlalchemy import migration
from nova import exception
from nova import objects
from nova import test
from nova.tests import fixtures as nova_fixtures
class TestNullInstanceUuidScanDB(test.TestCase):
@ -229,96 +221,3 @@ class TestGetEngine(test.NoDBTestCase):
engine = migration.get_engine('api')
self.assertEqual('api_engine', engine)
mock_get_engine.assert_called_once_with()
class TestNewtonCellsCheck(test.NoDBTestCase):
USES_DB_SELF = True
def setUp(self):
super(TestNewtonCellsCheck, self).setUp()
self.useFixture(nova_fixtures.Database('api', 28))
self.context = context.get_admin_context()
self.migration = importlib.import_module(
'nova.db.sqlalchemy.api_migrations.migrate_repo.versions.'
'030_require_cell_setup')
self.engine = db_api.get_api_engine()
def _flavor_me(self):
# We can't use the Flavor object or model to create the flavor because
# the model and object have the description field now but at this point
# we have not run the migration schema to add the description column.
flavors = db_utils.get_table(self.engine, 'flavors')
values = dict(name='foo', memory_mb=123,
vcpus=1, root_gb=1,
flavorid='m1.foo', swap=0)
flavors.insert().execute(values)
def _create_cell_mapping(self, **values):
mappings = db_utils.get_table(self.engine, 'cell_mappings')
return mappings.insert().execute(**values).inserted_primary_key[0]
def _create_host_mapping(self, **values):
mappings = db_utils.get_table(self.engine, 'host_mappings')
return mappings.insert().execute(**values).inserted_primary_key[0]
def test_upgrade_with_no_cell_mappings(self):
self._flavor_me()
self.assertRaisesRegex(exception.ValidationError,
'Cell mappings',
self.migration.upgrade, self.engine)
def test_upgrade_with_only_cell0(self):
self._flavor_me()
self._create_cell_mapping(uuid=objects.CellMapping.CELL0_UUID,
name='cell0',
transport_url='fake',
database_connection='fake')
self.assertRaisesRegex(exception.ValidationError,
'Cell mappings',
self.migration.upgrade, self.engine)
def test_upgrade_without_cell0(self):
self._flavor_me()
self._create_cell_mapping(uuid=uuidsentinel.cell1,
name='cell1',
transport_url='fake',
database_connection='fake')
self._create_cell_mapping(uuid=uuidsentinel.cell2,
name='cell2',
transport_url='fake',
database_connection='fake')
self.assertRaisesRegex(exception.ValidationError,
'Cell0',
self.migration.upgrade, self.engine)
def test_upgrade_with_no_host_mappings(self):
self._flavor_me()
self._create_cell_mapping(uuid=objects.CellMapping.CELL0_UUID,
name='cell0',
transport_url='fake',
database_connection='fake')
self._create_cell_mapping(uuid=uuidsentinel.cell1,
name='cell1',
transport_url='fake',
database_connection='fake')
with mock.patch.object(self.migration, 'LOG') as log:
self.migration.upgrade(self.engine)
self.assertTrue(log.warning.called)
def test_upgrade_with_required_mappings(self):
self._flavor_me()
self._create_cell_mapping(uuid=objects.CellMapping.CELL0_UUID,
name='cell0',
transport_url='fake',
database_connection='fake')
cell1_id = self._create_cell_mapping(uuid=uuidsentinel.cell1,
name='cell1',
transport_url='fake',
database_connection='fake')
self._create_host_mapping(cell_id=cell1_id, host='foo')
self.migration.upgrade(self.engine)
def test_upgrade_new_deploy(self):
self.migration.upgrade(self.engine)