Require cellsv2 setup before migrating to Ocata
We have code going into Ocata that needs to be sure that cell and host mappings are in place. Since this was required homework in Newton, we can land a migration to intentionally fail if this was not completed. This is, however, a little difficult to require because a first-time deployment will be initialized schema-wise with none of these records, which is also sane. So, we look to see if any flavors are defined as a sentinel to indicate that this is an upgrade of an existing deployment instead of a first-time event. Not perfect, but since this is really just a helper for the user, it seems like a reasonable risk. Depends-On: If1af9c478e8ea2420f2523a9bb8b70fafddc86b7 Change-Id: I72fb724dc13e1a5f4e97c58915b538ba761c582d
This commit is contained in:
parent
6d53334946
commit
ff6b9998bb
@ -0,0 +1,57 @@
|
||||
# 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, Table, func, select
|
||||
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import objects
|
||||
|
||||
|
||||
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 db 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 db 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:
|
||||
msg = _('No host mappings were found, but are required for Ocata. '
|
||||
'Please run nova-manage db simple_cell_setup before '
|
||||
'continuing.')
|
||||
raise exception.ValidationError(detail=msg)
|
@ -164,7 +164,10 @@ class NovaAPIMigrationsWalk(test_migrations.WalkVersionsMixin):
|
||||
def _skippable_migrations(self):
|
||||
mitaka_placeholders = range(8, 13)
|
||||
newton_placeholders = range(21, 26)
|
||||
return mitaka_placeholders + newton_placeholders
|
||||
special_cases = [
|
||||
30, # Enforcement migration, no changes to test
|
||||
]
|
||||
return mitaka_placeholders + newton_placeholders + special_cases
|
||||
|
||||
def migrate_up(self, version, with_data=False):
|
||||
if with_data:
|
||||
|
@ -365,3 +365,103 @@ class TestOcataCheck(test.TestCase):
|
||||
group = db_api.instance_group_create(self.context, self.ig_values)
|
||||
db_api.instance_group_delete(self.context, group['uuid'])
|
||||
self.migration.upgrade(self.engine)
|
||||
|
||||
|
||||
class TestNewtonCellsCheck(test.NoDBTestCase):
|
||||
USES_DB_SELF = True
|
||||
|
||||
def setUp(self):
|
||||
super(TestNewtonCellsCheck, self).setUp()
|
||||
self.useFixture(nova_fixtures.DatabaseAtVersion(28, 'api'))
|
||||
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()
|
||||
|
||||
@mock.patch('nova.objects.Flavor._ensure_migrated')
|
||||
def _flavor_me(self, _):
|
||||
flavor = objects.Flavor(context=self.context,
|
||||
name='foo', memory_mb=123,
|
||||
vcpus=1, root_gb=1,
|
||||
flavorid='m1.foo')
|
||||
flavor.create()
|
||||
|
||||
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()
|
||||
cell0 = objects.CellMapping(context=self.context,
|
||||
uuid=objects.CellMapping.CELL0_UUID,
|
||||
name='cell0',
|
||||
transport_url='fake',
|
||||
database_connection='fake')
|
||||
cell0.create()
|
||||
self.assertRaisesRegex(exception.ValidationError,
|
||||
'Cell mappings',
|
||||
self.migration.upgrade, self.engine)
|
||||
|
||||
def test_upgrade_without_cell0(self):
|
||||
self._flavor_me()
|
||||
cell1 = objects.CellMapping(context=self.context,
|
||||
uuid=uuidsentinel.cell1,
|
||||
name='cell1',
|
||||
transport_url='fake',
|
||||
database_connection='fake')
|
||||
cell1.create()
|
||||
cell2 = objects.CellMapping(context=self.context,
|
||||
uuid=uuidsentinel.cell2,
|
||||
name='cell2',
|
||||
transport_url='fake',
|
||||
database_connection='fake')
|
||||
cell2.create()
|
||||
self.assertRaisesRegex(exception.ValidationError,
|
||||
'Cell0',
|
||||
self.migration.upgrade, self.engine)
|
||||
|
||||
def test_upgrade_with_no_host_mappings(self):
|
||||
self._flavor_me()
|
||||
cell0 = objects.CellMapping(context=self.context,
|
||||
uuid=objects.CellMapping.CELL0_UUID,
|
||||
name='cell0',
|
||||
transport_url='fake',
|
||||
database_connection='fake')
|
||||
cell0.create()
|
||||
cell1 = objects.CellMapping(context=self.context,
|
||||
uuid=uuidsentinel.cell1,
|
||||
name='cell1',
|
||||
transport_url='fake',
|
||||
database_connection='fake')
|
||||
cell1.create()
|
||||
|
||||
self.assertRaisesRegex(exception.ValidationError,
|
||||
'host mappings',
|
||||
self.migration.upgrade, self.engine)
|
||||
|
||||
def test_upgrade_with_required_mappings(self):
|
||||
self._flavor_me()
|
||||
cell0 = objects.CellMapping(context=self.context,
|
||||
uuid=objects.CellMapping.CELL0_UUID,
|
||||
name='cell0',
|
||||
transport_url='fake',
|
||||
database_connection='fake')
|
||||
cell0.create()
|
||||
cell1 = objects.CellMapping(context=self.context,
|
||||
uuid=uuidsentinel.cell1,
|
||||
name='cell1',
|
||||
transport_url='fake',
|
||||
database_connection='fake')
|
||||
cell1.create()
|
||||
hostmapping = objects.HostMapping(context=self.context,
|
||||
cell_mapping=cell1,
|
||||
host='foo')
|
||||
hostmapping.create()
|
||||
|
||||
self.migration.upgrade(self.engine)
|
||||
|
||||
def test_upgrade_new_deploy(self):
|
||||
self.migration.upgrade(self.engine)
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
upgrade:
|
||||
- Ocata requires that your deployment have created the
|
||||
cell and host mappings in Newton. If you have not done
|
||||
this, Ocata's `db sync` command will fail. Small deployments
|
||||
will want to run `nova-manage db simple_cell_setup`
|
||||
on Newton before upgrading.
|
Loading…
Reference in New Issue
Block a user