diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py index 391ea8fb37bc..46bbfeebc621 100644 --- a/nova/network/neutronv2/api.py +++ b/nova/network/neutronv2/api.py @@ -1060,10 +1060,26 @@ 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( + _LE('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() profile = self._get_pci_device_profile(pci_dev) port_req_body['port'][BINDING_PROFILE] = profile diff --git a/nova/tests/unit/network/test_neutronv2.py b/nova/tests/unit/network/test_neutronv2.py index 0e6cc728ab7a..d9a77919b003 100644 --- a/nova/tests/unit/network/test_neutronv2.py +++ b/nova/tests/unit/network/test_neutronv2.py @@ -5059,6 +5059,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):