diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py index 89164a5d20c2..47b7ac7dcd0b 100644 --- a/nova/network/neutronv2/api.py +++ b/nova/network/neutronv2/api.py @@ -1167,10 +1167,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]) diff --git a/nova/tests/unit/network/test_neutronv2.py b/nova/tests/unit/network/test_neutronv2.py index 1ee80e01ba83..907aba73102a 100644 --- a/nova/tests/unit/network/test_neutronv2.py +++ b/nova/tests/unit/network/test_neutronv2.py @@ -5170,6 +5170,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):