Implement ResourceProvider.destroy()
Destroying a resource provider first checks to see if there are existing allocations associated with the provider. If there are a ResourceProviderInUse exception is raised. If there are not, the resource provider and associated inventories are deleted from the database. Change-Id: Icf0874e00bbee23aa805349e08273be09160c0de Partially-Implements: blueprint generic-resource-pools
This commit is contained in:
parent
eb7cdb053a
commit
83bf4bb312
@ -2094,6 +2094,10 @@ class ConcurrentUpdateDetected(NovaException):
|
|||||||
"Please retry your update")
|
"Please retry your update")
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceProviderInUse(NovaException):
|
||||||
|
msg_fmt = _("Resource provider has allocations.")
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedPointerModelRequested(Invalid):
|
class UnsupportedPointerModelRequested(Invalid):
|
||||||
msg_fmt = _("Pointer model '%(model)s' requested is not supported by "
|
msg_fmt = _("Pointer model '%(model)s' requested is not supported by "
|
||||||
"host.")
|
"host.")
|
||||||
|
@ -33,6 +33,23 @@ def _create_rp_in_db(context, updates):
|
|||||||
return db_rp
|
return db_rp
|
||||||
|
|
||||||
|
|
||||||
|
@db_api.api_context_manager.writer
|
||||||
|
def _delete_rp_from_db(context, _id):
|
||||||
|
# Don't delete the resource provider if it has allocations.
|
||||||
|
rp_allocations = context.session.query(models.Allocation).\
|
||||||
|
filter(models.Allocation.resource_provider_id == _id).\
|
||||||
|
count()
|
||||||
|
if rp_allocations:
|
||||||
|
raise exception.ResourceProviderInUse()
|
||||||
|
# Delete any inventory associated with the resource provider
|
||||||
|
context.session.query(models.Inventory).\
|
||||||
|
filter(models.Inventory.resource_provider_id == _id).delete()
|
||||||
|
result = context.session.query(models.ResourceProvider).\
|
||||||
|
filter(models.ResourceProvider.id == _id).delete()
|
||||||
|
if not result:
|
||||||
|
raise exception.NotFound()
|
||||||
|
|
||||||
|
|
||||||
@db_api.api_context_manager.writer
|
@db_api.api_context_manager.writer
|
||||||
def _update_rp_in_db(context, id, updates):
|
def _update_rp_in_db(context, id, updates):
|
||||||
db_rp = context.session.query(models.ResourceProvider).filter_by(
|
db_rp = context.session.query(models.ResourceProvider).filter_by(
|
||||||
@ -248,7 +265,8 @@ def _set_inventory(context, rp, inv_list):
|
|||||||
@base.NovaObjectRegistry.register
|
@base.NovaObjectRegistry.register
|
||||||
class ResourceProvider(base.NovaObject):
|
class ResourceProvider(base.NovaObject):
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
VERSION = '1.0'
|
# Version 1.1: Add destroy()
|
||||||
|
VERSION = '1.1'
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'id': fields.IntegerField(read_only=True),
|
'id': fields.IntegerField(read_only=True),
|
||||||
@ -272,6 +290,10 @@ class ResourceProvider(base.NovaObject):
|
|||||||
db_rp = self._create_in_db(self._context, updates)
|
db_rp = self._create_in_db(self._context, updates)
|
||||||
self._from_db_object(self._context, self, db_rp)
|
self._from_db_object(self._context, self, db_rp)
|
||||||
|
|
||||||
|
@base.remotable
|
||||||
|
def destroy(self):
|
||||||
|
self._delete(self._context, self.id)
|
||||||
|
|
||||||
@base.remotable
|
@base.remotable
|
||||||
def save(self):
|
def save(self):
|
||||||
updates = self.obj_get_changes()
|
updates = self.obj_get_changes()
|
||||||
@ -322,6 +344,10 @@ class ResourceProvider(base.NovaObject):
|
|||||||
def _create_in_db(context, updates):
|
def _create_in_db(context, updates):
|
||||||
return _create_rp_in_db(context, updates)
|
return _create_rp_in_db(context, updates)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _delete(context, id):
|
||||||
|
_delete_rp_from_db(context, id)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _update_in_db(context, id, updates):
|
def _update_in_db(context, id, updates):
|
||||||
return _update_rp_in_db(context, id, updates)
|
return _update_rp_in_db(context, id, updates)
|
||||||
|
@ -51,6 +51,20 @@ class ResourceProviderBaseCase(test.NoDBTestCase):
|
|||||||
self.useFixture(fixtures.Database(database='api'))
|
self.useFixture(fixtures.Database(database='api'))
|
||||||
self.context = context.RequestContext('fake-user', 'fake-project')
|
self.context = context.RequestContext('fake-user', 'fake-project')
|
||||||
|
|
||||||
|
def _make_allocation(self, rp_uuid=None):
|
||||||
|
rp_uuid = rp_uuid or uuidsentinel.allocation_resource_provider
|
||||||
|
db_rp = objects.ResourceProvider(
|
||||||
|
context=self.context,
|
||||||
|
uuid=rp_uuid,
|
||||||
|
name=rp_uuid)
|
||||||
|
db_rp.create()
|
||||||
|
updates = dict(DISK_ALLOCATION,
|
||||||
|
resource_class_id=RESOURCE_CLASS_ID,
|
||||||
|
resource_provider_id=db_rp.id)
|
||||||
|
db_allocation = objects.Allocation._create_in_db(self.context,
|
||||||
|
updates)
|
||||||
|
return db_rp, db_allocation
|
||||||
|
|
||||||
|
|
||||||
class ResourceProviderTestCase(ResourceProviderBaseCase):
|
class ResourceProviderTestCase(ResourceProviderBaseCase):
|
||||||
"""Test resource-provider objects' lifecycles."""
|
"""Test resource-provider objects' lifecycles."""
|
||||||
@ -98,6 +112,47 @@ class ResourceProviderTestCase(ResourceProviderBaseCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual('new-name', retrieved_resource_provider.name)
|
self.assertEqual('new-name', retrieved_resource_provider.name)
|
||||||
|
|
||||||
|
def test_destroy_resource_provider(self):
|
||||||
|
created_resource_provider = objects.ResourceProvider(
|
||||||
|
context=self.context,
|
||||||
|
uuid=uuidsentinel.fake_resource_provider,
|
||||||
|
name=uuidsentinel.fake_resource_name,
|
||||||
|
)
|
||||||
|
created_resource_provider.create()
|
||||||
|
created_resource_provider.destroy()
|
||||||
|
self.assertRaises(exception.NotFound,
|
||||||
|
objects.ResourceProvider.get_by_uuid,
|
||||||
|
self.context,
|
||||||
|
uuidsentinel.fake_resource_provider)
|
||||||
|
self.assertRaises(exception.NotFound,
|
||||||
|
created_resource_provider.destroy)
|
||||||
|
|
||||||
|
def test_destroy_allocated_resource_provider_fails(self):
|
||||||
|
rp, allocation = self._make_allocation()
|
||||||
|
self.assertRaises(exception.ResourceProviderInUse,
|
||||||
|
rp.destroy)
|
||||||
|
|
||||||
|
def test_destroy_resource_provider_destroy_inventory(self):
|
||||||
|
resource_provider = objects.ResourceProvider(
|
||||||
|
context=self.context,
|
||||||
|
uuid=uuidsentinel.fake_resource_provider,
|
||||||
|
name=uuidsentinel.fake_resource_name,
|
||||||
|
)
|
||||||
|
resource_provider.create()
|
||||||
|
disk_inventory = objects.Inventory(
|
||||||
|
context=self.context,
|
||||||
|
resource_provider=resource_provider,
|
||||||
|
**DISK_INVENTORY
|
||||||
|
)
|
||||||
|
disk_inventory.create()
|
||||||
|
inventories = objects.InventoryList.get_all_by_resource_provider_uuid(
|
||||||
|
self.context, resource_provider.uuid)
|
||||||
|
self.assertEqual(1, len(inventories))
|
||||||
|
resource_provider.destroy()
|
||||||
|
inventories = objects.InventoryList.get_all_by_resource_provider_uuid(
|
||||||
|
self.context, resource_provider.uuid)
|
||||||
|
self.assertEqual(0, len(inventories))
|
||||||
|
|
||||||
def test_create_inventory_with_uncreated_provider(self):
|
def test_create_inventory_with_uncreated_provider(self):
|
||||||
resource_provider = objects.ResourceProvider(
|
resource_provider = objects.ResourceProvider(
|
||||||
context=self.context,
|
context=self.context,
|
||||||
@ -338,20 +393,6 @@ class ResourceProviderListTestCase(test.NoDBTestCase):
|
|||||||
|
|
||||||
class TestAllocation(ResourceProviderBaseCase):
|
class TestAllocation(ResourceProviderBaseCase):
|
||||||
|
|
||||||
def _make_allocation(self, rp_uuid=None):
|
|
||||||
rp_uuid = rp_uuid or uuidsentinel.allocation_resource_provider
|
|
||||||
db_rp = objects.ResourceProvider(
|
|
||||||
context=self.context,
|
|
||||||
uuid=rp_uuid,
|
|
||||||
name=rp_uuid)
|
|
||||||
db_rp.create()
|
|
||||||
updates = dict(DISK_ALLOCATION,
|
|
||||||
resource_class_id=RESOURCE_CLASS_ID,
|
|
||||||
resource_provider_id=db_rp.id)
|
|
||||||
db_allocation = objects.Allocation._create_in_db(self.context,
|
|
||||||
updates)
|
|
||||||
return db_rp, db_allocation
|
|
||||||
|
|
||||||
def test_create_list_and_delete_allocation(self):
|
def test_create_list_and_delete_allocation(self):
|
||||||
resource_provider = objects.ResourceProvider(
|
resource_provider = objects.ResourceProvider(
|
||||||
context=self.context,
|
context=self.context,
|
||||||
@ -392,24 +433,24 @@ class TestAllocation(ResourceProviderBaseCase):
|
|||||||
self.assertEqual(0, len(allocations))
|
self.assertEqual(0, len(allocations))
|
||||||
|
|
||||||
def test_destroy(self):
|
def test_destroy(self):
|
||||||
db_rp, db_allocation = self._make_allocation()
|
rp, allocation = self._make_allocation()
|
||||||
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
||||||
self.context, db_rp.uuid)
|
self.context, rp.uuid)
|
||||||
self.assertEqual(1, len(allocations))
|
self.assertEqual(1, len(allocations))
|
||||||
objects.Allocation._destroy(self.context, db_allocation.id)
|
objects.Allocation._destroy(self.context, allocation.id)
|
||||||
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
||||||
self.context, db_rp.uuid)
|
self.context, rp.uuid)
|
||||||
self.assertEqual(0, len(allocations))
|
self.assertEqual(0, len(allocations))
|
||||||
self.assertRaises(exception.NotFound, objects.Allocation._destroy,
|
self.assertRaises(exception.NotFound, objects.Allocation._destroy,
|
||||||
self.context, db_allocation.id)
|
self.context, allocation.id)
|
||||||
|
|
||||||
def test_get_allocations_from_db(self):
|
def test_get_allocations_from_db(self):
|
||||||
db_rp, db_allocation = self._make_allocation()
|
rp, allocation = self._make_allocation()
|
||||||
allocations = objects.AllocationList._get_allocations_from_db(
|
allocations = objects.AllocationList._get_allocations_from_db(
|
||||||
self.context, db_rp.uuid)
|
self.context, rp.uuid)
|
||||||
self.assertEqual(1, len(allocations))
|
self.assertEqual(1, len(allocations))
|
||||||
self.assertEqual(db_rp.id, allocations[0].resource_provider_id)
|
self.assertEqual(rp.id, allocations[0].resource_provider_id)
|
||||||
self.assertEqual(db_allocation.resource_provider_id,
|
self.assertEqual(allocation.resource_provider_id,
|
||||||
allocations[0].resource_provider_id)
|
allocations[0].resource_provider_id)
|
||||||
|
|
||||||
allocations = objects.AllocationList._get_allocations_from_db(
|
allocations = objects.AllocationList._get_allocations_from_db(
|
||||||
@ -417,35 +458,35 @@ class TestAllocation(ResourceProviderBaseCase):
|
|||||||
self.assertEqual(0, len(allocations))
|
self.assertEqual(0, len(allocations))
|
||||||
|
|
||||||
def test_get_all_by_resource_provider(self):
|
def test_get_all_by_resource_provider(self):
|
||||||
db_rp, db_allocation = self._make_allocation()
|
rp, allocation = self._make_allocation()
|
||||||
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
||||||
self.context, db_rp.uuid)
|
self.context, rp.uuid)
|
||||||
self.assertEqual(1, len(allocations))
|
self.assertEqual(1, len(allocations))
|
||||||
self.assertEqual(db_rp.id, allocations[0].resource_provider.id)
|
self.assertEqual(rp.id, allocations[0].resource_provider.id)
|
||||||
self.assertEqual(db_allocation.resource_provider_id,
|
self.assertEqual(allocation.resource_provider_id,
|
||||||
allocations[0].resource_provider.id)
|
allocations[0].resource_provider.id)
|
||||||
|
|
||||||
def test_get_all_multiple_providers(self):
|
def test_get_all_multiple_providers(self):
|
||||||
# This confirms that the join with resource provider is
|
# This confirms that the join with resource provider is
|
||||||
# behaving.
|
# behaving.
|
||||||
db_rp1, db_allocation1 = self._make_allocation(uuidsentinel.rp1)
|
rp1, allocation1 = self._make_allocation(uuidsentinel.rp1)
|
||||||
db_rp2, db_allocation2 = self._make_allocation(uuidsentinel.rp2)
|
rp2, allocation2 = self._make_allocation(uuidsentinel.rp2)
|
||||||
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
||||||
self.context, db_rp1.uuid)
|
self.context, rp1.uuid)
|
||||||
self.assertEqual(1, len(allocations))
|
self.assertEqual(1, len(allocations))
|
||||||
self.assertEqual(db_rp1.id, allocations[0].resource_provider.id)
|
self.assertEqual(rp1.id, allocations[0].resource_provider.id)
|
||||||
self.assertEqual(db_allocation1.resource_provider_id,
|
self.assertEqual(allocation1.resource_provider_id,
|
||||||
allocations[0].resource_provider.id)
|
allocations[0].resource_provider.id)
|
||||||
|
|
||||||
# add more allocations for the first resource provider
|
# add more allocations for the first resource provider
|
||||||
# of the same class
|
# of the same class
|
||||||
updates = dict(consumer_id=uuidsentinel.consumer1,
|
updates = dict(consumer_id=uuidsentinel.consumer1,
|
||||||
resource_class_id=RESOURCE_CLASS_ID,
|
resource_class_id=RESOURCE_CLASS_ID,
|
||||||
resource_provider_id=db_rp1.id,
|
resource_provider_id=rp1.id,
|
||||||
used=2)
|
used=2)
|
||||||
objects.Allocation._create_in_db(self.context, updates)
|
objects.Allocation._create_in_db(self.context, updates)
|
||||||
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
||||||
self.context, db_rp1.uuid)
|
self.context, rp1.uuid)
|
||||||
self.assertEqual(2, len(allocations))
|
self.assertEqual(2, len(allocations))
|
||||||
|
|
||||||
# add more allocations for the first resource provider
|
# add more allocations for the first resource provider
|
||||||
@ -453,18 +494,18 @@ class TestAllocation(ResourceProviderBaseCase):
|
|||||||
updates = dict(consumer_id=uuidsentinel.consumer1,
|
updates = dict(consumer_id=uuidsentinel.consumer1,
|
||||||
resource_class_id=fields.ResourceClass.index(
|
resource_class_id=fields.ResourceClass.index(
|
||||||
fields.ResourceClass.IPV4_ADDRESS),
|
fields.ResourceClass.IPV4_ADDRESS),
|
||||||
resource_provider_id=db_rp1.id,
|
resource_provider_id=rp1.id,
|
||||||
used=4)
|
used=4)
|
||||||
objects.Allocation._create_in_db(self.context, updates)
|
objects.Allocation._create_in_db(self.context, updates)
|
||||||
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
||||||
self.context, db_rp1.uuid)
|
self.context, rp1.uuid)
|
||||||
self.assertEqual(3, len(allocations))
|
self.assertEqual(3, len(allocations))
|
||||||
self.assertEqual(db_rp1.uuid, allocations[0].resource_provider.uuid)
|
self.assertEqual(rp1.uuid, allocations[0].resource_provider.uuid)
|
||||||
|
|
||||||
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
|
||||||
self.context, db_rp2.uuid)
|
self.context, rp2.uuid)
|
||||||
self.assertEqual(1, len(allocations))
|
self.assertEqual(1, len(allocations))
|
||||||
self.assertEqual(db_rp2.uuid, allocations[0].resource_provider.uuid)
|
self.assertEqual(rp2.uuid, allocations[0].resource_provider.uuid)
|
||||||
self.assertIn(RESOURCE_CLASS,
|
self.assertIn(RESOURCE_CLASS,
|
||||||
[allocation.resource_class
|
[allocation.resource_class
|
||||||
for allocation in allocations])
|
for allocation in allocations])
|
||||||
|
@ -1180,7 +1180,7 @@ object_data = {
|
|||||||
'Quotas': '1.2-1fe4cd50593aaf5d36a6dc5ab3f98fb3',
|
'Quotas': '1.2-1fe4cd50593aaf5d36a6dc5ab3f98fb3',
|
||||||
'QuotasNoOp': '1.2-e041ddeb7dc8188ca71706f78aad41c1',
|
'QuotasNoOp': '1.2-e041ddeb7dc8188ca71706f78aad41c1',
|
||||||
'RequestSpec': '1.6-c1cb516acdf120d367a42d343ed695b5',
|
'RequestSpec': '1.6-c1cb516acdf120d367a42d343ed695b5',
|
||||||
'ResourceProvider': '1.0-421c968ee9b2341dd78b0c19c904d4de',
|
'ResourceProvider': '1.1-7bbcd5ea1c51782692f55489ab08dea6',
|
||||||
'ResourceProviderList': '1.0-82bd48d8d0f7913bbe7266f3835c81bf',
|
'ResourceProviderList': '1.0-82bd48d8d0f7913bbe7266f3835c81bf',
|
||||||
'S3ImageMapping': '1.0-7dd7366a890d82660ed121de9092276e',
|
'S3ImageMapping': '1.0-7dd7366a890d82660ed121de9092276e',
|
||||||
'SchedulerLimits': '1.0-249c4bd8e62a9b327b7026b7f19cc641',
|
'SchedulerLimits': '1.0-249c4bd8e62a9b327b7026b7f19cc641',
|
||||||
|
Loading…
Reference in New Issue
Block a user