Merge "Add delete_, update_ and add_ inventory to ResourceProvider"

This commit is contained in:
Jenkins 2016-06-20 22:55:33 +00:00 committed by Gerrit Code Review
commit a7402060ec
4 changed files with 177 additions and 6 deletions

View File

@ -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:

View File

@ -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))

View File

@ -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',

View File

@ -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):