summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/330_enforce_mitaka_online_migrations.py47
-rw-r--r--nova/tests/unit/db/test_migrations.py4
-rw-r--r--nova/tests/unit/db/test_sqlalchemy_migration.py55
3 files changed, 106 insertions, 0 deletions
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/330_enforce_mitaka_online_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/330_enforce_mitaka_online_migrations.py
new file mode 100644
index 0000000000..652a0e919a
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/330_enforce_mitaka_online_migrations.py
@@ -0,0 +1,47 @@
+# 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 _
+
+
+WARNING_MSG = _('There are still %(count)i unmigrated records in '
+ 'the %(table)s table. Migration cannot continue '
+ 'until all records have been migrated.')
+
+
+def upgrade(migrate_engine):
+ meta = MetaData(migrate_engine)
+ compute_nodes = Table('compute_nodes', meta, autoload=True)
+ aggregates = Table('aggregates', meta, autoload=True)
+
+ for table in (compute_nodes, aggregates):
+ count = select([func.count()]).select_from(table).where(
+ table.c.uuid == None).execute().scalar() # NOQA
+ if count > 0:
+ msg = WARNING_MSG % {
+ 'count': count,
+ 'table': table.name,
+ }
+ raise exception.ValidationError(detail=msg)
+
+ pci_devices = Table('pci_devices', meta, autoload=True)
+ count = select([func.count()]).select_from(pci_devices).where(
+ pci_devices.c.parent_addr == None).execute().scalar() # NOQA
+ if count > 0:
+ msg = WARNING_MSG % {
+ 'count': count,
+ 'table': pci_devices.name,
+ }
+ raise exception.ValidationError(detail=msg)
diff --git a/nova/tests/unit/db/test_migrations.py b/nova/tests/unit/db/test_migrations.py
index 01af1f82f2..782b4b1345 100644
--- a/nova/tests/unit/db/test_migrations.py
+++ b/nova/tests/unit/db/test_migrations.py
@@ -887,6 +887,10 @@ class NovaMigrationsCheckers(test_migrations.ModelsMigrationsSync,
'instances_deleted_created_at_idx',
['deleted', 'created_at'])
+ def _check_330(self, engine, data):
+ # Just a sanity-check migration
+ pass
+
class TestNovaMigrationsSQLite(NovaMigrationsCheckers,
test_base.DbTestCase,
diff --git a/nova/tests/unit/db/test_sqlalchemy_migration.py b/nova/tests/unit/db/test_sqlalchemy_migration.py
index 1e3d761c9b..a4d2aff965 100644
--- a/nova/tests/unit/db/test_sqlalchemy_migration.py
+++ b/nova/tests/unit/db/test_sqlalchemy_migration.py
@@ -28,6 +28,7 @@ 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):
@@ -224,3 +225,57 @@ class TestFlavorCheck(test.TestCase):
inst.create()
inst.destroy()
self.migration.upgrade(self.engine)
+
+
+class TestNewtonCheck(test.TestCase):
+ def setUp(self):
+ super(TestNewtonCheck, self).setUp()
+ self.useFixture(nova_fixtures.DatabaseAtVersion(329))
+ self.context = context.get_admin_context()
+ self.migration = importlib.import_module(
+ 'nova.db.sqlalchemy.migrate_repo.versions.'
+ '330_enforce_mitaka_online_migrations')
+ self.engine = db_api.get_engine()
+
+ def test_all_migrated(self):
+ cn = objects.ComputeNode(context=self.context,
+ vcpus=1, memory_mb=512, local_gb=10,
+ vcpus_used=0, memory_mb_used=256,
+ local_gb_used=5, hypervisor_type='HyperDanVM',
+ hypervisor_version='34', cpu_info='foo')
+ cn.create()
+ objects.Aggregate(context=self.context,
+ name='foo').create()
+ objects.PciDevice.create(self.context, {})
+ self.migration.upgrade(self.engine)
+
+ def test_cn_not_migrated(self):
+ cn = objects.ComputeNode(context=self.context,
+ vcpus=1, memory_mb=512, local_gb=10,
+ vcpus_used=0, memory_mb_used=256,
+ local_gb_used=5, hypervisor_type='HyperDanVM',
+ hypervisor_version='34', cpu_info='foo')
+ cn.create()
+ db_api.compute_node_update(self.context, cn.id, {'uuid': None})
+ self.assertRaises(exception.ValidationError,
+ self.migration.upgrade, self.engine)
+
+ def test_aggregate_not_migrated(self):
+ agg = objects.Aggregate(context=self.context, name='foo')
+ agg.create()
+ db_api.aggregate_update(self.context, agg.id, {'uuid': None})
+ self.assertRaises(exception.ValidationError,
+ self.migration.upgrade, self.engine)
+
+ def test_pci_device_not_migrated(self):
+ db_api.pci_device_update(self.context, 1, 'foo:bar',
+ {'parent_addr': None,
+ 'compute_node_id': 1,
+ 'address': 'foo:bar',
+ 'vendor_id': '123',
+ 'product_id': '456',
+ 'dev_type': 'foo',
+ 'label': 'foobar',
+ 'status': 'whatisthis?'})
+ self.assertRaises(exception.ValidationError,
+ self.migration.upgrade, self.engine)