try:
resource_provider.set_inventory(inventories)
+ except exception.ResourceClassNotFound as exc:
+ raise webob.exc.HTTPBadRequest(
+ _('Unknown resource class in inventory for resource provider '
+ '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
+ 'error': exc},
+ json_formatter=util.json_error_formatter)
+ except exception.InventoryWithResourceClassNotFound as exc:
+ raise webob.exc.HTTPConflict(
+ _('Race condition detected when setting inventory. No inventory '
+ 'record with resource class for resource provider '
+ '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
+ 'error': exc},
+ json_formatter=util.json_error_formatter)
except (exception.ConcurrentUpdateDetected,
exception.InventoryInUse,
db_exc.DBDuplicateEntry) as exc:
raise webob.exc.HTTPConflict(
_('update conflict: %(error)s') % {'error': exc},
json_formatter=util.json_error_formatter)
+ except exception.InventoryWithResourceClassNotFound as exc:
+ raise webob.exc.HTTPBadRequest(
+ _('No inventory record with resource class for resource provider '
+ '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
+ 'error': exc},
+ json_formatter=util.json_error_formatter)
except exception.InvalidInventoryCapacity as exc:
raise webob.exc.HTTPBadRequest(
_('Unable to update inventory for resource provider '
from nova.db.sqlalchemy import api as db_api
from nova.db.sqlalchemy import api_models as models
+from nova import exception
from nova.objects import fields
_RC_TBL = models.ResourceClass.__table__
:returns integer identifier for the resource class, or None, if no such
resource class was found in the list of standard resource
classes or the resource_classes database table.
+ :raises `exception.ResourceClassNotFound` if rc_str cannot be found in
+ either the standard classes or the DB.
"""
if rc_str in self.id_cache:
return self.id_cache[rc_str]
else:
# Otherwise, check the database table
_refresh_from_db(self.ctx, self)
- return self.id_cache.get(rc_str)
+ if rc_str in self.id_cache:
+ return self.id_cache[rc_str]
+ raise exception.ResourceClassNotFound(resource_class=rc_str)
def string_from_id(self, rc_id):
"""The reverse of the id_from_string() method. Given a supplied numeric
:returns string identifier for the resource class, or None, if no such
resource class was found in the list of standard resource
classes or the resource_classes database table.
+ :raises `exception.ResourceClassNotFound` if rc_id cannot be found in
+ either the standard classes or the DB.
"""
if rc_id in self.str_cache:
return self.str_cache[rc_id]
except IndexError:
# Otherwise, check the database table
_refresh_from_db(self.ctx, self)
- return self.str_cache.get(rc_id)
+ if rc_id in self.str_cache:
+ return self.str_cache[rc_id]
+ raise exception.ResourceClassNotFound(resource_class=rc_id)
"Please retry your update")
+class ResourceClassNotFound(NotFound):
+ msg_fmt = _("No such resource class %(resource_class)s.")
+
+
class ResourceProviderInUse(NovaException):
msg_fmt = _("Resource provider has allocations.")
+class InventoryWithResourceClassNotFound(NotFound):
+ msg_fmt = _("No inventory of class %(resource_class)s found.")
+
+
class InvalidInventory(Invalid):
msg_fmt = _("Inventory for '%(resource_class)s' on "
"resource provider '%(resource_provider)s' invalid.")
allocation_ratio=inv_record.allocation_ratio)
res = conn.execute(upd_stmt)
if not res.rowcount:
- raise exception.NotFound(
- 'No inventory of class %s found for update' % rc_str)
+ raise exception.InventoryWithResourceClassNotFound(
+ resource_class=rc_str)
return exceeded
@db_api.api_context_manager.writer
def _add_inventory(context, rp, inventory):
- """Add one Inventory that wasn't already on the provider."""
+ """Add one Inventory that wasn't already on the provider.
+
+ :raises `exception.ResourceClassNotFound` if inventory.resource_class
+ cannot be found in either the standard classes or the DB.
+ """
_ensure_rc_cache(context)
rc_id = _RC_CACHE.id_from_string(inventory.resource_class)
- if rc_id is None:
- raise exception.NotFound("No such resource class '%s'" %
- inventory.resource_class)
inv_list = InventoryList(objects=[inventory])
conn = context.session.connection()
with conn.begin():
@db_api.api_context_manager.writer
def _update_inventory(context, rp, inventory):
- """Update an inventory already on the provider."""
+ """Update an inventory already on the provider.
+
+ :raises `exception.ResourceClassNotFound` if inventory.resource_class
+ cannot be found in either the standard classes or the DB.
+ """
_ensure_rc_cache(context)
rc_id = _RC_CACHE.id_from_string(inventory.resource_class)
- if rc_id is None:
- raise exception.NotFound("No such resource class '%s'" %
- inventory.resource_class)
inv_list = InventoryList(objects=[inventory])
conn = context.session.connection()
with conn.begin():
@db_api.api_context_manager.writer
def _delete_inventory(context, rp, resource_class):
- """Delete up to one Inventory of the given resource_class string."""
+ """Delete up to one Inventory of the given resource_class string.
+
+ :raises `exception.ResourceClassNotFound` if resource_class
+ cannot be found in either the standard classes or the DB.
+ """
_ensure_rc_cache(context)
conn = context.session.connection()
rc_id = _RC_CACHE.id_from_string(resource_class)
the same resource provider's view of its inventory or allocations
in between the time when this object was originally read
and the call to set the inventory.
+ :raises `exception.ResourceClassNotFound` if any resource class in any
+ inventory in inv_list cannot be found in either the standard
+ classes or the DB.
"""
_ensure_rc_cache(context)
conn = context.session.connection()
We must check that there is capacity for each allocation.
If there is not we roll back the entire set.
+
+ :raises `exception.ResourceClassNotFound` if any resource class in any
+ allocation in allocs cannot be found in either the standard
+ classes or the DB.
"""
_ensure_rc_cache(context)
conn = context.session.connection()
# Short-circuit out if there are any allocations with string
- # resource class names that don't exist.
+ # resource class names that don't exist this will raise a
+ # ResourceClassNotFound exception.
for alloc in allocs:
- if _RC_CACHE.id_from_string(alloc.resource_class) is None:
- raise exception.NotFound("No such resource class '%s'" %
- alloc.resource_class)
+ _RC_CACHE.id_from_string(alloc.resource_class)
# Before writing any allocation records, we check that the submitted
# allocations do not cause any inventory capacity to be exceeded for
COWS: 12
status: 400
response_strings:
- - No such resource class 'COWS'
+ - No such resource class COWS
- name: delete allocation
DELETE: /allocations/599ffd2d-526a-4b2e-8683-f13ad25f9958
response_strings:
- resource provider generation conflict
+- name: modify inventory no such resource class in inventory
+ PUT: /resource_providers/$ENVIRON['RP_UUID']/inventories/MEMORY_MB
+ request_headers:
+ content-type: application/json
+ data:
+ resource_provider_generation: 2
+ total: 2048
+ status: 400
+ response_strings:
+ - No inventory record with resource class
+
- name: modify inventory invalid data
desc: This should 400 because reserved is greater than total
PUT: $LAST_URL
total: 2048
status: 400
response_strings:
- - No such resource class 'NO_CLASS_14'
+ - No such resource class NO_CLASS_14
- name: post inventory duplicated resource class
desc: DISK_GB was already created above
response_strings:
- resource provider generation conflict
+- name: put all inventory unknown resource class
+ PUT: /resource_providers/$ENVIRON['RP_UUID']/inventories
+ request_headers:
+ content-type: application/json
+ data:
+ resource_provider_generation: 6
+ inventories:
+ HOUSE:
+ total: 253
+ status: 400
+ response_strings:
+ - Unknown resource class in inventory
+
# NOTE(cdent): The generation is 6 now, based on the activity at
# the start of this file.
- name: put all inventory bad capacity
import mock
from nova.db.sqlalchemy import resource_class_cache as rc_cache
+from nova import exception
from nova import test
from nova.tests import fixtures
"""
cache = rc_cache.ResourceClassCache(self.context)
- # Haven't added anything to the DB yet, so should return None
- self.assertIsNone(cache.string_from_id(1001))
- self.assertIsNone(cache.id_from_string("IRON_NFV"))
+ # Haven't added anything to the DB yet, so should raise
+ # ResourceClassNotFound
+ self.assertRaises(exception.ResourceClassNotFound,
+ cache.string_from_id, 1001)
+ self.assertRaises(exception.ResourceClassNotFound,
+ cache.id_from_string, "IRON_NFV")
# Now add to the database and verify appropriate results...
with self.context.session.connection() as conn:
self.assertEqual('IRON_NFV', cache.string_from_id(1001))
self.assertEqual(1001, cache.id_from_string('IRON_NFV'))
self.assertFalse(sel_mock.called)
+
+ def test_rc_cache_miss(self):
+ """Test that we raise ResourceClassNotFound if an unknown resource
+ class ID or string is searched for.
+ """
+ cache = rc_cache.ResourceClassCache(self.context)
+ self.assertRaises(exception.ResourceClassNotFound,
+ cache.string_from_id, 99999999)
+ self.assertRaises(exception.ResourceClassNotFound,
+ cache.id_from_string, 'UNKNOWN')
self.context, resource_provider.uuid))
self.assertEqual(33, reloaded_inventories[0].total)
+ def test_set_inventory_unknown_resource_class(self):
+ """Test attempting to set inventory to an unknown resource class raises
+ an exception.
+ """
+ rp = objects.ResourceProvider(
+ context=self.context,
+ uuid=uuidsentinel.rp_uuid,
+ name='compute-host',
+ )
+ rp.create()
+
+ inv = objects.Inventory(
+ resource_provider=rp,
+ resource_class='UNKNOWN',
+ total=1024,
+ reserved=15,
+ min_unit=10,
+ max_unit=100,
+ step_size=10,
+ allocation_ratio=1.0,
+ )
+
+ inv_list = objects.InventoryList(objects=[inv])
+ self.assertRaises(exception.ResourceClassNotFound,
+ rp.set_inventory, inv_list)
+
@mock.patch('nova.objects.resource_provider.LOG')
def test_set_inventory_over_capacity(self, mock_log):
rp = objects.ResourceProvider(context=self.context,
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',
+ self.assertIn('No inventory of class DISK_GB found',
str(error))
@mock.patch('nova.objects.resource_provider.LOG')