Reject devname based device_spec config
We agreed not to support 'devname' based [pci]device_spec configuration in the new PCI Placement tracking code. So this patch adds a check to reject those. blueprint: pci-device-tracking-in-placement Change-Id: Ifa0dd34506ebc25cfe5bafd6952b72b0008fc741
This commit is contained in:
parent
10ba714125
commit
01d7a39e00
|
@ -386,4 +386,12 @@ be added to the resource provider representing the matching PCI devices.
|
||||||
enforce the same rule for the configuration as well and will refuse to
|
enforce the same rule for the configuration as well and will refuse to
|
||||||
start if both the parent PF and its VFs are configured.
|
start if both the parent PF and its VFs are configured.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
While nova supported configuring PCI devices by device name via the
|
||||||
|
``devname`` parameter in :oslo.config:option:`pci.device_spec` in the past,
|
||||||
|
this proved to be problematic as the netdev name of a PCI device could
|
||||||
|
change for multiple reasons during hypervisor reboot. So since nova 26.0.0
|
||||||
|
(Zed) the nova-compute service will refuse to start with such configuration.
|
||||||
|
It is suggested to use the PCI address of the device instead.
|
||||||
|
|
||||||
For deeper technical details please read the `nova specification. <https://specs.openstack.org/openstack/nova-specs/specs/zed/approved/pci-device-tracking-in-placement.html>`_
|
For deeper technical details please read the `nova specification. <https://specs.openstack.org/openstack/nova-specs/specs/zed/approved/pci-device-tracking-in-placement.html>`_
|
||||||
|
|
|
@ -22,6 +22,7 @@ from nova import exception
|
||||||
from nova.i18n import _
|
from nova.i18n import _
|
||||||
from nova.objects import fields
|
from nova.objects import fields
|
||||||
from nova.objects import pci_device
|
from nova.objects import pci_device
|
||||||
|
from nova.pci import devspec
|
||||||
from nova.pci import manager as pci_manager
|
from nova.pci import manager as pci_manager
|
||||||
|
|
||||||
|
|
||||||
|
@ -278,6 +279,18 @@ class PlacementView:
|
||||||
rp.update_provider_tree(provider_tree)
|
rp.update_provider_tree(provider_tree)
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_no_dev_spec_with_devname(dev_specs: ty.List[devspec.PciDeviceSpec]):
|
||||||
|
for dev_spec in dev_specs:
|
||||||
|
if dev_spec.dev_spec_conf.get("devname"):
|
||||||
|
msg = _(
|
||||||
|
"Invalid [pci]device_spec configuration. PCI Placement "
|
||||||
|
"reporting does not support 'devname' based device "
|
||||||
|
"specification but we got %(dev_spec)s. "
|
||||||
|
"Please use PCI address in the configuration instead."
|
||||||
|
) % {"dev_spec": dev_spec.dev_spec_conf}
|
||||||
|
raise exception.PlacementPciException(error=msg)
|
||||||
|
|
||||||
|
|
||||||
def update_provider_tree_for_pci(
|
def update_provider_tree_for_pci(
|
||||||
provider_tree: provider_tree.ProviderTree,
|
provider_tree: provider_tree.ProviderTree,
|
||||||
nodename: str,
|
nodename: str,
|
||||||
|
@ -317,6 +330,8 @@ def update_provider_tree_for_pci(
|
||||||
# If tracking is not enabled we just return without touching anything
|
# If tracking is not enabled we just return without touching anything
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
ensure_no_dev_spec_with_devname(pci_tracker.dev_filter.specs)
|
||||||
|
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
'Collecting PCI inventories and allocations to track them in Placement'
|
'Collecting PCI inventories and allocations to track them in Placement'
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
import copy
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
import typing as ty
|
import typing as ty
|
||||||
|
@ -267,6 +268,10 @@ class WhitelistPciAddress(object):
|
||||||
|
|
||||||
class PciDeviceSpec(PciAddressSpec):
|
class PciDeviceSpec(PciAddressSpec):
|
||||||
def __init__(self, dev_spec: ty.Dict[str, str]) -> None:
|
def __init__(self, dev_spec: ty.Dict[str, str]) -> None:
|
||||||
|
# stored for better error reporting
|
||||||
|
self.dev_spec_conf = copy.deepcopy(dev_spec)
|
||||||
|
# the non tag fields (i.e. address, devname) will be removed by
|
||||||
|
# _init_dev_details
|
||||||
self.tags = dev_spec
|
self.tags = dev_spec
|
||||||
self._init_dev_details()
|
self._init_dev_details()
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,12 @@ class PlacementPCIReportingTests(test_pci_sriov_servers._PCIServersTestBase):
|
||||||
# These tests should not depend on the host's sysfs
|
# These tests should not depend on the host's sysfs
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.MockPatch('nova.pci.utils.is_physical_function'))
|
fixtures.MockPatch('nova.pci.utils.is_physical_function'))
|
||||||
|
self.useFixture(
|
||||||
|
fixtures.MockPatch(
|
||||||
|
'nova.pci.utils.get_function_by_ifname',
|
||||||
|
return_value=(None, False)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _to_device_spec_conf(spec_list):
|
def _to_device_spec_conf(spec_list):
|
||||||
|
@ -309,3 +315,26 @@ class PlacementPCIReportingTests(test_pci_sriov_servers._PCIServersTestBase):
|
||||||
inventories={},
|
inventories={},
|
||||||
traits={},
|
traits={},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_devname_based_dev_spec_rejected(self):
|
||||||
|
device_spec = self._to_device_spec_conf(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"devname": "eth0",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.flags(group='pci', device_spec=device_spec)
|
||||||
|
|
||||||
|
ex = self.assertRaises(
|
||||||
|
exception.PlacementPciException,
|
||||||
|
self.start_compute,
|
||||||
|
hostname="compute1",
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
" Invalid [pci]device_spec configuration. PCI Placement reporting "
|
||||||
|
"does not support 'devname' based device specification but we got "
|
||||||
|
"{'devname': 'eth0'}. Please use PCI address in the configuration "
|
||||||
|
"instead.",
|
||||||
|
str(ex)
|
||||||
|
)
|
||||||
|
|
|
@ -50,6 +50,7 @@ class TestTranslator(test.NoDBTestCase):
|
||||||
)
|
)
|
||||||
# So we have a device but there is no spec for it
|
# So we have a device but there is no spec for it
|
||||||
pci_tracker.dev_filter.get_devspec = mock.Mock(return_value=None)
|
pci_tracker.dev_filter.get_devspec = mock.Mock(return_value=None)
|
||||||
|
pci_tracker.dev_filter.specs = []
|
||||||
# we expect that the provider_tree is not touched as the device without
|
# we expect that the provider_tree is not touched as the device without
|
||||||
# spec is skipped, we assert that with the NonCallableMock
|
# spec is skipped, we assert that with the NonCallableMock
|
||||||
provider_tree = mock.NonCallableMock()
|
provider_tree = mock.NonCallableMock()
|
||||||
|
|
Loading…
Reference in New Issue