From 0b85bb4b42ab8d47809ecb9244df88770de5d89b Mon Sep 17 00:00:00 2001 From: Nikola Dipanov Date: Tue, 5 Apr 2016 19:04:07 +0100 Subject: [PATCH] pci: related updates are done without DB lookups Now that we have all relationships recorded on objects kept in the master-list in memory, we can use those links to do updates (that eventually get saved on pci_tracker.save()) without wrongfully updating objects within the local scope and losing changes immediately. As a convenience, we add two properties to the PciDevice object that take care of fetching related objects without worrying about missing or unset values. We also clarify a bit more how to use PciDevTracker.pci_devs attribute and why we can't just randomly fish PciDevices out of the DB for the purposes of updating them. Change-Id: I118ba35f464afc970fef54759d5560ba20ff9c52 Closes-bug: #1565785 --- nova/objects/pci_device.py | 62 ++---- nova/pci/manager.py | 14 +- nova/pci/stats.py | 10 +- nova/tests/unit/objects/test_pci_device.py | 248 +++++++++------------ nova/tests/unit/pci/test_stats.py | 134 +++++------ 5 files changed, 199 insertions(+), 269 deletions(-) diff --git a/nova/objects/pci_device.py b/nova/objects/pci_device.py index a61a5f3bd73f..87e55645e952 100644 --- a/nova/objects/pci_device.py +++ b/nova/objects/pci_device.py @@ -279,10 +279,7 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): if self.dev_type == fields.PciDeviceType.SRIOV_PF: # Update PF status to CLAIMED if all of it dependants are free # and set their status to UNCLAIMABLE - vfs_list = objects.PciDeviceList.get_by_parent_address( - self._context, - self.compute_node_id, - self.address) + vfs_list = self.child_devices if not all([vf.is_available() for vf in vfs_list]): raise exception.PciDeviceVFInvalidStatus( compute_node_id=self.compute_node_id, @@ -301,10 +298,8 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): parent_ok_statuses = (fields.PciDeviceStatus.AVAILABLE, fields.PciDeviceStatus.UNCLAIMABLE, fields.PciDeviceStatus.UNAVAILABLE) - try: - parent = self.get_by_dev_addr(self._context, - self.compute_node_id, - self.parent_addr) + parent = self.parent_device + if parent: if parent.status not in parent_ok_statuses: raise exception.PciDevicePFInvalidStatus( compute_node_id=self.compute_node_id, @@ -314,11 +309,11 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): # Set PF status if parent.status == fields.PciDeviceStatus.AVAILABLE: parent.status = fields.PciDeviceStatus.UNCLAIMABLE - except exception.PciDeviceNotFound: + else: LOG.debug('Physical function addr: %(pf_addr)s parent of ' - 'VF addr: %(vf_addr)s was not found', - {'pf_addr': self.parent_addr, - 'vf_addr': self.address}) + 'VF addr: %(vf_addr)s was not found', + {'pf_addr': self.parent_addr, + 'vf_addr': self.address}) self.status = fields.PciDeviceStatus.CLAIMED self.instance_uuid = instance_uuid @@ -343,10 +338,7 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): address=self.address, owner=self.instance_uuid, hopeowner=instance['uuid']) if self.dev_type == fields.PciDeviceType.SRIOV_PF: - vfs_list = objects.PciDeviceList.get_by_parent_address( - self._context, - self.compute_node_id, - self.address) + vfs_list = self.child_devices if not all([vf.status in dependatns_ok_statuses for vf in vfs_list]): raise exception.PciDeviceVFInvalidStatus( @@ -356,10 +348,8 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): fields.PciDeviceStatus.UNAVAILABLE) elif (self.dev_type == fields.PciDeviceType.SRIOV_VF): - try: - parent = self.get_by_dev_addr(self._context, - self.compute_node_id, - self.parent_addr) + parent = self.parent_device + if parent: if parent.status not in parent_ok_statuses: raise exception.PciDevicePFInvalidStatus( compute_node_id=self.compute_node_id, @@ -368,7 +358,7 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): hopestatus=parent_ok_statuses) # Set PF status parent.status = fields.PciDeviceStatus.UNAVAILABLE - except exception.PciDeviceNotFound: + else: LOG.debug('Physical function addr: %(pf_addr)s parent of ' 'VF addr: %(vf_addr)s was not found', {'pf_addr': self.parent_addr, @@ -412,31 +402,23 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): hopeowner=instance['uuid']) if self.dev_type == fields.PciDeviceType.SRIOV_PF: # Set all PF dependants status to AVAILABLE - vfs_list = objects.PciDeviceList.get_by_parent_address( - self._context, - self.compute_node_id, - self.address) + vfs_list = self.child_devices self._bulk_update_status(vfs_list, fields.PciDeviceStatus.AVAILABLE) free_devs.extend(vfs_list) if self.dev_type == fields.PciDeviceType.SRIOV_VF: # Set PF status to AVAILABLE if all of it's VFs are free - vfs_list = objects.PciDeviceList.get_by_parent_address( - self._context, - self.compute_node_id, - self.parent_addr) - if all([vf.is_available() for vf in vfs_list if vf.id != self.id]): - try: - parent = self.get_by_dev_addr(self._context, - self.compute_node_id, - self.parent_addr) - parent.status = fields.PciDeviceStatus.AVAILABLE + parent = self.parent_device + if not parent: + LOG.debug('Physical function addr: %(pf_addr)s parent of ' + 'VF addr: %(vf_addr)s was not found', + {'pf_addr': self.parent_addr, + 'vf_addr': self.address}) + else: + vfs_list = parent.child_devices + if all([vf.is_available() for vf in vfs_list + if vf.id != self.id]): free_devs.append(parent) - except exception.PciDeviceNotFound: - LOG.debug('Physical function addr: %(pf_addr)s parent of ' - 'VF addr: %(vf_addr)s was not found', - {'pf_addr': self.parent_addr, - 'vf_addr': self.address}) old_status = self.status self.status = fields.PciDeviceStatus.AVAILABLE free_devs.append(self) diff --git a/nova/pci/manager.py b/nova/pci/manager.py index c98c15c94cbd..473d5bf4d142 100644 --- a/nova/pci/manager.py +++ b/nova/pci/manager.py @@ -40,8 +40,18 @@ class PciDevTracker(object): It's called by compute node resource tracker to allocate and free devices to/from instances, and to update the available pci passthrough - devices information from hypervisor periodically. The devices - information is updated to DB when devices information is changed. + devices information from hypervisor periodically. + + `pci_devs` attribute of this class is the in-memory "master copy" of all + devices on each compute host, and all data changes that happen when + claiming/allocating/freeing + devices HAVE TO be made against instances contained in `pci_devs` list, + because they are periodically flushed to the DB when the save() + method is called. + + It is unsafe to fetch PciDevice objects elsewhere in the code for update + purposes as those changes will end up being overwritten when the `pci_devs` + are saved. """ def __init__(self, context, node_id=None): diff --git a/nova/pci/stats.py b/nova/pci/stats.py index 3185ca66b0ec..cd713499d50f 100644 --- a/nova/pci/stats.py +++ b/nova/pci/stats.py @@ -22,7 +22,6 @@ import six from nova import exception from nova.i18n import _LE -from nova import objects from nova.objects import fields from nova.objects import pci_device_pool from nova.pci import utils @@ -192,18 +191,13 @@ class PciDeviceStats(object): decreased, unless it is no longer in a pool. """ if pci_dev.dev_type == fields.PciDeviceType.SRIOV_PF: - vfs_list = objects.PciDeviceList.get_by_parent_address( - pci_dev._context, - pci_dev.compute_node_id, - pci_dev.address) + vfs_list = pci_dev.child_devices if vfs_list: for vf in vfs_list: self.remove_device(vf) elif pci_dev.dev_type == fields.PciDeviceType.SRIOV_VF: try: - parent = pci_dev.get_by_dev_addr(pci_dev._context, - pci_dev.compute_node_id, - pci_dev.parent_addr) + parent = pci_dev.parent_device # Make sure not to decrease PF pool count if this parent has # been already removed from pools if parent in self.get_free_devs(): diff --git a/nova/tests/unit/objects/test_pci_device.py b/nova/tests/unit/objects/test_pci_device.py index 00818a877b06..b56cb455fe19 100644 --- a/nova/tests/unit/objects/test_pci_device.py +++ b/nova/tests/unit/objects/test_pci_device.py @@ -25,7 +25,6 @@ from nova import objects from nova.objects import fields from nova.objects import instance from nova.objects import pci_device -from nova import test from nova.tests.unit.objects import test_objects from nova.tests import uuidsentinel as uuids @@ -523,6 +522,7 @@ class _TestSRIOVPciDeviceObject(object): 'numa_node': 0} pci_dev_obj = objects.PciDevice.create(None, pci_dev) pci_dev_obj.id = num_pfs + 81 + pci_dev_obj.child_devices = [] self.sriov_pf_devices.append(pci_dev_obj) self.sriov_vf_devices = [] @@ -538,6 +538,8 @@ class _TestSRIOVPciDeviceObject(object): 'numa_node': 0} pci_dev_obj = objects.PciDevice.create(None, pci_dev) pci_dev_obj.id = num_vfs + 1 + pci_dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)] + pci_dev_obj.parent_device.child_devices.append(pci_dev_obj) self.sriov_vf_devices.append(pci_dev_obj) def _create_fake_instance(self): @@ -553,188 +555,158 @@ class _TestSRIOVPciDeviceObject(object): self.mox.ReplayAll() self.pci_device = pci_device.PciDevice.get_by_dev_addr(ctxt, 1, 'a') - def _fake_get_by_parent_address(self, ctxt, node_id, addr): + def _get_children_by_parent_address(self, addr): vf_devs = [] for dev in self.sriov_vf_devices: if dev.parent_addr == addr: vf_devs.append(dev) return vf_devs - def _fake_pci_device_get_by_addr(self, ctxt, id, addr): + def _get_parent_by_address(self, addr): for dev in self.sriov_pf_devices: if dev.address == addr: return dev def test_claim_PF(self): self._create_fake_instance() - with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address): - self._create_pci_devices() - devobj = self.sriov_pf_devices[0] - devobj.claim(self.inst.uuid) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.CLAIMED) - self.assertEqual(devobj.instance_uuid, - self.inst.uuid) - self.assertEqual(len(self.inst.pci_devices), 0) - # check if the all the dependants are UNCLAIMABLE - self.assertTrue(all( - [dev.status == fields.PciDeviceStatus.UNCLAIMABLE for - dev in self._fake_get_by_parent_address(None, None, - self.sriov_pf_devices[0].address)])) + self._create_pci_devices() + devobj = self.sriov_pf_devices[0] + devobj.claim(self.inst.uuid) + self.assertEqual(devobj.status, + fields.PciDeviceStatus.CLAIMED) + self.assertEqual(devobj.instance_uuid, + self.inst.uuid) + self.assertEqual(len(self.inst.pci_devices), 0) + # check if the all the dependants are UNCLAIMABLE + self.assertTrue(all( + [dev.status == fields.PciDeviceStatus.UNCLAIMABLE for + dev in self._get_children_by_parent_address( + self.sriov_pf_devices[0].address)])) def test_claim_VF(self): self._create_fake_instance() - with mock.patch.object(objects.PciDevice, 'get_by_dev_addr', - side_effect=self._fake_pci_device_get_by_addr): - self._create_pci_devices() - devobj = self.sriov_vf_devices[0] - devobj.claim(self.inst.uuid) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.CLAIMED) - self.assertEqual(devobj.instance_uuid, - self.inst.uuid) - self.assertEqual(len(self.inst.pci_devices), 0) + self._create_pci_devices() + devobj = self.sriov_vf_devices[0] + devobj.claim(self.inst.uuid) + self.assertEqual(devobj.status, + fields.PciDeviceStatus.CLAIMED) + self.assertEqual(devobj.instance_uuid, + self.inst.uuid) + self.assertEqual(len(self.inst.pci_devices), 0) - # check if parent device status has been changed to UNCLAIMABLE - parent = self._fake_pci_device_get_by_addr(None, None, - devobj.parent_addr) - self.assertTrue(fields.PciDeviceStatus.UNCLAIMABLE, parent.status) + # check if parent device status has been changed to UNCLAIMABLE + parent = self._get_parent_by_address(devobj.parent_addr) + self.assertTrue(fields.PciDeviceStatus.UNCLAIMABLE, parent.status) def test_allocate_PF(self): self._create_fake_instance() - with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address): - self._create_pci_devices() - devobj = self.sriov_pf_devices[0] - devobj.claim(self.inst.uuid) - devobj.allocate(self.inst) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.ALLOCATED) - self.assertEqual(devobj.instance_uuid, - self.inst.uuid) - self.assertEqual(len(self.inst.pci_devices), 1) - # check if the all the dependants are UNAVAILABLE - self.assertTrue(all( - [dev.status == fields.PciDeviceStatus.UNAVAILABLE for - dev in self._fake_get_by_parent_address(None, None, - self.sriov_pf_devices[0].address)])) + self._create_pci_devices() + devobj = self.sriov_pf_devices[0] + devobj.claim(self.inst.uuid) + devobj.allocate(self.inst) + self.assertEqual(devobj.status, + fields.PciDeviceStatus.ALLOCATED) + self.assertEqual(devobj.instance_uuid, + self.inst.uuid) + self.assertEqual(len(self.inst.pci_devices), 1) + # check if the all the dependants are UNAVAILABLE + self.assertTrue(all( + [dev.status == fields.PciDeviceStatus.UNAVAILABLE for + dev in self._get_children_by_parent_address( + self.sriov_pf_devices[0].address)])) def test_allocate_VF(self): self._create_fake_instance() - with mock.patch.object(objects.PciDevice, 'get_by_dev_addr', - side_effect=self._fake_pci_device_get_by_addr): - self._create_pci_devices() - devobj = self.sriov_vf_devices[0] - devobj.claim(self.inst.uuid) - devobj.allocate(self.inst) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.ALLOCATED) - self.assertEqual(devobj.instance_uuid, - self.inst.uuid) - self.assertEqual(len(self.inst.pci_devices), 1) + self._create_pci_devices() + devobj = self.sriov_vf_devices[0] + devobj.claim(self.inst.uuid) + devobj.allocate(self.inst) + self.assertEqual(devobj.status, + fields.PciDeviceStatus.ALLOCATED) + self.assertEqual(devobj.instance_uuid, + self.inst.uuid) + self.assertEqual(len(self.inst.pci_devices), 1) - # check if parent device status has been changed to UNAVAILABLE - parent = self._fake_pci_device_get_by_addr(None, None, - devobj.parent_addr) - self.assertTrue(fields.PciDeviceStatus.UNAVAILABLE, parent.status) + # check if parent device status has been changed to UNAVAILABLE + parent = self._get_parent_by_address(devobj.parent_addr) + self.assertTrue(fields.PciDeviceStatus.UNAVAILABLE, parent.status) def test_claim_PF_fail(self): self._create_fake_instance() - with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address): - self._create_pci_devices() - devobj = self.sriov_pf_devices[0] - self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED + self._create_pci_devices() + devobj = self.sriov_pf_devices[0] + self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED - self.assertRaises(exception.PciDeviceVFInvalidStatus, - devobj.claim, self.inst) + self.assertRaises(exception.PciDeviceVFInvalidStatus, + devobj.claim, self.inst) def test_claim_VF_fail(self): self._create_fake_instance() - with mock.patch.object(objects.PciDevice, 'get_by_dev_addr', - side_effect=self._fake_pci_device_get_by_addr): - self._create_pci_devices() - devobj = self.sriov_vf_devices[0] - parent = self._fake_pci_device_get_by_addr(None, None, - devobj.parent_addr) - parent.status = fields.PciDeviceStatus.CLAIMED + self._create_pci_devices() + devobj = self.sriov_vf_devices[0] + parent = self._get_parent_by_address(devobj.parent_addr) + parent.status = fields.PciDeviceStatus.CLAIMED - self.assertRaises(exception.PciDevicePFInvalidStatus, - devobj.claim, self.inst) + self.assertRaises(exception.PciDevicePFInvalidStatus, + devobj.claim, self.inst) def test_allocate_PF_fail(self): self._create_fake_instance() - with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address): - self._create_pci_devices() - devobj = self.sriov_pf_devices[0] - self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED + self._create_pci_devices() + devobj = self.sriov_pf_devices[0] + self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED - self.assertRaises(exception.PciDeviceVFInvalidStatus, - devobj.allocate, self.inst) + self.assertRaises(exception.PciDeviceVFInvalidStatus, + devobj.allocate, self.inst) def test_allocate_VF_fail(self): self._create_fake_instance() - with mock.patch.object(objects.PciDevice, 'get_by_dev_addr', - side_effect=self._fake_pci_device_get_by_addr): - self._create_pci_devices() - devobj = self.sriov_vf_devices[0] - parent = self._fake_pci_device_get_by_addr(None, None, - devobj.parent_addr) - parent.status = fields.PciDeviceStatus.CLAIMED + self._create_pci_devices() + devobj = self.sriov_vf_devices[0] + parent = self._get_parent_by_address(devobj.parent_addr) + parent.status = fields.PciDeviceStatus.CLAIMED - self.assertRaises(exception.PciDevicePFInvalidStatus, - devobj.allocate, self.inst) + self.assertRaises(exception.PciDevicePFInvalidStatus, + devobj.allocate, self.inst) def test_free_allocated_PF(self): self._create_fake_instance() - with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address): - self._create_pci_devices() - devobj = self.sriov_pf_devices[0] - devobj.claim(self.inst.uuid) - devobj.allocate(self.inst) - devobj.free(self.inst) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.AVAILABLE) - self.assertIsNone(devobj.instance_uuid) - # check if the all the dependants are AVAILABLE - self.assertTrue(all( - [dev.status == fields.PciDeviceStatus.AVAILABLE for - dev in self._fake_get_by_parent_address(None, None, - self.sriov_pf_devices[0].address)])) + self._create_pci_devices() + devobj = self.sriov_pf_devices[0] + devobj.claim(self.inst.uuid) + devobj.allocate(self.inst) + devobj.free(self.inst) + self.assertEqual(devobj.status, + fields.PciDeviceStatus.AVAILABLE) + self.assertIsNone(devobj.instance_uuid) + # check if the all the dependants are AVAILABLE + self.assertTrue(all( + [dev.status == fields.PciDeviceStatus.AVAILABLE for + dev in self._get_children_by_parent_address( + self.sriov_pf_devices[0].address)])) def test_free_allocated_VF(self): self._create_fake_instance() - with test.nested( - mock.patch.object(objects.PciDevice, 'get_by_dev_addr', - side_effect=self._fake_pci_device_get_by_addr), - mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address)): - self._create_pci_devices() - vf = self.sriov_vf_devices[0] - dependents = self._fake_get_by_parent_address(None, None, - vf.parent_addr) - for devobj in dependents: - devobj.claim(self.inst.uuid) - devobj.allocate(self.inst) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.ALLOCATED) - for devobj in dependents[:3]: - devobj.free(self.inst) - # check if parent device status is still UNAVAILABLE - parent = self._fake_pci_device_get_by_addr(None, None, - devobj.parent_addr) - self.assertTrue(fields.PciDeviceStatus.UNAVAILABLE, - parent.status) - for devobj in dependents[3:]: - devobj.free(self.inst) - # check if parent device status is now AVAILABLE - parent = self._fake_pci_device_get_by_addr(None, None, - devobj.parent_addr) - self.assertTrue(fields.PciDeviceStatus.AVAILABLE, - parent.status) + self._create_pci_devices() + vf = self.sriov_vf_devices[0] + dependents = self._get_children_by_parent_address(vf.parent_addr) + for devobj in dependents: + devobj.claim(self.inst.uuid) + devobj.allocate(self.inst) + self.assertEqual(devobj.status, + fields.PciDeviceStatus.ALLOCATED) + for devobj in dependents[:3]: + devobj.free(self.inst) + # check if parent device status is still UNAVAILABLE + parent = self._get_parent_by_address(devobj.parent_addr) + self.assertTrue(fields.PciDeviceStatus.UNAVAILABLE, + parent.status) + for devobj in dependents[3:]: + devobj.free(self.inst) + # check if parent device status is now AVAILABLE + parent = self._get_parent_by_address(devobj.parent_addr) + self.assertTrue(fields.PciDeviceStatus.AVAILABLE, + parent.status) class TestSRIOVPciDeviceListObject(test_objects._LocalTest, diff --git a/nova/tests/unit/pci/test_stats.py b/nova/tests/unit/pci/test_stats.py index bf0c1b0f0d89..3a42d1435a2f 100644 --- a/nova/tests/unit/pci/test_stats.py +++ b/nova/tests/unit/pci/test_stats.py @@ -367,8 +367,9 @@ class PciDeviceVFPFStatsTestCase(test.NoDBTestCase): 'dev_type': fields.PciDeviceType.SRIOV_PF, 'parent_addr': None, 'numa_node': 0} - self.sriov_pf_devices.append(objects.PciDevice.create(None, - pci_dev)) + dev_obj = objects.PciDevice.create(None, pci_dev) + dev_obj.child_devices = [] + self.sriov_pf_devices.append(dev_obj) self.sriov_vf_devices = [] for dev in range(8): @@ -381,95 +382,66 @@ class PciDeviceVFPFStatsTestCase(test.NoDBTestCase): 'dev_type': fields.PciDeviceType.SRIOV_VF, 'parent_addr': '0000:81:00.%d' % int(dev / 4), 'numa_node': 0} - self.sriov_vf_devices.append(objects.PciDevice.create(None, - pci_dev)) + dev_obj = objects.PciDevice.create(None, pci_dev) + dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)] + dev_obj.parent_device.child_devices.append(dev_obj) + self.sriov_vf_devices.append(dev_obj) list(map(self.pci_stats.add_device, self.sriov_pf_devices)) list(map(self.pci_stats.add_device, self.sriov_vf_devices)) - def _fake_get_by_parent_address(self, ctxt, node_id, addr): - vf_devs = [] - for dev in self.sriov_vf_devices: - if dev.parent_addr == addr: - vf_devs.append(dev) - return vf_devs - - def _fake_pci_device_get_by_addr(self, ctxt, id, addr): - for dev in self.sriov_pf_devices: - if dev.address == addr: - return dev - def test_consume_VF_requests(self): - with mock.patch.object(objects.PciDevice, 'get_by_dev_addr', - side_effect=self._fake_pci_device_get_by_addr): - self._create_pci_devices() - pci_requests = [objects.InstancePCIRequest(count=2, - spec=[{'product_id': '1515'}])] - devs = self.pci_stats.consume_requests(pci_requests) - self.assertEqual(2, len(devs)) - self.assertEqual(set(['1515']), - set([dev.product_id for dev in devs])) - free_devs = self.pci_stats.get_free_devs() - # Validate that the parents of these VFs has been removed - # from pools. - for dev in devs: - self.assertTrue(all(dev.parent_addr != free_dev.address - for free_dev in free_devs)) + self._create_pci_devices() + pci_requests = [objects.InstancePCIRequest(count=2, + spec=[{'product_id': '1515'}])] + devs = self.pci_stats.consume_requests(pci_requests) + self.assertEqual(2, len(devs)) + self.assertEqual(set(['1515']), + set([dev.product_id for dev in devs])) + free_devs = self.pci_stats.get_free_devs() + # Validate that the parents of these VFs has been removed + # from pools. + for dev in devs: + self.assertTrue(all(dev.parent_addr != free_dev.address + for free_dev in free_devs)) def test_consume_PF_requests(self): - with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address): - self._create_pci_devices() - pci_requests = [objects.InstancePCIRequest(count=2, - spec=[{'product_id': '1528', - 'dev_type': 'type-PF'}])] - devs = self.pci_stats.consume_requests(pci_requests) - self.assertEqual(2, len(devs)) - self.assertEqual(set(['1528']), - set([dev.product_id for dev in devs])) - free_devs = self.pci_stats.get_free_devs() - # Validate that there are no free devices left, as when allocating - # both available PFs, its VFs should not be available. - self.assertEqual(0, len(free_devs)) + self._create_pci_devices() + pci_requests = [objects.InstancePCIRequest(count=2, + spec=[{'product_id': '1528', + 'dev_type': 'type-PF'}])] + devs = self.pci_stats.consume_requests(pci_requests) + self.assertEqual(2, len(devs)) + self.assertEqual(set(['1528']), + set([dev.product_id for dev in devs])) + free_devs = self.pci_stats.get_free_devs() + # Validate that there are no free devices left, as when allocating + # both available PFs, its VFs should not be available. + self.assertEqual(0, len(free_devs)) def test_consume_VF_and_PF_requests(self): - with test.nested( - mock.patch.object(objects.PciDevice, 'get_by_dev_addr', - side_effect=self._fake_pci_device_get_by_addr), - mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address)): - self._create_pci_devices() - pci_requests = [objects.InstancePCIRequest(count=2, - spec=[{'product_id': '1515'}]), - objects.InstancePCIRequest(count=1, - spec=[{'product_id': '1528', - 'dev_type': 'type-PF'}])] - devs = self.pci_stats.consume_requests(pci_requests) - self.assertEqual(3, len(devs)) - self.assertEqual(set(['1528', '1515']), - set([dev.product_id for dev in devs])) + self._create_pci_devices() + pci_requests = [objects.InstancePCIRequest(count=2, + spec=[{'product_id': '1515'}]), + objects.InstancePCIRequest(count=1, + spec=[{'product_id': '1528', + 'dev_type': 'type-PF'}])] + devs = self.pci_stats.consume_requests(pci_requests) + self.assertEqual(3, len(devs)) + self.assertEqual(set(['1528', '1515']), + set([dev.product_id for dev in devs])) def test_consume_VF_and_PF_requests_failed(self): - with test.nested( - mock.patch.object(objects.PciDevice, 'get_by_dev_addr', - side_effect=self._fake_pci_device_get_by_addr), - mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address)): - self._create_pci_devices() - pci_requests = [objects.InstancePCIRequest(count=5, - spec=[{'product_id': '1515'}]), - objects.InstancePCIRequest(count=1, - spec=[{'product_id': '1528', - 'dev_type': 'type-PF'}])] - self.assertIsNone(self.pci_stats.consume_requests(pci_requests)) + self._create_pci_devices() + pci_requests = [objects.InstancePCIRequest(count=5, + spec=[{'product_id': '1515'}]), + objects.InstancePCIRequest(count=1, + spec=[{'product_id': '1528', + 'dev_type': 'type-PF'}])] + self.assertIsNone(self.pci_stats.consume_requests(pci_requests)) def test_consume_VF_and_PF_same_prodict_id_failed(self): - with test.nested( - mock.patch.object(objects.PciDevice, 'get_by_dev_addr', - side_effect=self._fake_pci_device_get_by_addr), - mock.patch.object(objects.PciDeviceList, 'get_by_parent_address', - side_effect=self._fake_get_by_parent_address)): - self._create_pci_devices(pf_product_id=1515) - pci_requests = [objects.InstancePCIRequest(count=9, - spec=[{'product_id': '1515'}])] - self.assertIsNone(self.pci_stats.consume_requests(pci_requests)) + self._create_pci_devices(pf_product_id=1515) + pci_requests = [objects.InstancePCIRequest(count=9, + spec=[{'product_id': '1515'}])] + self.assertIsNone(self.pci_stats.consume_requests(pci_requests))