From 642caf0c58ed0a0e0c06103d2e3ef001c1ae142f Mon Sep 17 00:00:00 2001 From: melanie witt Date: Fri, 17 Feb 2017 17:27:57 +0000 Subject: [PATCH] Skip soft-deleted records in 330_enforce_mitaka_online_migrations The 330_enforce_mitaka_online_migrations migration considers soft-deleted records as unmigrated (the blocker migration uses the select function from sqlalchemy), but the online migrations only migrate non-deleted records (the migrations use the model_query function which defaults to read_deleted='no'). So even after running all of the online migrations, operators can get stuck until they can hard delete any soft-deleted compute_nodes, aggregates, and pci_devices records they have. Conflicts: nova/tests/unit/db/test_sqlalchemy_migration.py NOTE(melwitt): The conflict is due to ocata unit tests that don't exist in newton. Closes-Bug: #1665719 Change-Id: I2285005098b7dab7753366f53667ff8d4532d668 (cherry picked from commit 6d64b7274410ae45b95bd7ac7f702c16daaa0fcd) --- .../330_enforce_mitaka_online_migrations.py | 12 +++++---- .../unit/db/test_sqlalchemy_migration.py | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+), 5 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 index 652a0e919a0f..d6a432c81dc6 100644 --- 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 @@ -10,7 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. -from sqlalchemy import MetaData, Table, func, select +from sqlalchemy import MetaData, Table, and_, func, select from nova import exception from nova.i18n import _ @@ -27,8 +27,9 @@ def upgrade(migrate_engine): 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 + count = select([func.count()]).select_from(table).where(and_( + table.c.deleted == 0, + table.c.uuid == None)).execute().scalar() # NOQA if count > 0: msg = WARNING_MSG % { 'count': count, @@ -37,8 +38,9 @@ def upgrade(migrate_engine): 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 + count = select([func.count()]).select_from(pci_devices).where(and_( + pci_devices.c.deleted == 0, + pci_devices.c.parent_addr == None)).execute().scalar() # NOQA if count > 0: msg = WARNING_MSG % { 'count': count, diff --git a/nova/tests/unit/db/test_sqlalchemy_migration.py b/nova/tests/unit/db/test_sqlalchemy_migration.py index 9f2af9d21656..bf344bca199f 100644 --- a/nova/tests/unit/db/test_sqlalchemy_migration.py +++ b/nova/tests/unit/db/test_sqlalchemy_migration.py @@ -280,3 +280,28 @@ class TestNewtonCheck(test.TestCase): 'status': 'whatisthis?'}) self.assertRaises(exception.ValidationError, self.migration.upgrade, self.engine) + + def test_deleted_not_migrated(self): + cn_values = dict(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 = db_api.compute_node_create(self.context, cn_values) + agg_values = dict(name='foo') + agg = db_api.aggregate_create(self.context, agg_values) + pd = 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?'}) + db_api.compute_node_delete(self.context, cn['id']) + db_api.aggregate_delete(self.context, agg['id']) + db_api.pci_device_destroy(self.context, pd['compute_node_id'], + pd['address']) + + # blocker should not block on soft-deleted records + self.migration.upgrade(self.engine)