def _make_allocation(self, rp_uuid=None): rp_uuid = rp_uuid or uuidsentinel.allocation_resource_provider rp = objects.ResourceProvider(context=self.context, uuid=rp_uuid, name=rp_uuid) rp.create() alloc = objects.Allocation(self.context, resource_provider=rp, **DISK_ALLOCATION) alloc.create() return rp, alloc
def test_get_allocations(self, mock_get_allocations_from_db, mock_ensure_cache): rp = objects.ResourceProvider(id=_RESOURCE_PROVIDER_ID, uuid=uuids.resource_provider) allocations = objects.AllocationList.get_all_by_resource_provider_uuid( self.context, rp.uuid) self.assertEqual(1, len(allocations)) mock_get_allocations_from_db.assert_called_once_with( self.context, resource_provider_uuid=uuids.resource_provider) self.assertEqual(_ALLOCATION_DB['used'], allocations[0].used)
def test_create(self, mock_db_create): obj = objects.ResourceProvider(context=self.context, uuid=_RESOURCE_PROVIDER_UUID, name=_RESOURCE_PROVIDER_NAME) obj.create() self.assertEqual(_RESOURCE_PROVIDER_UUID, obj.uuid) self.assertIsInstance(obj.id, int) mock_db_create.assert_called_once_with(self.context, { 'uuid': _RESOURCE_PROVIDER_UUID, 'name': _RESOURCE_PROVIDER_NAME })
def test_get_by_uuid_from_db(self): rp = objects.ResourceProvider(context=self.context, uuid=_RESOURCE_PROVIDER_UUID) rp.create() retrieved_rp = objects.ResourceProvider._get_by_uuid_from_db( self.context, _RESOURCE_PROVIDER_UUID) self.assertEqual(rp.uuid, retrieved_rp.uuid) self.assertRaises(exception.NotFound, objects.ResourceProvider._get_by_uuid_from_db, self.context, uuids.missing)
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 start_fixture(self): super(AllocationFixture, self).start_fixture() self.context = context.get_admin_context() # Stealing from the super rp_name = os.environ['RP_NAME'] rp_uuid = os.environ['RP_UUID'] rp = objects.ResourceProvider( self.context, name=rp_name, uuid=rp_uuid) rp.create() # Create some DISK_GB inventory and allocations. inventory = objects.Inventory( self.context, resource_provider=rp, resource_class='DISK_GB', total=2048, step_size=10, min_unit=10, max_unit=600) inventory.obj_set_defaults() rp.add_inventory(inventory) allocation = objects.Allocation( self.context, resource_provider=rp, resource_class='DISK_GB', consumer_id=uuidutils.generate_uuid(), used=512) allocation.create() allocation = objects.Allocation( self.context, resource_provider=rp, resource_class='DISK_GB', consumer_id=uuidutils.generate_uuid(), used=512) allocation.create() # Create some VCPU inventory and allocations. inventory = objects.Inventory( self.context, resource_provider=rp, resource_class='VCPU', total=8, max_unit=4) inventory.obj_set_defaults() rp.add_inventory(inventory) allocation = objects.Allocation( self.context, resource_provider=rp, resource_class='VCPU', consumer_id=uuidutils.generate_uuid(), used=2) allocation.create() allocation = objects.Allocation( self.context, resource_provider=rp, resource_class='VCPU', consumer_id=uuidutils.generate_uuid(), used=4) allocation.create() # The ALT_RP_XXX variables are for a resource provider that has # not been created in the Allocation fixture os.environ['ALT_RP_UUID'] = uuidutils.generate_uuid() os.environ['ALT_RP_NAME'] = uuidutils.generate_uuid()
def _create_resource_provider(self, inventory): """Helper method to create a resource provider with inventory""" ctxt = context.get_admin_context() rp_uuid = uuidutils.generate_uuid() rp = objects.ResourceProvider(context=ctxt, name=rp_uuid, uuid=rp_uuid) rp.create() inventory = objects.Inventory(context=ctxt, resource_provider=rp, **inventory) inventory.create() return rp
def test_save_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.name = 'new-name' created_resource_provider.save() retrieved_resource_provider = objects.ResourceProvider.get_by_uuid( self.context, uuidsentinel.fake_resource_provider) self.assertEqual('new-name', retrieved_resource_provider.name)
def test_create_requires_created_resource_provider(self): rp = objects.ResourceProvider(context=self.context, uuid=uuids.inventory_resource_provider) inventory_dict = dict(_INVENTORY_DB) inventory_dict.pop('id') inventory_dict.pop('resource_provider_id') inventory_dict.pop('resource_class_id') inventory_dict['resource_provider'] = rp inventory = objects.Inventory(context=self.context, **inventory_dict) error = self.assertRaises(exception.ObjectActionError, inventory.create) self.assertIn('resource_provider required', 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', str(error))
def test_create_inventory_with_uncreated_provider(self): resource_provider = objects.ResourceProvider( context=self.context, uuid=uuidsentinel.inventory_resource_provider ) disk_inventory = objects.Inventory( context=self.context, resource_provider=resource_provider, **DISK_INVENTORY ) self.assertRaises(exception.ObjectActionError, disk_inventory.create)
def test_create(self, mock_db_create, mock_ensure_cache): rp = objects.ResourceProvider(id=_RESOURCE_PROVIDER_ID, uuid=uuids.resource_provider) obj = objects.Allocation(context=self.context, resource_provider=rp, resource_class=_RESOURCE_CLASS_NAME, consumer_id=uuids.fake_instance, used=8) obj.create() self.assertEqual(_ALLOCATION_ID, obj.id) expected = dict(_ALLOCATION_DB) expected.pop('id') mock_db_create.assert_called_once_with(self.context, expected)
def _make_rp_and_inventory(self, **kwargs): # Create one resource provider and set some inventory rp_name = uuidsentinel.rp_name rp_uuid = uuidsentinel.rp_uuid rp = objects.ResourceProvider( self.context, name=rp_name, uuid=rp_uuid) rp.create() inv = objects.Inventory(resource_provider=rp, total=1024, allocation_ratio=1, reserved=0, **kwargs) inv.obj_set_defaults() rp.set_inventory(objects.InventoryList(objects=[inv])) return rp
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_compute_node_inventory(self): # This is for making sure we only check once the I/O so we can directly # call this helper method for the next tests. uuid = uuids.compute_node name = 'computehost' compute_node = objects.ComputeNode(uuid=uuid, hypervisor_hostname=name, vcpus=2, cpu_allocation_ratio=16.0, memory_mb=1024, ram_allocation_ratio=1.5, local_gb=10, disk_allocation_ratio=1.0) rp = objects.ResourceProvider(uuid=uuid, name=name, generation=42) self.client._resource_providers[uuid] = rp self.flags(reserved_host_memory_mb=1000) self.flags(reserved_host_disk_mb=2000) result = self.client._compute_node_inventory(compute_node) expected_inventories = { 'VCPU': { 'total': compute_node.vcpus, 'reserved': 0, 'min_unit': 1, 'max_unit': 1, 'step_size': 1, 'allocation_ratio': compute_node.cpu_allocation_ratio, }, 'MEMORY_MB': { 'total': compute_node.memory_mb, 'reserved': CONF.reserved_host_memory_mb, 'min_unit': 1, 'max_unit': 1, 'step_size': 1, 'allocation_ratio': compute_node.ram_allocation_ratio, }, 'DISK_GB': { 'total': compute_node.local_gb, 'reserved': CONF.reserved_host_disk_mb * 1024, 'min_unit': 1, 'max_unit': 1, 'step_size': 1, 'allocation_ratio': compute_node.disk_allocation_ratio, }, } expected = { 'inventories': expected_inventories, } self.assertEqual(expected, result)
def test_update_inventory_conflicts_and_then_succeeds(self, ensure_mock): # Ensure _update_inventory() fails if we have a conflict when updating # but retries correctly. uuid = uuids.compute_node name = 'computehost' compute_node = objects.ComputeNode(uuid=uuid, hypervisor_hostname=name, vcpus=2, cpu_allocation_ratio=16.0, memory_mb=1024, ram_allocation_ratio=1.5, local_gb=10, disk_allocation_ratio=1.0) rp = objects.ResourceProvider(uuid=uuid, name=name, generation=42) # Make sure the ResourceProvider exists for preventing to call the API def fake_ensure_rp(uuid, name=None): self.client._resource_providers[uuid] = rp ensure_mock.side_effect = fake_ensure_rp self.client._resource_providers[uuid] = rp # Make sure we store the original generation bit before it's updated original_generation = rp.generation expected_payload = self.client._compute_node_inventory(compute_node) expected_output = mock.sentinel.inventories conflict_mock = mock.Mock(status_code=409) success_mock = mock.Mock(status_code=200, json=lambda: expected_output) self.ks_sess_mock.put.side_effect = (conflict_mock, success_mock) result = self.client._update_inventory(compute_node) expected_url = '/resource_providers/' + uuid + '/inventories' self.ks_sess_mock.put.assert_has_calls([ mock.call(expected_url, endpoint_filter=mock.ANY, json=expected_payload, raise_exc=False), mock.call(expected_url, endpoint_filter=mock.ANY, json=expected_payload, raise_exc=False), ]) self.assertTrue(result) # Make sure the generation bit has been incremented rp = self.client._resource_providers[compute_node.uuid] self.assertEqual(original_generation + 1, rp.generation)
def test_set_defaults(self): rp = objects.ResourceProvider(id=_RESOURCE_PROVIDER_ID, uuid=_RESOURCE_PROVIDER_UUID) kwargs = dict(resource_provider=rp, resource_class=_RESOURCE_CLASS_NAME, total=16) inv = objects.Inventory(self.context, **kwargs) inv.obj_set_defaults() self.assertEqual(0, inv.reserved) self.assertEqual(1, inv.min_unit) self.assertEqual(1, inv.max_unit) self.assertEqual(1, inv.step_size) self.assertEqual(1.0, inv.allocation_ratio)
def test_non_negative_handling(self): # NOTE(cdent): Just checking, useless to be actually # comprehensive here. rp = objects.ResourceProvider(id=_RESOURCE_PROVIDER_ID, uuid=_RESOURCE_PROVIDER_UUID) kwargs = dict(resource_provider=rp, resource_class=_RESOURCE_CLASS_NAME, total=16, reserved=2, min_unit=1, max_unit=-8, step_size=1, allocation_ratio=1.0) self.assertRaises(ValueError, objects.Inventory, **kwargs)
def _ensure_resource_provider(self): shortname = self.host.split('.')[0] rp_name = 'compute-%s-%s' % (shortname, self.uuid) rp = objects.ResourceProvider(context=self._context, uuid=self.uuid, name=rp_name) try: rp.create() except db_exc.DBDuplicateEntry: rp = objects.ResourceProvider.get_by_uuid(self._context, self.uuid) if rp.name != rp_name: rp.name = rp_name rp.save() return rp
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)
def test_get_all_by_filters(self): for rp_i in ['1', '2']: uuid = getattr(uuidsentinel, 'rp_uuid_' + rp_i) name = 'rp_name_' + rp_i rp = objects.ResourceProvider(self.context, name=name, uuid=uuid) rp.create() resource_providers = objects.ResourceProviderList.get_all_by_filters( self.context) self.assertEqual(2, len(resource_providers)) resource_providers = objects.ResourceProviderList.get_all_by_filters( self.context, filters={'name': 'rp_name_1'}) self.assertEqual(1, len(resource_providers)) resource_providers = objects.ResourceProviderList.get_all_by_filters( self.context, filters={'can_host': 1}) self.assertEqual(0, len(resource_providers))
def create_inventory(self): """Create the initial inventory objects for this compute node. This is only ever called once, either for the first time when a compute is created, or after an upgrade where the required services have reached the required version. """ rp = objects.ResourceProvider(context=self._context, uuid=self.uuid) rp.create() cpu = objects.Inventory(context=self._context, resource_provider=rp, resource_class=fields.ResourceClass.VCPU, total=self.vcpus, reserved=0, min_unit=1, max_unit=1, step_size=1, allocation_ratio=self.cpu_allocation_ratio) cpu.create() mem = objects.Inventory(context=self._context, resource_provider=rp, resource_class=fields.ResourceClass.MEMORY_MB, total=self.memory_mb, reserved=0, min_unit=1, max_unit=1, step_size=1, allocation_ratio=self.ram_allocation_ratio) mem.create() # FIXME(danms): Eventually we want to not write this record # if the compute host is on shared storage. We'll need some # indication from it to that effect, so for now we always # write it so that we can make all the usual machinery depend # on these records instead of the legacy columns. disk = objects.Inventory(context=self._context, resource_provider=rp, resource_class=fields.ResourceClass.DISK_GB, total=self.local_gb, reserved=0, min_unit=1, max_unit=1, step_size=1, allocation_ratio=self.disk_allocation_ratio) disk.create()
def test_delete_inventory_already_no_inventory(self, mock_get, mock_put, mock_extract): cn = self.compute_node rp = objects.ResourceProvider(uuid=cn.uuid, generation=42) # Make sure the ResourceProvider exists for preventing to call the API self.client._resource_providers[cn.uuid] = rp mock_get.return_value.json.return_value = { 'resource_provider_generation': 1, 'inventories': {} } result = self.client._delete_inventory(cn.uuid) self.assertIsNone(result) self.assertFalse(mock_put.called) self.assertFalse(mock_extract.called) new_gen = self.client._resource_providers[cn.uuid].generation self.assertEqual(1, new_gen)
def test_update_inventory_unknown_response(self, mock_put, mock_get): # Ensure _update_inventory() returns a list of Inventories objects # after creating or updating the existing values uuid = uuids.compute_node compute_node = self.compute_node rp = objects.ResourceProvider(uuid=uuid, name='foo', generation=42) # Make sure the ResourceProvider exists for preventing to call the API self.client._resource_providers[uuid] = rp mock_get.return_value = {} mock_put.return_value.status_code = 234 result = self.client._update_inventory_attempt(compute_node) self.assertFalse(result) # No cache invalidation self.assertIn(uuid, self.client._resource_providers)
def test_create(self, mock_db_create): rp = objects.ResourceProvider(id=_RESOURCE_PROVIDER_ID, uuid=_RESOURCE_PROVIDER_UUID) obj = objects.Inventory(context=self.context, resource_provider=rp, resource_class=_RESOURCE_CLASS_NAME, total=16, reserved=2, min_unit=1, max_unit=8, step_size=1, allocation_ratio=1.0) obj.create() self.assertEqual(_INVENTORY_ID, obj.id) expected = dict(_INVENTORY_DB) expected.pop('id') mock_db_create.assert_called_once_with(self.context, expected)
def test_add_invalid_inventory(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=fields.ResourceClass.DISK_GB, total=1024, reserved=2048) disk_inv.obj_set_defaults() error = self.assertRaises(exception.InvalidInventoryCapacity, rp.add_inventory, disk_inv) self.assertIn("Invalid inventory for '%s'" % fields.ResourceClass.DISK_GB, str(error)) self.assertIn("on resource provider '%s'." % rp.uuid, str(error))
def _create_resource_provider(self, uuid, name): """Calls the placement API to create a new resource provider record. Returns an `objects.ResourceProvider` object representing the newly-created resource provider object. :param uuid: UUID of the new resource provider :param name: Name of the resource provider """ url = "/resource_providers" payload = { 'uuid': uuid, 'name': name, } resp = self.post(url, payload) if resp.status_code == 201: msg = _LI("Created resource provider record via placement API " "for resource provider with UUID {0} and name {1}.") msg = msg.format(uuid, name) LOG.info(msg) return objects.ResourceProvider( uuid=uuid, name=name, generation=1, ) elif resp.status_code == 409: # Another thread concurrently created a resource provider with the # same UUID. Log a warning and then just return the resource # provider object from _get_resource_provider() msg = _LI("Another thread already created a resource provider " "with the UUID {0}. Grabbing that record from " "the placement API.") msg = msg.format(uuid) LOG.info(msg) return self._get_resource_provider(uuid) else: msg = _LE("Failed to create resource provider record in " "placement API for UUID %(uuid)s. " "Got %(status_code)d: %(err_text)s.") args = { 'uuid': uuid, 'status_code': resp.status_code, 'err_text': resp.text, } LOG.error(msg, args)
def test_set_inventory_over_capacity(self, mock_log): 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=fields.ResourceClass.DISK_GB, total=1024, reserved=15, min_unit=10, max_unit=100, step_size=10, allocation_ratio=1.0) vcpu_inv = objects.Inventory(resource_provider=rp, resource_class=fields.ResourceClass.VCPU, total=12, reserved=0, min_unit=1, max_unit=12, step_size=1, allocation_ratio=16.0) inv_list = objects.InventoryList(objects=[disk_inv, vcpu_inv]) rp.set_inventory(inv_list) self.assertFalse(mock_log.warning.called) # Allocate something reasonable for the above inventory alloc = objects.Allocation(context=self.context, resource_provider=rp, consumer_id=uuidsentinel.consumer, resource_class='DISK_GB', used=512) alloc.create() # Update our inventory to over-subscribe us after the above allocation disk_inv.total = 400 rp.set_inventory(inv_list) # We should succeed, but have logged a warning for going over on disk mock_log.warning.assert_called_once_with(mock.ANY, { 'uuid': rp.uuid, 'resource': 'DISK_GB' })
def test_get_inventory_no_allocation(self): db_rp = objects.ResourceProvider(self.context, name=uuidsentinel.rp_no_inv, uuid=uuidsentinel.rp_no_inv) db_rp.create() inv = objects.Inventory(resource_provider=db_rp, resource_class=fields.ResourceClass.DISK_GB, total=1024) inv.obj_set_defaults() inv_list = objects.InventoryList(objects=[inv]) db_rp.set_inventory(inv_list) usage_list = objects.UsageList.get_all_by_resource_provider_uuid( self.context, db_rp.uuid) self.assertEqual(1, len(usage_list)) self.assertEqual(0, usage_list[0].usage) self.assertEqual(fields.ResourceClass.DISK_GB, usage_list[0].resource_class)
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))