Handle IndexError in _populate_neutron_binding_profile

This fixes the code that was blindly pop'ing an entry
from an empty list of PCI devices claimed by the instance.
It's not exactly clear how we can get into this situation,
presumably there was a failure in the actual PCI device
claim logic in the ResourceTracker - maybe related to the
configured PCI passthrough whitelist. Regardless, we should
handle the empty PCI device list in this method and raise
an appropriate exception to fail the build on this host.

Change-Id: I401bb74cf6e17c2b72cc62bf8ec03ec58238c44a
Closes-Bug: #1795064
(cherry picked from commit 035708c37d)
This commit is contained in:
Matt Riedemann 2018-10-03 12:54:53 -04:00
parent d1243fe398
commit dfbcf5e40b
2 changed files with 30 additions and 2 deletions

View File

@ -1398,10 +1398,25 @@ class API(base_api.NetworkAPI):
"""Populate neutron binding:profile.
Populate it with SR-IOV related information
:raises PciDeviceNotFound: If a claimed PCI device for the given
pci_request_id cannot be found on the instance.
"""
if pci_request_id:
pci_dev = pci_manager.get_instance_pci_devs(
instance, pci_request_id).pop()
pci_devices = pci_manager.get_instance_pci_devs(
instance, pci_request_id)
if not pci_devices:
# The pci_request_id likely won't mean much except for tracing
# through the logs since it is generated per request.
LOG.error('Unable to find PCI device using PCI request ID in '
'list of claimed instance PCI devices: %s. Is the '
'[pci]/passthrough_whitelist configuration correct?',
# Convert to a primitive list to stringify it.
list(instance.pci_devices), instance=instance)
raise exception.PciDeviceNotFound(
_('PCI device not found for request ID %s.') %
pci_request_id)
pci_dev = pci_devices.pop()
if port_req_body['port'].get(BINDING_PROFILE) is None:
port_req_body['port'][BINDING_PROFILE] = {}
profile = copy.deepcopy(port_req_body['port'][BINDING_PROFILE])

View File

@ -5479,6 +5479,19 @@ class TestNeutronv2Portbinding(TestNeutronv2Base):
exception.PciDeviceNotFound, api._populate_neutron_binding_profile,
instance, pci_req_id, port_req_body)
@mock.patch.object(pci_manager, 'get_instance_pci_devs', return_value=[])
def test_populate_neutron_binding_profile_pci_dev_not_found(
self, mock_get_instance_pci_devs):
api = neutronapi.API()
instance = objects.Instance(pci_devices=objects.PciDeviceList())
port_req_body = {'port': {}}
pci_req_id = 'my_req_id'
self.assertRaises(exception.PciDeviceNotFound,
api._populate_neutron_binding_profile,
instance, pci_req_id, port_req_body)
mock_get_instance_pci_devs.assert_called_once_with(
instance, pci_req_id)
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
def test_pci_parse_whitelist_called_once(self,
mock_get_instance_pci_devs):