def test_get_all_null(self): for uuid in [uuidsentinel.rp_uuid_1, uuidsentinel.rp_uuid_2]: self._create_provider(uuid, uuid=uuid) usages = usage_obj.get_all_by_resource_provider_uuid( self.ctx, uuidsentinel.rp_uuid_1) self.assertEqual(0, len(usages))
def test_get_all_multiple_inv(self): db_rp = self._create_provider('rp_no_inv') tb.add_inventory(db_rp, orc.DISK_GB, 1024) tb.add_inventory(db_rp, orc.VCPU, 24) usages = usage_obj.get_all_by_resource_provider_uuid( self.ctx, db_rp.uuid) self.assertEqual(2, len(usages))
def test_get_inventory_no_allocation(self): db_rp = self._create_provider('rp_no_inv') tb.add_inventory(db_rp, orc.DISK_GB, 1024) usages = usage_obj.get_all_by_resource_provider_uuid( self.ctx, db_rp.uuid) self.assertEqual(1, len(usages)) self.assertEqual(0, usages[0].usage) self.assertEqual(orc.DISK_GB, usages[0].resource_class)
def test_get_all_one_allocation(self): db_rp, _ = self._make_allocation(tb.DISK_INVENTORY, tb.DISK_ALLOCATION) inv = inv_obj.Inventory(resource_provider=db_rp, resource_class=orc.DISK_GB, total=1024) db_rp.set_inventory([inv]) usages = usage_obj.get_all_by_resource_provider_uuid( self.ctx, db_rp.uuid) self.assertEqual(1, len(usages)) self.assertEqual(2, usages[0].usage) self.assertEqual(orc.DISK_GB, usages[0].resource_class)
def list_usages(req): """GET a dictionary of resource provider usage by resource class. If the resource provider does not exist return a 404. On success return a 200 with an application/json representation of the usage dictionary. """ context = req.environ['placement.context'] context.can(policies.PROVIDER_USAGES) uuid = util.wsgi_path_item(req.environ, 'uuid') want_version = req.environ[microversion.MICROVERSION_ENVIRON] # Resource provider object needed for two things: If it is # NotFound we'll get a 404 here, which needs to happen because # get_all_by_resource_provider_uuid can return an empty list. # It is also needed for the generation, used in the outgoing # representation. try: resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid) except exception.NotFound as exc: raise webob.exc.HTTPNotFound( "No resource provider with uuid %(uuid)s found: %(error)s" % { 'uuid': uuid, 'error': exc }) usage = usage_obj.get_all_by_resource_provider_uuid(context, uuid) response = req.response response.body = encodeutils.to_utf8( jsonutils.dumps(_serialize_usages(resource_provider, usage))) req.response.content_type = 'application/json' if want_version.matches((1, 15)): req.response.cache_control = 'no-cache' # While it would be possible to generate a last-modified time # based on the collection of allocations that result in a usage # value (with some spelunking in the SQL) that doesn't align with # the question that is being asked in a request for usages: What # is the usage, now? So the last-modified time is set to utcnow. req.response.last_modified = timeutils.utcnow(with_timezone=True) return req.response
def test_update_inventory_violates_allocation(self, mock_log): # Compute nodes that are reconfigured have to be able to set # their inventory to something that violates allocations so # we need to make that possible. rp, allocation = self._make_allocation(tb.DISK_INVENTORY, tb.DISK_ALLOCATION) # attempt to set inventory to less than currently allocated # amounts new_total = 1 disk_inv = inv_obj.Inventory( resource_provider=rp, resource_class=orc.DISK_GB, total=new_total) rp.update_inventory(disk_inv) usages = usage_obj.get_all_by_resource_provider_uuid( self.ctx, rp.uuid) self.assertEqual(allocation.used, usages[0].usage) inv_list = inv_obj.get_all_by_resource_provider(self.ctx, rp) self.assertEqual(new_total, inv_list[0].total) mock_log.warning.assert_called_once_with( mock.ANY, {'uuid': rp.uuid, 'resource': 'DISK_GB'})
def _validate_usage(self, rp, usage): rp_usage = usage_obj.get_all_by_resource_provider_uuid( self.ctx, rp.uuid) self.assertEqual(usage, rp_usage[0].usage)
def test_allocation_list_create(self): max_unit = 10 consumer_uuid = uuidsentinel.consumer # Create a consumer representing the instance inst_consumer = consumer_obj.Consumer( self.ctx, uuid=consumer_uuid, user=self.user_obj, project=self.project_obj) inst_consumer.create() # Create two resource providers rp1_name = uuidsentinel.rp1_name rp1_uuid = uuidsentinel.rp1_uuid rp1_class = orc.DISK_GB rp1_used = 6 rp2_name = uuidsentinel.rp2_name rp2_uuid = uuidsentinel.rp2_uuid rp2_class = orc.IPV4_ADDRESS rp2_used = 2 rp1 = self._create_provider(rp1_name, uuid=rp1_uuid) rp2 = self._create_provider(rp2_name, uuid=rp2_uuid) # Two allocations, one for each resource provider. allocation_1 = alloc_obj.Allocation( resource_provider=rp1, consumer=inst_consumer, resource_class=rp1_class, used=rp1_used) allocation_2 = alloc_obj.Allocation( resource_provider=rp2, consumer=inst_consumer, resource_class=rp2_class, used=rp2_used) allocation_list = [allocation_1, allocation_2] # There's no inventory, we have a failure. error = self.assertRaises(exception.InvalidInventory, alloc_obj.replace_all, self.ctx, allocation_list) # Confirm that the resource class string, not index, is in # the exception and resource providers are listed by uuid. self.assertIn(rp1_class, str(error)) self.assertIn(rp2_class, str(error)) self.assertIn(rp1.uuid, str(error)) self.assertIn(rp2.uuid, str(error)) # Add inventory for one of the two resource providers. This should also # fail, since rp2 has no inventory. tb.add_inventory(rp1, rp1_class, 1024, max_unit=1) self.assertRaises(exception.InvalidInventory, alloc_obj.replace_all, self.ctx, allocation_list) # Add inventory for the second resource provider tb.add_inventory(rp2, rp2_class, 255, reserved=2, max_unit=1) # Now the allocations will still fail because max_unit 1 self.assertRaises(exception.InvalidAllocationConstraintsViolated, alloc_obj.replace_all, self.ctx, allocation_list) inv1 = inv_obj.Inventory(resource_provider=rp1, resource_class=rp1_class, total=1024, max_unit=max_unit) rp1.set_inventory([inv1]) inv2 = inv_obj.Inventory(resource_provider=rp2, resource_class=rp2_class, total=255, reserved=2, max_unit=max_unit) rp2.set_inventory([inv2]) # Now we can finally allocate. alloc_obj.replace_all(self.ctx, allocation_list) # Check that those allocations changed usage on each # resource provider. rp1_usage = usage_obj.get_all_by_resource_provider_uuid( self.ctx, rp1_uuid) rp2_usage = usage_obj.get_all_by_resource_provider_uuid( self.ctx, rp2_uuid) self.assertEqual(rp1_used, rp1_usage[0].usage) self.assertEqual(rp2_used, rp2_usage[0].usage) # redo one allocation # TODO(cdent): This does not currently behave as expected # because a new allocation is created, adding to the total # used, not replacing. rp1_used += 1 self.allocate_from_provider( rp1, rp1_class, rp1_used, consumer=inst_consumer) rp1_usage = usage_obj.get_all_by_resource_provider_uuid( self.ctx, rp1_uuid) self.assertEqual(rp1_used, rp1_usage[0].usage) # delete the allocations for the consumer # NOTE(cdent): The database uses 'consumer_id' for the # column, presumably because some ids might not be uuids, at # some point in the future. consumer_allocations = alloc_obj.get_all_by_consumer_id( self.ctx, consumer_uuid) alloc_obj.delete_all(self.ctx, consumer_allocations) rp1_usage = usage_obj.get_all_by_resource_provider_uuid( self.ctx, rp1_uuid) rp2_usage = usage_obj.get_all_by_resource_provider_uuid( self.ctx, rp2_uuid) self.assertEqual(0, rp1_usage[0].usage) self.assertEqual(0, rp2_usage[0].usage)