Merge "[placement] Allow _set_allocations to delete allocations"
This commit is contained in:
commit
25ecb01963
|
@ -1666,7 +1666,7 @@ def _check_capacity_exceeded(conn, allocs):
|
|||
resource_provider=rp_uuid)
|
||||
if rp_uuid not in res_providers:
|
||||
res_providers[rp_uuid] = alloc.resource_provider
|
||||
return list(res_providers.values())
|
||||
return res_providers
|
||||
|
||||
|
||||
def _ensure_lookup_table_entry(conn, tbl, external_id):
|
||||
|
@ -1799,12 +1799,31 @@ class AllocationList(base.ObjectListBase, base.NovaObject):
|
|||
for alloc in allocs:
|
||||
consumer_id = alloc.consumer_id
|
||||
_delete_allocations_for_consumer(context, consumer_id)
|
||||
# If there are any allocations with string resource class names
|
||||
# that don't exist this will raise a ResourceClassNotFound
|
||||
# exception.
|
||||
before_gens = _check_capacity_exceeded(conn, allocs)
|
||||
# Don't check capacity when alloc.used is zero. Zero is not a
|
||||
# valid amount when making an allocation (the minimum consumption
|
||||
# of a resource is one) but is used in this method to indicate a
|
||||
# need for removal. Providing 0 is controlled at the HTTP API layer
|
||||
# where PUT /allocations does not allow empty allocations. When
|
||||
# POST /allocations is implemented it will for the special case of
|
||||
# atomically setting and removing different allocations in the same
|
||||
# request. _check_capacity_exceeded will raise a
|
||||
# ResourceClassNotFound # if any allocation is using a resource
|
||||
# class that does not exist.
|
||||
visited_rps = _check_capacity_exceeded(conn,
|
||||
[alloc for alloc in
|
||||
allocs if alloc.used > 0])
|
||||
seen_consumers = set()
|
||||
for alloc in allocs:
|
||||
# If alloc.used is set to zero that is a signal that we don't
|
||||
# want to (re-)create any allocations for this resource class.
|
||||
# _delete_current_allocs has already wiped out allocations so
|
||||
# all that's being done here is adding the resource provider
|
||||
# to visited_rps so its generation will be checked at the end
|
||||
# of the transaction.
|
||||
if alloc.used == 0:
|
||||
rp = alloc.resource_provider
|
||||
visited_rps[rp.uuid] = rp
|
||||
continue
|
||||
consumer_id = alloc.consumer_id
|
||||
# Only set consumer <-> project/user association if we
|
||||
# haven't set it already.
|
||||
|
@ -1826,7 +1845,7 @@ class AllocationList(base.ObjectListBase, base.NovaObject):
|
|||
# this will raise a ConcurrentUpdateDetected which can be caught
|
||||
# by the caller to choose to try again. It will also rollback the
|
||||
# transaction so that these changes always happen atomically.
|
||||
for rp in before_gens:
|
||||
for rp in visited_rps.values():
|
||||
rp.generation = _increment_provider_generation(conn, rp)
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -1173,8 +1173,8 @@ class TestAllocationListCreateDelete(ResourceProviderBaseCase):
|
|||
|
||||
def _make_rp_and_inventory(self, **kwargs):
|
||||
# Create one resource provider and set some inventory
|
||||
rp_name = uuidsentinel.rp_name
|
||||
rp_uuid = uuidsentinel.rp_uuid
|
||||
rp_name = kwargs.get('rp_name') or uuidsentinel.rp_name
|
||||
rp_uuid = kwargs.get('rp_uuid') or uuidsentinel.rp_uuid
|
||||
rp = rp_obj.ResourceProvider(
|
||||
self.ctx, name=rp_name, uuid=rp_uuid)
|
||||
rp.create()
|
||||
|
@ -1314,6 +1314,134 @@ class TestAllocationListCreateDelete(ResourceProviderBaseCase):
|
|||
self.assertEqual(1, len(usage_list))
|
||||
self.assertEqual(200, usage_list[0].usage)
|
||||
|
||||
def test_create_and_clear(self):
|
||||
"""Test that a used of 0 in an allocation wipes allocations."""
|
||||
consumer_uuid = uuidsentinel.consumer
|
||||
rp_class = fields.ResourceClass.DISK_GB
|
||||
target_rp = self._make_rp_and_inventory(resource_class=rp_class,
|
||||
max_unit=500)
|
||||
|
||||
# Create two allocations with values and confirm the resulting
|
||||
# usage is as expected.
|
||||
allocation1 = rp_obj.Allocation(resource_provider=target_rp,
|
||||
consumer_id=consumer_uuid,
|
||||
resource_class=rp_class,
|
||||
project_id=self.ctx.project_id,
|
||||
user_id=self.ctx.user_id,
|
||||
used=100)
|
||||
allocation2 = rp_obj.Allocation(resource_provider=target_rp,
|
||||
consumer_id=consumer_uuid,
|
||||
resource_class=rp_class,
|
||||
project_id=self.ctx.project_id,
|
||||
user_id=self.ctx.user_id,
|
||||
used=200)
|
||||
allocation_list = rp_obj.AllocationList(
|
||||
self.ctx,
|
||||
objects=[allocation1, allocation2],
|
||||
)
|
||||
allocation_list.create_all()
|
||||
|
||||
allocations = rp_obj.AllocationList.get_all_by_consumer_id(
|
||||
self.ctx, consumer_uuid)
|
||||
self.assertEqual(2, len(allocations))
|
||||
usage = sum(alloc.used for alloc in allocations)
|
||||
self.assertEqual(300, usage)
|
||||
|
||||
# Create two allocations, one with 0 used, to confirm the
|
||||
# resulting usage is only of one.
|
||||
allocation1 = rp_obj.Allocation(resource_provider=target_rp,
|
||||
consumer_id=consumer_uuid,
|
||||
resource_class=rp_class,
|
||||
project_id=self.ctx.project_id,
|
||||
user_id=self.ctx.user_id,
|
||||
used=0)
|
||||
allocation2 = rp_obj.Allocation(resource_provider=target_rp,
|
||||
consumer_id=consumer_uuid,
|
||||
resource_class=rp_class,
|
||||
project_id=self.ctx.project_id,
|
||||
user_id=self.ctx.user_id,
|
||||
used=200)
|
||||
allocation_list = rp_obj.AllocationList(
|
||||
self.ctx,
|
||||
objects=[allocation1, allocation2],
|
||||
)
|
||||
allocation_list.create_all()
|
||||
|
||||
allocations = rp_obj.AllocationList.get_all_by_consumer_id(
|
||||
self.ctx, consumer_uuid)
|
||||
self.assertEqual(1, len(allocations))
|
||||
usage = allocations[0].used
|
||||
self.assertEqual(200, usage)
|
||||
|
||||
# add a source rp and a migration consumer
|
||||
migration_uuid = uuidsentinel.migration
|
||||
source_rp = self._make_rp_and_inventory(
|
||||
rp_name=uuidsentinel.source_name, rp_uuid=uuidsentinel.source_uuid,
|
||||
resource_class=rp_class, max_unit=500)
|
||||
|
||||
# Create two allocations, one as the consumer, one as the
|
||||
# migration.
|
||||
allocation1 = rp_obj.Allocation(resource_provider=target_rp,
|
||||
consumer_id=consumer_uuid,
|
||||
resource_class=rp_class,
|
||||
project_id=self.ctx.project_id,
|
||||
user_id=self.ctx.user_id,
|
||||
used=200)
|
||||
allocation2 = rp_obj.Allocation(resource_provider=source_rp,
|
||||
consumer_id=migration_uuid,
|
||||
resource_class=rp_class,
|
||||
project_id=self.ctx.project_id,
|
||||
user_id=self.ctx.user_id,
|
||||
used=200)
|
||||
allocation_list = rp_obj.AllocationList(
|
||||
self.ctx,
|
||||
objects=[allocation1, allocation2],
|
||||
)
|
||||
allocation_list.create_all()
|
||||
|
||||
# Check primary consumer allocations.
|
||||
allocations = rp_obj.AllocationList.get_all_by_consumer_id(
|
||||
self.ctx, consumer_uuid)
|
||||
self.assertEqual(1, len(allocations))
|
||||
usage = allocations[0].used
|
||||
self.assertEqual(200, usage)
|
||||
|
||||
# Check migration allocations.
|
||||
allocations = rp_obj.AllocationList.get_all_by_consumer_id(
|
||||
self.ctx, migration_uuid)
|
||||
self.assertEqual(1, len(allocations))
|
||||
usage = allocations[0].used
|
||||
self.assertEqual(200, usage)
|
||||
|
||||
# Clear the migration and confirm the target.
|
||||
allocation1 = rp_obj.Allocation(resource_provider=target_rp,
|
||||
consumer_id=consumer_uuid,
|
||||
resource_class=rp_class,
|
||||
project_id=self.ctx.project_id,
|
||||
user_id=self.ctx.user_id,
|
||||
used=200)
|
||||
allocation2 = rp_obj.Allocation(resource_provider=source_rp,
|
||||
consumer_id=migration_uuid,
|
||||
resource_class=rp_class,
|
||||
project_id=self.ctx.project_id,
|
||||
user_id=self.ctx.user_id,
|
||||
used=0)
|
||||
allocation_list = rp_obj.AllocationList(
|
||||
self.ctx,
|
||||
objects=[allocation1, allocation2],
|
||||
)
|
||||
allocation_list.create_all()
|
||||
|
||||
allocations = rp_obj.AllocationList.get_all_by_consumer_id(
|
||||
self.ctx, consumer_uuid)
|
||||
self.assertEqual(1, len(allocations))
|
||||
usage = allocations[0].used
|
||||
self.assertEqual(200, usage)
|
||||
|
||||
allocations = rp_obj.AllocationList.get_all_by_consumer_id(
|
||||
self.ctx, migration_uuid)
|
||||
self.assertEqual(0, len(allocations))
|
||||
|
||||
|
||||
class UsageListTestCase(ResourceProviderBaseCase):
|
||||
|
||||
|
|
Loading…
Reference in New Issue