diff --git a/nova/pci/request.py b/nova/pci/request.py index fe12bb50fd..6ef87df551 100644 --- a/nova/pci/request.py +++ b/nova/pci/request.py @@ -121,6 +121,23 @@ _ALIAS_SCHEMA = { } +def _validate_aliases(aliases): + """Checks the parsed aliases for common mistakes and raise easy to parse + error messages + """ + if CONF.filter_scheduler.pci_in_placement: + alias_with_multiple_specs = [ + name for name, spec in aliases.items() if len(spec[1]) > 1] + if alias_with_multiple_specs: + raise exception.PciInvalidAlias( + "The PCI alias(es) %s have multiple specs but " + "[filter_scheduler]pci_in_placement is True. The PCI in " + "Placement feature only supports one spec per alias. You can " + "assign the same resource_class to multiple [pci]device_spec " + "matchers to allow using different devices for the same alias." + % ",".join(alias_with_multiple_specs)) + + def _get_alias_from_config() -> Alias: """Parse and validate PCI aliases from the nova config. @@ -177,6 +194,7 @@ def _get_alias_from_config() -> Alias: except Exception as exc: raise exception.PciInvalidAlias(reason=str(exc)) + _validate_aliases(aliases) return aliases diff --git a/nova/tests/functional/regressions/test_bug_2102038.py b/nova/tests/functional/regressions/test_bug_2102038.py index e867e27c6f..f1f1d13770 100644 --- a/nova/tests/functional/regressions/test_bug_2102038.py +++ b/nova/tests/functional/regressions/test_bug_2102038.py @@ -49,7 +49,11 @@ class MultipleSpecPerAliasWithPCIInPlacementTest( flavor_id=flavor_id, networks=[], ) - # This is bug 2102038 as nova does not handle the internal ValueError - # and therefore returns HTTP 500 instead of returning 400 Bad Request - # with a message pointing to the unsupported alias config. - self.assertEqual(500, exc.response.status_code) + self.assertEqual(400, exc.response.status_code) + self.assertIn( + "The PCI alias(es) a-vf have multiple specs but " + "[filter_scheduler]pci_in_placement is True. The PCI in Placement " + "feature only supports one spec per alias. You can assign the " + "same resource_class to multiple [pci]device_spec matchers to " + "allow using different devices for the same alias.", + exc.response.text) diff --git a/nova/tests/unit/pci/test_request.py b/nova/tests/unit/pci/test_request.py index be9c6be877..fcd14d117c 100644 --- a/nova/tests/unit/pci/test_request.py +++ b/nova/tests/unit/pci/test_request.py @@ -120,6 +120,28 @@ class PciRequestTestCase(test.NoDBTestCase): }]) self.assertEqual(expected_result, result['QuickAssist']) + def test_get_alias_from_config_multispec_rejected_pci_in_placement(self): + _fake_alias = jsonutils.dumps({ + "name": "QuickAssist", + "capability_type": "pci", + "product_id": "4444", + "vendor_id": "8086", + "device_type": "type-PCI", + }) + + self.flags(pci_in_placement=True, group='filter_scheduler') + self.flags(alias=[_fake_alias1, _fake_alias], group='pci') + + ex = self.assertRaises( + exception.PciInvalidAlias, request._get_alias_from_config) + self.assertEqual( + "The PCI alias(es) QuickAssist have multiple specs but " + "[filter_scheduler]pci_in_placement is True. The PCI in Placement " + "feature only supports one spec per alias. You can assign the " + "same resource_class to multiple [pci]device_spec matchers to " + "allow using different devices for the same alias.", + str(ex)) + def _test_get_alias_from_config_invalid(self, alias): self.flags(alias=[alias], group='pci') self.assertRaises(