From 83396b325428332bd51c57f89599cf4cc074c7fb Mon Sep 17 00:00:00 2001 From: Matt Riedemann Date: Tue, 16 Oct 2018 13:47:05 -0400 Subject: [PATCH] Add recreate test for bug 1798163 Change Icae5038190ab8c7bbdb38d54ae909fcbf9048912 in Rocky attempts to online migrate missing consumers table records when listing allocations for a given resource provider. The problem is when it's doing an insert-from-select, it's not handling multiple allocations on the same provider for the same consumer, like you'd have with a compute instance that has VCPU, MEMORY_MB and DISK_GB allocations against a single compute node resource provider. As a result, the insert statement has duplicate consumer IDs in it which results in a unique constraint violation. The existing tests never caught this because they tested with 3 unique consumers with a single allocation each. The functional test added here hits both online data migration routines: via the API when listing allocations for a resource provider and the direct online data migration CLI. Conflicts: nova/tests/functional/api/openstack/placement/db/test_consumer.py NOTE(mriedem): The conflict was due to not having change I7f5f08691ca3f73073c66c29dddb996fb2c2b266 in Rocky. Change-Id: Iba56aa6b227b6455d2437e4fabcd296b1b0f06ee Related-Bug: #1798163 (cherry picked from commit 618b47627d8dc4f071032e3e63c530d3fe199b39) --- .../openstack/placement/db/test_consumer.py | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/nova/tests/functional/api/openstack/placement/db/test_consumer.py b/nova/tests/functional/api/openstack/placement/db/test_consumer.py index 9fe2f2493d19..9055b650a5e2 100644 --- a/nova/tests/functional/api/openstack/placement/db/test_consumer.py +++ b/nova/tests/functional/api/openstack/placement/db/test_consumer.py @@ -11,6 +11,7 @@ # under the License. from oslo_config import cfg +from oslo_db import exception as db_exc import sqlalchemy as sa from nova.api.openstack.placement import db_api @@ -104,7 +105,7 @@ class CreateIncompleteConsumersTestCase(base.TestCase): self.ctx = self.context @db_api.placement_context_manager.writer - def _create_incomplete_allocations(self, ctx): + def _create_incomplete_allocations(self, ctx, num_of_consumer_allocs=1): # Create some allocations with consumers that don't exist in the # consumers table to represent old allocations that we expect to be # "cleaned up" with consumers table records that point to the sentinel @@ -113,10 +114,14 @@ class CreateIncompleteConsumersTestCase(base.TestCase): c2_missing_uuid = uuids.c2_missing c3_missing_uuid = uuids.c3_missing for c_uuid in (c1_missing_uuid, c2_missing_uuid, c3_missing_uuid): - ins_stmt = ALLOC_TBL.insert().values( - resource_provider_id=1, resource_class_id=0, - consumer_id=c_uuid, used=1) - ctx.session.execute(ins_stmt) + # Create $num_of_consumer_allocs allocations per consumer with + # different resource classes. + for resource_class_id in range(num_of_consumer_allocs): + ins_stmt = ALLOC_TBL.insert().values( + resource_provider_id=1, + resource_class_id=resource_class_id, + consumer_id=c_uuid, used=1) + ctx.session.execute(ins_stmt) # Verify there are no records in the projects/users table project_count = ctx.session.scalar( sa.select([sa.func.count('*')]).select_from(PROJECT_TBL)) @@ -216,6 +221,31 @@ class CreateIncompleteConsumersTestCase(base.TestCase): res = consumer_obj.create_incomplete_consumers(self.ctx, 10) self.assertEqual((0, 0), res) + def test_create_incomplete_consumers_multiple_allocs_per_consumer(self): + """Tests that missing consumer records are created when listing + allocations against a resource provider or running the online data + migration routine when the consumers have multiple allocations on the + same provider. + """ + self._create_incomplete_allocations(self.ctx, num_of_consumer_allocs=2) + # Run the online data migration to migrate one consumer. The batch size + # needs to be large enough to hit more than one consumer for this test + # where each consumer has two allocations. + # FIXME(mriedem): This should not raise a UniqueConstraint error once + # bug 1798163 is fixed. + # res = consumer_obj.create_incomplete_consumers(self.ctx, 2) + # self.assertEqual((2, 2), res) + self.assertRaises(db_exc.DBDuplicateEntry, + consumer_obj.create_incomplete_consumers, + self.ctx, 2) + # Migrate the rest by listing allocations on the resource provider. + rp1 = rp_obj.ResourceProvider(self.ctx, id=1) + # FIXME(mriedem): This should not raise a UniqueConstraint error once + # bug 1798163 is fixed. + self.assertRaises(db_exc.DBDuplicateEntry, + rp_obj.AllocationList.get_all_by_resource_provider, + self.ctx, rp1) + class DeleteConsumerIfNoAllocsTestCase(tb.PlacementDbBaseTestCase): def test_delete_consumer_if_no_allocs(self):