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 618b47627d
)
This commit is contained in:
parent
237bfcfd82
commit
83396b3254
|
@ -11,6 +11,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_db import exception as db_exc
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from nova.api.openstack.placement import db_api
|
from nova.api.openstack.placement import db_api
|
||||||
|
@ -104,7 +105,7 @@ class CreateIncompleteConsumersTestCase(base.TestCase):
|
||||||
self.ctx = self.context
|
self.ctx = self.context
|
||||||
|
|
||||||
@db_api.placement_context_manager.writer
|
@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
|
# Create some allocations with consumers that don't exist in the
|
||||||
# consumers table to represent old allocations that we expect to be
|
# consumers table to represent old allocations that we expect to be
|
||||||
# "cleaned up" with consumers table records that point to the sentinel
|
# "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
|
c2_missing_uuid = uuids.c2_missing
|
||||||
c3_missing_uuid = uuids.c3_missing
|
c3_missing_uuid = uuids.c3_missing
|
||||||
for c_uuid in (c1_missing_uuid, c2_missing_uuid, c3_missing_uuid):
|
for c_uuid in (c1_missing_uuid, c2_missing_uuid, c3_missing_uuid):
|
||||||
ins_stmt = ALLOC_TBL.insert().values(
|
# Create $num_of_consumer_allocs allocations per consumer with
|
||||||
resource_provider_id=1, resource_class_id=0,
|
# different resource classes.
|
||||||
consumer_id=c_uuid, used=1)
|
for resource_class_id in range(num_of_consumer_allocs):
|
||||||
ctx.session.execute(ins_stmt)
|
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
|
# Verify there are no records in the projects/users table
|
||||||
project_count = ctx.session.scalar(
|
project_count = ctx.session.scalar(
|
||||||
sa.select([sa.func.count('*')]).select_from(PROJECT_TBL))
|
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)
|
res = consumer_obj.create_incomplete_consumers(self.ctx, 10)
|
||||||
self.assertEqual((0, 0), res)
|
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):
|
class DeleteConsumerIfNoAllocsTestCase(tb.PlacementDbBaseTestCase):
|
||||||
def test_delete_consumer_if_no_allocs(self):
|
def test_delete_consumer_if_no_allocs(self):
|
||||||
|
|
Loading…
Reference in New Issue