Merge "Add delete_, update_ and add_ inventory to ResourceProvider"
This commit is contained in:
commit
a7402060ec
|
@ -75,7 +75,8 @@ def _delete_inventory_from_provider(conn, rp, to_delete):
|
|||
del_stmt = _INV_TBL.delete().where(sa.and_(
|
||||
_INV_TBL.c.resource_provider_id == rp.id,
|
||||
_INV_TBL.c.resource_class_id.in_(to_delete)))
|
||||
conn.execute(del_stmt)
|
||||
res = conn.execute(del_stmt)
|
||||
return res.rowcount
|
||||
|
||||
|
||||
def _add_inventory_to_provider(conn, rp, inv_list, to_add):
|
||||
|
@ -89,6 +90,9 @@ def _add_inventory_to_provider(conn, rp, inv_list, to_add):
|
|||
"""
|
||||
for res_class in to_add:
|
||||
inv_record = inv_list.find(res_class)
|
||||
if inv_record.capacity <= 0:
|
||||
raise exception.ObjectActionError(
|
||||
action='add inventory', reason='invalid resource capacity')
|
||||
ins_stmt = _INV_TBL.insert().values(
|
||||
resource_provider_id=rp.id,
|
||||
resource_class_id=res_class,
|
||||
|
@ -112,6 +116,9 @@ def _update_inventory_for_provider(conn, rp, inv_list, to_update):
|
|||
"""
|
||||
for res_class in to_update:
|
||||
inv_record = inv_list.find(res_class)
|
||||
if inv_record.capacity <= 0:
|
||||
raise exception.ObjectActionError(
|
||||
action='update inventory', reason='invalid resource capacity')
|
||||
upd_stmt = _INV_TBL.update().where(sa.and_(
|
||||
_INV_TBL.c.resource_provider_id == rp.id,
|
||||
_INV_TBL.c.resource_class_id == res_class)).values(
|
||||
|
@ -121,7 +128,11 @@ def _update_inventory_for_provider(conn, rp, inv_list, to_update):
|
|||
max_unit=inv_record.max_unit,
|
||||
step_size=inv_record.step_size,
|
||||
allocation_ratio=inv_record.allocation_ratio)
|
||||
conn.execute(upd_stmt)
|
||||
res = conn.execute(upd_stmt)
|
||||
if not res.rowcount:
|
||||
raise exception.NotFound(
|
||||
'No inventory of class %s found for update'
|
||||
% fields.ResourceClass.from_index(res_class))
|
||||
|
||||
|
||||
def _increment_provider_generation(conn, rp):
|
||||
|
@ -149,6 +160,43 @@ def _increment_provider_generation(conn, rp):
|
|||
return new_generation
|
||||
|
||||
|
||||
@db_api.api_context_manager.writer
|
||||
def _add_inventory(context, rp, inventory):
|
||||
"""Add one Inventory that wasn't already on the provider."""
|
||||
resource_class_id = fields.ResourceClass.index(inventory.resource_class)
|
||||
inv_list = InventoryList(objects=[inventory])
|
||||
conn = context.session.connection()
|
||||
with conn.begin():
|
||||
_add_inventory_to_provider(
|
||||
conn, rp, inv_list, set([resource_class_id]))
|
||||
rp.generation = _increment_provider_generation(conn, rp)
|
||||
|
||||
|
||||
@db_api.api_context_manager.writer
|
||||
def _update_inventory(context, rp, inventory):
|
||||
"""Update an inventory already on the provider."""
|
||||
resource_class_id = fields.ResourceClass.index(inventory.resource_class)
|
||||
inv_list = InventoryList(objects=[inventory])
|
||||
conn = context.session.connection()
|
||||
with conn.begin():
|
||||
_update_inventory_for_provider(
|
||||
conn, rp, inv_list, set([resource_class_id]))
|
||||
rp.generation = _increment_provider_generation(conn, rp)
|
||||
|
||||
|
||||
@db_api.api_context_manager.writer
|
||||
def _delete_inventory(context, rp, resource_class_id):
|
||||
"""Delete up to one Inventory of the given resource_class id."""
|
||||
|
||||
conn = context.session.connection()
|
||||
with conn.begin():
|
||||
if not _delete_inventory_from_provider(conn, rp, [resource_class_id]):
|
||||
raise exception.NotFound(
|
||||
'No inventory of class %s found for delete'
|
||||
% fields.ResourceClass.from_index(resource_class_id))
|
||||
rp.generation = _increment_provider_generation(conn, rp)
|
||||
|
||||
|
||||
@db_api.api_context_manager.writer
|
||||
def _set_inventory(context, rp, inv_list):
|
||||
"""Given an InventoryList object, replaces the inventory of the
|
||||
|
@ -238,11 +286,38 @@ class ResourceProvider(base.NovaObject):
|
|||
db_resource_provider = cls._get_by_uuid_from_db(context, uuid)
|
||||
return cls._from_db_object(context, cls(), db_resource_provider)
|
||||
|
||||
@base.remotable
|
||||
def add_inventory(self, inventory):
|
||||
"""Add one new Inventory to the resource provider.
|
||||
|
||||
Fails if Inventory of the provided resource class is
|
||||
already present.
|
||||
"""
|
||||
_add_inventory(self._context, self, inventory)
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
def delete_inventory(self, resource_class):
|
||||
"""Delete Inventory of provided resource_class."""
|
||||
resource_class_id = fields.ResourceClass.index(resource_class)
|
||||
_delete_inventory(self._context, self, resource_class_id)
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
def set_inventory(self, inv_list):
|
||||
"""Set all resource provider Inventory to be the provided list."""
|
||||
_set_inventory(self._context, self, inv_list)
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
def update_inventory(self, inventory):
|
||||
"""Update one existing Inventory of the same resource class.
|
||||
|
||||
Fails if no Inventory of the same class is present.
|
||||
"""
|
||||
_update_inventory(self._context, self, inventory)
|
||||
self.obj_reset_changes()
|
||||
|
||||
@staticmethod
|
||||
def _create_in_db(context, updates):
|
||||
return _create_rp_in_db(context, updates)
|
||||
|
@ -345,6 +420,11 @@ class Inventory(_HasAResourceProvider):
|
|||
'allocation_ratio': fields.NonNegativeFloatField(default=1.0),
|
||||
}
|
||||
|
||||
@property
|
||||
def capacity(self):
|
||||
"""Inventory capacity, adjusted by allocation_ratio."""
|
||||
return int((self.total - self.reserved) * self.allocation_ratio)
|
||||
|
||||
@base.remotable
|
||||
def create(self):
|
||||
if 'id' in self:
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from oslo_db import exception as db_exc
|
||||
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova import objects
|
||||
|
@ -137,7 +140,7 @@ class ResourceProviderTestCase(test.NoDBTestCase):
|
|||
self.context, resource_provider.uuid))
|
||||
self.assertEqual(33, reloaded_inventories[0].total)
|
||||
|
||||
def test_provider_set_inventory(self):
|
||||
def test_provider_modify_inventory(self):
|
||||
rp = objects.ResourceProvider(context=self.context,
|
||||
uuid=uuidsentinel.rp_uuid,
|
||||
name=uuidsentinel.rp_name)
|
||||
|
@ -205,8 +208,7 @@ class ResourceProviderTestCase(test.NoDBTestCase):
|
|||
max_unit=100,
|
||||
step_size=10,
|
||||
allocation_ratio=1.0)
|
||||
inv_list = objects.InventoryList(objects=[disk_inv])
|
||||
rp.set_inventory(inv_list)
|
||||
rp.update_inventory(disk_inv)
|
||||
|
||||
# generation has bumped
|
||||
self.assertEqual(saved_generation + 1, rp.generation)
|
||||
|
@ -217,7 +219,80 @@ class ResourceProviderTestCase(test.NoDBTestCase):
|
|||
self.assertEqual(1, len(new_inv_list))
|
||||
self.assertEqual(2048, new_inv_list[0].total)
|
||||
|
||||
# fail when inventory bad
|
||||
disk_inv = objects.Inventory(
|
||||
resource_provider=rp,
|
||||
resource_class=fields.ResourceClass.DISK_GB,
|
||||
total=2048,
|
||||
reserved=2048)
|
||||
disk_inv.obj_set_defaults()
|
||||
self.assertRaises(exception.ObjectActionError,
|
||||
rp.update_inventory, disk_inv)
|
||||
|
||||
# generation has not bumped
|
||||
self.assertEqual(saved_generation, rp.generation)
|
||||
|
||||
# delete inventory
|
||||
rp.delete_inventory(fields.ResourceClass.DISK_GB)
|
||||
|
||||
# generation has bumped
|
||||
self.assertEqual(saved_generation + 1, rp.generation)
|
||||
saved_generation = rp.generation
|
||||
|
||||
new_inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
|
||||
self.context, uuidsentinel.rp_uuid)
|
||||
result = new_inv_list.find(fields.ResourceClass.DISK_GB)
|
||||
self.assertIsNone(result)
|
||||
self.assertRaises(exception.NotFound, rp.delete_inventory,
|
||||
fields.ResourceClass.DISK_GB)
|
||||
|
||||
# check inventory list is empty
|
||||
inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
|
||||
self.context, uuidsentinel.rp_uuid)
|
||||
self.assertEqual(0, len(inv_list))
|
||||
|
||||
# add some inventory
|
||||
rp.add_inventory(vcpu_inv)
|
||||
inv_list = objects.InventoryList.get_all_by_resource_provider_uuid(
|
||||
self.context, uuidsentinel.rp_uuid)
|
||||
self.assertEqual(1, len(inv_list))
|
||||
|
||||
# generation has bumped
|
||||
self.assertEqual(saved_generation + 1, rp.generation)
|
||||
saved_generation = rp.generation
|
||||
|
||||
# add same inventory again
|
||||
self.assertRaises(db_exc.DBDuplicateEntry,
|
||||
rp.add_inventory, vcpu_inv)
|
||||
|
||||
# generation has not bumped
|
||||
self.assertEqual(saved_generation, rp.generation)
|
||||
|
||||
# fail when generation wrong
|
||||
rp.generation = rp.generation - 1
|
||||
self.assertRaises(exception.ConcurrentUpdateDetected,
|
||||
rp.set_inventory, inv_list)
|
||||
|
||||
def test_delete_inventory_not_found(self):
|
||||
rp = objects.ResourceProvider(context=self.context,
|
||||
uuid=uuidsentinel.rp_uuid,
|
||||
name=uuidsentinel.rp_name)
|
||||
rp.create()
|
||||
error = self.assertRaises(exception.NotFound, rp.delete_inventory,
|
||||
'DISK_GB')
|
||||
self.assertIn('No inventory of class DISK_GB found for delete',
|
||||
str(error))
|
||||
|
||||
def test_update_inventory_not_found(self):
|
||||
rp = objects.ResourceProvider(context=self.context,
|
||||
uuid=uuidsentinel.rp_uuid,
|
||||
name=uuidsentinel.rp_name)
|
||||
rp.create()
|
||||
disk_inv = objects.Inventory(resource_provider=rp,
|
||||
resource_class='DISK_GB',
|
||||
total=2048)
|
||||
disk_inv.obj_set_defaults()
|
||||
error = self.assertRaises(exception.NotFound, rp.update_inventory,
|
||||
disk_inv)
|
||||
self.assertIn('No inventory of class DISK_GB found for update',
|
||||
str(error))
|
||||
|
|
|
@ -1180,7 +1180,7 @@ object_data = {
|
|||
'Quotas': '1.2-1fe4cd50593aaf5d36a6dc5ab3f98fb3',
|
||||
'QuotasNoOp': '1.2-e041ddeb7dc8188ca71706f78aad41c1',
|
||||
'RequestSpec': '1.6-c1cb516acdf120d367a42d343ed695b5',
|
||||
'ResourceProvider': '1.0-94e0e906feb26a24e217935c1e401467',
|
||||
'ResourceProvider': '1.0-421c968ee9b2341dd78b0c19c904d4de',
|
||||
'S3ImageMapping': '1.0-7dd7366a890d82660ed121de9092276e',
|
||||
'SchedulerLimits': '1.0-249c4bd8e62a9b327b7026b7f19cc641',
|
||||
'SchedulerRetries': '1.1-3c9c8b16143ebbb6ad7030e999d14cc0',
|
||||
|
|
|
@ -205,6 +205,22 @@ class _TestInventoryNoDB(object):
|
|||
self.assertEqual(1, inv.step_size)
|
||||
self.assertEqual(1.0, inv.allocation_ratio)
|
||||
|
||||
def test_capacity(self):
|
||||
rp = objects.ResourceProvider(id=_RESOURCE_PROVIDER_ID,
|
||||
uuid=_RESOURCE_PROVIDER_UUID)
|
||||
kwargs = dict(resource_provider=rp,
|
||||
resource_class=_RESOURCE_CLASS_NAME,
|
||||
total=16,
|
||||
reserved=16)
|
||||
inv = objects.Inventory(self.context, **kwargs)
|
||||
inv.obj_set_defaults()
|
||||
|
||||
self.assertEqual(0, inv.capacity)
|
||||
inv.reserved = 15
|
||||
self.assertEqual(1, inv.capacity)
|
||||
inv.allocation_ratio = 2.0
|
||||
self.assertEqual(2, inv.capacity)
|
||||
|
||||
|
||||
class TestInventoryNoDB(test_objects._LocalTest,
|
||||
_TestInventoryNoDB):
|
||||
|
|
Loading…
Reference in New Issue