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
This commit is contained in:
Nikola Dipanov 2016-04-05 19:04:07 +01:00 committed by Sahid Orentino Ferdjaoui
parent c469b8466f
commit 0b85bb4b42
5 changed files with 199 additions and 269 deletions

View File

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

View File

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

View File

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

View File

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

View File

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