591 lines
24 KiB
Diff
591 lines
24 KiB
Diff
|
From 9383855c8a15e6d7c4033cd8d7ae8310b462d166 Mon Sep 17 00:00:00 2001
|
||
|
From: Vojtech Trefny <vtrefny@redhat.com>
|
||
|
Date: Tue, 18 Oct 2022 10:38:00 +0200
|
||
|
Subject: [PATCH 1/3] Add a basic support for NVMe and NVMe Fabrics devices
|
||
|
|
||
|
This adds two new device types: NVMeNamespaceDevice and
|
||
|
NVMeFabricsNamespaceDevice mostly to allow to differentiate
|
||
|
between "local" and "remote" NVMe devices. The new libblockdev
|
||
|
NVMe plugin is required for full functionality.
|
||
|
---
|
||
|
blivet/__init__.py | 6 +-
|
||
|
blivet/devices/__init__.py | 2 +-
|
||
|
blivet/devices/disk.py | 101 ++++++++++++++++++++++
|
||
|
blivet/devices/lib.py | 1 +
|
||
|
blivet/populator/helpers/__init__.py | 2 +-
|
||
|
blivet/populator/helpers/disk.py | 64 ++++++++++++++
|
||
|
blivet/udev.py | 33 +++++++
|
||
|
blivet/util.py | 9 ++
|
||
|
tests/unit_tests/populator_test.py | 124 +++++++++++++++++++++++++++
|
||
|
9 files changed, 339 insertions(+), 3 deletions(-)
|
||
|
|
||
|
diff --git a/blivet/__init__.py b/blivet/__init__.py
|
||
|
index bbc7ea3a..3b9e659e 100644
|
||
|
--- a/blivet/__init__.py
|
||
|
+++ b/blivet/__init__.py
|
||
|
@@ -67,6 +67,10 @@ if arch.is_s390():
|
||
|
else:
|
||
|
_REQUESTED_PLUGIN_NAMES = set(("swap", "crypto", "loop", "mdraid", "mpath", "dm", "nvdimm"))
|
||
|
|
||
|
+# nvme plugin is not generally available
|
||
|
+if hasattr(blockdev.Plugin, "NVME"):
|
||
|
+ _REQUESTED_PLUGIN_NAMES.add("nvme")
|
||
|
+
|
||
|
_requested_plugins = blockdev.plugin_specs_from_names(_REQUESTED_PLUGIN_NAMES)
|
||
|
# XXX force non-dbus LVM plugin
|
||
|
lvm_plugin = blockdev.PluginSpec()
|
||
|
@@ -74,7 +78,7 @@ lvm_plugin.name = blockdev.Plugin.LVM
|
||
|
lvm_plugin.so_name = "libbd_lvm.so.2"
|
||
|
_requested_plugins.append(lvm_plugin)
|
||
|
try:
|
||
|
- # do not check for dependencies during libblockdev initializtion, do runtime
|
||
|
+ # do not check for dependencies during libblockdev initialization, do runtime
|
||
|
# checks instead
|
||
|
blockdev.switch_init_checks(False)
|
||
|
succ_, avail_plugs = blockdev.try_reinit(require_plugins=_requested_plugins, reload=False, log_func=log_bd_message)
|
||
|
diff --git a/blivet/devices/__init__.py b/blivet/devices/__init__.py
|
||
|
index 8bb0a979..4d16466e 100644
|
||
|
--- a/blivet/devices/__init__.py
|
||
|
+++ b/blivet/devices/__init__.py
|
||
|
@@ -22,7 +22,7 @@
|
||
|
from .lib import device_path_to_name, device_name_to_disk_by_path, ParentList
|
||
|
from .device import Device
|
||
|
from .storage import StorageDevice
|
||
|
-from .disk import DiskDevice, DiskFile, DMRaidArrayDevice, MultipathDevice, iScsiDiskDevice, FcoeDiskDevice, DASDDevice, ZFCPDiskDevice, NVDIMMNamespaceDevice
|
||
|
+from .disk import DiskDevice, DiskFile, DMRaidArrayDevice, MultipathDevice, iScsiDiskDevice, FcoeDiskDevice, DASDDevice, ZFCPDiskDevice, NVDIMMNamespaceDevice, NVMeNamespaceDevice, NVMeFabricsNamespaceDevice
|
||
|
from .partition import PartitionDevice
|
||
|
from .dm import DMDevice, DMLinearDevice, DMCryptDevice, DMIntegrityDevice, DM_MAJORS
|
||
|
from .luks import LUKSDevice, IntegrityDevice
|
||
|
diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py
|
||
|
index bc4a1b5e..b5e25939 100644
|
||
|
--- a/blivet/devices/disk.py
|
||
|
+++ b/blivet/devices/disk.py
|
||
|
@@ -22,10 +22,13 @@
|
||
|
|
||
|
import gi
|
||
|
gi.require_version("BlockDev", "2.0")
|
||
|
+gi.require_version("GLib", "2.0")
|
||
|
|
||
|
from gi.repository import BlockDev as blockdev
|
||
|
+from gi.repository import GLib
|
||
|
|
||
|
import os
|
||
|
+from collections import namedtuple
|
||
|
|
||
|
from .. import errors
|
||
|
from .. import util
|
||
|
@@ -725,3 +728,101 @@ class NVDIMMNamespaceDevice(DiskDevice):
|
||
|
@property
|
||
|
def sector_size(self):
|
||
|
return self._sector_size
|
||
|
+
|
||
|
+
|
||
|
+NVMeController = namedtuple("NVMeController", ["name", "serial", "nvme_ver", "id", "subsysnqn"])
|
||
|
+
|
||
|
+
|
||
|
+class NVMeNamespaceDevice(DiskDevice):
|
||
|
+
|
||
|
+ """ NVMe namespace """
|
||
|
+ _type = "nvme"
|
||
|
+ _packages = ["nvme-cli"]
|
||
|
+
|
||
|
+ def __init__(self, device, **kwargs):
|
||
|
+ """
|
||
|
+ :param name: the device name (generally a device node's basename)
|
||
|
+ :type name: str
|
||
|
+ :keyword exists: does this device exist?
|
||
|
+ :type exists: bool
|
||
|
+ :keyword size: the device's size
|
||
|
+ :type size: :class:`~.size.Size`
|
||
|
+ :keyword parents: a list of parent devices
|
||
|
+ :type parents: list of :class:`StorageDevice`
|
||
|
+ :keyword format: this device's formatting
|
||
|
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
|
||
|
+ :keyword nsid: namespace ID
|
||
|
+ :type nsid: int
|
||
|
+ """
|
||
|
+ self.nsid = kwargs.pop("nsid", 0)
|
||
|
+
|
||
|
+ DiskDevice.__init__(self, device, **kwargs)
|
||
|
+
|
||
|
+ self._clear_local_tags()
|
||
|
+ self.tags.add(Tags.local)
|
||
|
+ self.tags.add(Tags.nvme)
|
||
|
+
|
||
|
+ self._controllers = None
|
||
|
+
|
||
|
+ @property
|
||
|
+ def controllers(self):
|
||
|
+ if self._controllers is not None:
|
||
|
+ return self._controllers
|
||
|
+
|
||
|
+ self._controllers = []
|
||
|
+ if not hasattr(blockdev.Plugin, "NVME"):
|
||
|
+ # the nvme plugin is not generally available
|
||
|
+ log.debug("Failed to get controllers for %s: libblockdev NVME plugin is not available", self.name)
|
||
|
+ return self._controllers
|
||
|
+
|
||
|
+ try:
|
||
|
+ controllers = blockdev.nvme_find_ctrls_for_ns(self.sysfs_path)
|
||
|
+ except GLib.GError as err:
|
||
|
+ log.debug("Failed to get controllers for %s: %s", self.name, str(err))
|
||
|
+ return self._controllers
|
||
|
+
|
||
|
+ for controller in controllers:
|
||
|
+ try:
|
||
|
+ cpath = util.get_path_by_sysfs_path(controller, "char")
|
||
|
+ except RuntimeError as err:
|
||
|
+ log.debug("Failed to find controller %s: %s", controller, str(err))
|
||
|
+ continue
|
||
|
+ try:
|
||
|
+ cinfo = blockdev.nvme_get_controller_info(cpath)
|
||
|
+ except GLib.GError as err:
|
||
|
+ log.debug("Failed to get controller info for %s: %s", cpath, str(err))
|
||
|
+ continue
|
||
|
+ self._controllers.append(NVMeController(name=os.path.basename(cpath),
|
||
|
+ serial=cinfo.serial_number,
|
||
|
+ nvme_ver=cinfo.nvme_ver,
|
||
|
+ id=cinfo.ctrl_id,
|
||
|
+ subsysnqn=cinfo.subsysnqn))
|
||
|
+
|
||
|
+ return self._controllers
|
||
|
+
|
||
|
+
|
||
|
+class NVMeFabricsNamespaceDevice(NVMeNamespaceDevice, NetworkStorageDevice):
|
||
|
+
|
||
|
+ """ NVMe fabrics namespace """
|
||
|
+ _type = "nvme-fabrics"
|
||
|
+ _packages = ["nvme-cli"]
|
||
|
+
|
||
|
+ def __init__(self, device, **kwargs):
|
||
|
+ """
|
||
|
+ :param name: the device name (generally a device node's basename)
|
||
|
+ :type name: str
|
||
|
+ :keyword exists: does this device exist?
|
||
|
+ :type exists: bool
|
||
|
+ :keyword size: the device's size
|
||
|
+ :type size: :class:`~.size.Size`
|
||
|
+ :keyword parents: a list of parent devices
|
||
|
+ :type parents: list of :class:`StorageDevice`
|
||
|
+ :keyword format: this device's formatting
|
||
|
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
|
||
|
+ """
|
||
|
+ NVMeNamespaceDevice.__init__(self, device, **kwargs)
|
||
|
+ NetworkStorageDevice.__init__(self)
|
||
|
+
|
||
|
+ self._clear_local_tags()
|
||
|
+ self.tags.add(Tags.remote)
|
||
|
+ self.tags.add(Tags.nvme)
|
||
|
diff --git a/blivet/devices/lib.py b/blivet/devices/lib.py
|
||
|
index 1bda0bab..b3c4c5b0 100644
|
||
|
--- a/blivet/devices/lib.py
|
||
|
+++ b/blivet/devices/lib.py
|
||
|
@@ -32,6 +32,7 @@ class Tags(str, Enum):
|
||
|
"""Tags that describe various classes of disk."""
|
||
|
local = 'local'
|
||
|
nvdimm = 'nvdimm'
|
||
|
+ nvme = 'nvme'
|
||
|
remote = 'remote'
|
||
|
removable = 'removable'
|
||
|
ssd = 'ssd'
|
||
|
diff --git a/blivet/populator/helpers/__init__.py b/blivet/populator/helpers/__init__.py
|
||
|
index c5ac412f..50ab4de8 100644
|
||
|
--- a/blivet/populator/helpers/__init__.py
|
||
|
+++ b/blivet/populator/helpers/__init__.py
|
||
|
@@ -6,7 +6,7 @@ from .formatpopulator import FormatPopulator
|
||
|
|
||
|
from .btrfs import BTRFSFormatPopulator
|
||
|
from .boot import AppleBootFormatPopulator, EFIFormatPopulator, MacEFIFormatPopulator
|
||
|
-from .disk import DiskDevicePopulator, iScsiDevicePopulator, FCoEDevicePopulator, MDBiosRaidDevicePopulator, DASDDevicePopulator, ZFCPDevicePopulator, NVDIMMNamespaceDevicePopulator
|
||
|
+from .disk import DiskDevicePopulator, iScsiDevicePopulator, FCoEDevicePopulator, MDBiosRaidDevicePopulator, DASDDevicePopulator, ZFCPDevicePopulator, NVDIMMNamespaceDevicePopulator, NVMeNamespaceDevicePopulator, NVMeFabricsNamespaceDevicePopulator
|
||
|
from .disklabel import DiskLabelFormatPopulator
|
||
|
from .dm import DMDevicePopulator
|
||
|
from .dmraid import DMRaidFormatPopulator
|
||
|
diff --git a/blivet/populator/helpers/disk.py b/blivet/populator/helpers/disk.py
|
||
|
index 9db7b810..9ed1eebe 100644
|
||
|
--- a/blivet/populator/helpers/disk.py
|
||
|
+++ b/blivet/populator/helpers/disk.py
|
||
|
@@ -22,13 +22,16 @@
|
||
|
|
||
|
import gi
|
||
|
gi.require_version("BlockDev", "2.0")
|
||
|
+gi.require_version("GLib", "2.0")
|
||
|
|
||
|
from gi.repository import BlockDev as blockdev
|
||
|
+from gi.repository import GLib
|
||
|
|
||
|
from ... import udev
|
||
|
from ... import util
|
||
|
from ...devices import DASDDevice, DiskDevice, FcoeDiskDevice, iScsiDiskDevice
|
||
|
from ...devices import MDBiosRaidArrayDevice, ZFCPDiskDevice, NVDIMMNamespaceDevice
|
||
|
+from ...devices import NVMeNamespaceDevice, NVMeFabricsNamespaceDevice
|
||
|
from ...devices import device_path_to_name
|
||
|
from ...storage_log import log_method_call
|
||
|
from .devicepopulator import DevicePopulator
|
||
|
@@ -251,3 +254,64 @@ class NVDIMMNamespaceDevicePopulator(DiskDevicePopulator):
|
||
|
|
||
|
log.info("%s is an NVDIMM namespace device", udev.device_get_name(self.data))
|
||
|
return kwargs
|
||
|
+
|
||
|
+
|
||
|
+class NVMeNamespaceDevicePopulator(DiskDevicePopulator):
|
||
|
+ priority = 20
|
||
|
+
|
||
|
+ _device_class = NVMeNamespaceDevice
|
||
|
+
|
||
|
+ @classmethod
|
||
|
+ def match(cls, data):
|
||
|
+ return (super(NVMeNamespaceDevicePopulator, NVMeNamespaceDevicePopulator).match(data) and
|
||
|
+ udev.device_is_nvme_namespace(data) and not udev.device_is_nvme_fabrics(data))
|
||
|
+
|
||
|
+ def _get_kwargs(self):
|
||
|
+ kwargs = super(NVMeNamespaceDevicePopulator, self)._get_kwargs()
|
||
|
+
|
||
|
+ log.info("%s is an NVMe local namespace device", udev.device_get_name(self.data))
|
||
|
+
|
||
|
+ if not hasattr(blockdev.Plugin, "NVME"):
|
||
|
+ # the nvme plugin is not generally available
|
||
|
+ return kwargs
|
||
|
+
|
||
|
+ path = udev.device_get_devname(self.data)
|
||
|
+ try:
|
||
|
+ ninfo = blockdev.nvme_get_namespace_info(path)
|
||
|
+ except GLib.GError as err:
|
||
|
+ log.debug("Failed to get namespace info for %s: %s", path, str(err))
|
||
|
+ else:
|
||
|
+ kwargs["nsid"] = ninfo.nsid
|
||
|
+
|
||
|
+ log.info("%s is an NVMe local namespace device", udev.device_get_name(self.data))
|
||
|
+ return kwargs
|
||
|
+
|
||
|
+
|
||
|
+class NVMeFabricsNamespaceDevicePopulator(DiskDevicePopulator):
|
||
|
+ priority = 20
|
||
|
+
|
||
|
+ _device_class = NVMeFabricsNamespaceDevice
|
||
|
+
|
||
|
+ @classmethod
|
||
|
+ def match(cls, data):
|
||
|
+ return (super(NVMeFabricsNamespaceDevicePopulator, NVMeFabricsNamespaceDevicePopulator).match(data) and
|
||
|
+ udev.device_is_nvme_namespace(data) and udev.device_is_nvme_fabrics(data))
|
||
|
+
|
||
|
+ def _get_kwargs(self):
|
||
|
+ kwargs = super(NVMeFabricsNamespaceDevicePopulator, self)._get_kwargs()
|
||
|
+
|
||
|
+ log.info("%s is an NVMe fabrics namespace device", udev.device_get_name(self.data))
|
||
|
+
|
||
|
+ if not hasattr(blockdev.Plugin, "NVME"):
|
||
|
+ # the nvme plugin is not generally available
|
||
|
+ return kwargs
|
||
|
+
|
||
|
+ path = udev.device_get_devname(self.data)
|
||
|
+ try:
|
||
|
+ ninfo = blockdev.nvme_get_namespace_info(path)
|
||
|
+ except GLib.GError as err:
|
||
|
+ log.debug("Failed to get namespace info for %s: %s", path, str(err))
|
||
|
+ else:
|
||
|
+ kwargs["nsid"] = ninfo.nsid
|
||
|
+
|
||
|
+ return kwargs
|
||
|
diff --git a/blivet/udev.py b/blivet/udev.py
|
||
|
index efbc53d6..533a1edc 100644
|
||
|
--- a/blivet/udev.py
|
||
|
+++ b/blivet/udev.py
|
||
|
@@ -1023,6 +1023,39 @@ def device_is_nvdimm_namespace(info):
|
||
|
return ninfo is not None
|
||
|
|
||
|
|
||
|
+def device_is_nvme_namespace(info):
|
||
|
+ if info.get("DEVTYPE") != "disk":
|
||
|
+ return False
|
||
|
+
|
||
|
+ if not info.get("SYS_PATH"):
|
||
|
+ return False
|
||
|
+
|
||
|
+ device = pyudev.Devices.from_sys_path(global_udev, info.get("SYS_PATH"))
|
||
|
+ while device:
|
||
|
+ if device.subsystem and device.subsystem.startswith("nvme"):
|
||
|
+ return True
|
||
|
+ device = device.parent
|
||
|
+
|
||
|
+ return False
|
||
|
+
|
||
|
+
|
||
|
+def device_is_nvme_fabrics(info):
|
||
|
+ if not device_is_nvme_namespace(info):
|
||
|
+ return False
|
||
|
+
|
||
|
+ if not hasattr(blockdev.Plugin, "NVME") or not blockdev.is_plugin_available(blockdev.Plugin.NVME): # pylint: disable=no-member
|
||
|
+ # nvme plugin is not available -- even if this is an nvme fabrics device we
|
||
|
+ # don't have tools to work with it, so we should pretend it's just a normal nvme
|
||
|
+ return False
|
||
|
+
|
||
|
+ controllers = blockdev.nvme_find_ctrls_for_ns(info.get("SYS_PATH", ""))
|
||
|
+ if not controllers:
|
||
|
+ return False
|
||
|
+
|
||
|
+ transport = util.get_sysfs_attr(controllers[0], "transport")
|
||
|
+ return transport in ("rdma", "fc", "tcp", "loop")
|
||
|
+
|
||
|
+
|
||
|
def device_is_hidden(info):
|
||
|
sysfs_path = device_get_sysfs_path(info)
|
||
|
hidden = util.get_sysfs_attr(sysfs_path, "hidden")
|
||
|
diff --git a/blivet/util.py b/blivet/util.py
|
||
|
index 0e578aea..3040ee5a 100644
|
||
|
--- a/blivet/util.py
|
||
|
+++ b/blivet/util.py
|
||
|
@@ -432,6 +432,15 @@ def get_sysfs_path_by_name(dev_node, class_name="block"):
|
||
|
"for '%s' (it is not at '%s')" % (dev_node, dev_path))
|
||
|
|
||
|
|
||
|
+def get_path_by_sysfs_path(sysfs_path, dev_type="block"):
|
||
|
+ """ Return device path for a given device sysfs path. """
|
||
|
+
|
||
|
+ dev = get_sysfs_attr(sysfs_path, "dev")
|
||
|
+ if not dev or not os.path.exists("/dev/%s/%s" % (dev_type, dev)):
|
||
|
+ raise RuntimeError("get_path_by_sysfs_path: Could not find device for %s" % sysfs_path)
|
||
|
+ return os.path.realpath("/dev/%s/%s" % (dev_type, dev))
|
||
|
+
|
||
|
+
|
||
|
def get_cow_sysfs_path(dev_path, dev_sysfsPath):
|
||
|
""" Return sysfs path of cow device for a given device.
|
||
|
"""
|
||
|
diff --git a/tests/unit_tests/populator_test.py b/tests/unit_tests/populator_test.py
|
||
|
index 369fe878..1ee29b57 100644
|
||
|
--- a/tests/unit_tests/populator_test.py
|
||
|
+++ b/tests/unit_tests/populator_test.py
|
||
|
@@ -13,6 +13,7 @@ from gi.repository import BlockDev as blockdev
|
||
|
from blivet.devices import DiskDevice, DMDevice, FileDevice, LoopDevice
|
||
|
from blivet.devices import MDRaidArrayDevice, MultipathDevice, OpticalDevice
|
||
|
from blivet.devices import PartitionDevice, StorageDevice, NVDIMMNamespaceDevice
|
||
|
+from blivet.devices import NVMeNamespaceDevice, NVMeFabricsNamespaceDevice
|
||
|
from blivet.devicelibs import lvm
|
||
|
from blivet.devicetree import DeviceTree
|
||
|
from blivet.formats import get_device_format_class, get_format, DeviceFormat
|
||
|
@@ -21,6 +22,7 @@ from blivet.populator.helpers import DiskDevicePopulator, DMDevicePopulator, Loo
|
||
|
from blivet.populator.helpers import LVMDevicePopulator, MDDevicePopulator, MultipathDevicePopulator
|
||
|
from blivet.populator.helpers import OpticalDevicePopulator, PartitionDevicePopulator
|
||
|
from blivet.populator.helpers import LVMFormatPopulator, MDFormatPopulator, NVDIMMNamespaceDevicePopulator
|
||
|
+from blivet.populator.helpers import NVMeNamespaceDevicePopulator, NVMeFabricsNamespaceDevicePopulator
|
||
|
from blivet.populator.helpers import get_format_helper, get_device_helper
|
||
|
from blivet.populator.helpers.boot import AppleBootFormatPopulator, EFIFormatPopulator, MacEFIFormatPopulator
|
||
|
from blivet.populator.helpers.formatpopulator import FormatPopulator
|
||
|
@@ -591,6 +593,128 @@ class NVDIMMNamespaceDevicePopulatorTestCase(PopulatorHelperTestCase):
|
||
|
self.assertTrue(device in devicetree.devices)
|
||
|
|
||
|
|
||
|
+class NVMeNamespaceDevicePopulatorTestCase(PopulatorHelperTestCase):
|
||
|
+ helper_class = NVMeNamespaceDevicePopulator
|
||
|
+
|
||
|
+ @patch("os.path.join")
|
||
|
+ @patch("blivet.udev.device_is_cdrom", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_dm", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_loop", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_md", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_partition", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_disk", return_value=True)
|
||
|
+ @patch("blivet.udev.device_is_nvme_fabrics", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_nvme_namespace", return_value=True)
|
||
|
+ def test_match(self, *args):
|
||
|
+ """Test matching of NVMe namespace device populator."""
|
||
|
+ device_is_nvme_namespace = args[0]
|
||
|
+ self.assertTrue(self.helper_class.match(None))
|
||
|
+ device_is_nvme_namespace.return_value = False
|
||
|
+ self.assertFalse(self.helper_class.match(None))
|
||
|
+
|
||
|
+ @patch("os.path.join")
|
||
|
+ @patch("blivet.udev.device_is_cdrom", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_dm", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_loop", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_md", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_partition", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_disk", return_value=True)
|
||
|
+ @patch("blivet.udev.device_is_nvme_fabrics", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_nvme_namespace", return_value=True)
|
||
|
+ def test_get_helper(self, *args):
|
||
|
+ """Test get_device_helper for NVMe namespaces."""
|
||
|
+ device_is_nvme_namespace = args[0]
|
||
|
+ data = {}
|
||
|
+ self.assertEqual(get_device_helper(data), self.helper_class)
|
||
|
+
|
||
|
+ # verify that setting one of the required True return values to False prevents success
|
||
|
+ device_is_nvme_namespace.return_value = False
|
||
|
+ self.assertNotEqual(get_device_helper(data), self.helper_class)
|
||
|
+ device_is_nvme_namespace.return_value = True
|
||
|
+
|
||
|
+ @patch("blivet.udev.device_get_name")
|
||
|
+ def test_run(self, *args):
|
||
|
+ """Test disk device populator."""
|
||
|
+ device_get_name = args[0]
|
||
|
+
|
||
|
+ devicetree = DeviceTree()
|
||
|
+
|
||
|
+ # set up some fake udev data to verify handling of specific entries
|
||
|
+ data = {'SYS_PATH': 'dummy', 'DEVNAME': 'dummy', 'ID_PATH': 'dummy'}
|
||
|
+
|
||
|
+ device_name = "nop"
|
||
|
+ device_get_name.return_value = device_name
|
||
|
+ helper = self.helper_class(devicetree, data)
|
||
|
+
|
||
|
+ device = helper.run()
|
||
|
+
|
||
|
+ self.assertIsInstance(device, NVMeNamespaceDevice)
|
||
|
+ self.assertTrue(device.exists)
|
||
|
+ self.assertTrue(device.is_disk)
|
||
|
+ self.assertTrue(device in devicetree.devices)
|
||
|
+
|
||
|
+
|
||
|
+class NVMeFabricsNamespaceDevicePopulatorTestCase(PopulatorHelperTestCase):
|
||
|
+ helper_class = NVMeFabricsNamespaceDevicePopulator
|
||
|
+
|
||
|
+ @patch("os.path.join")
|
||
|
+ @patch("blivet.udev.device_is_cdrom", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_dm", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_loop", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_md", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_partition", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_disk", return_value=True)
|
||
|
+ @patch("blivet.udev.device_is_nvme_namespace", return_value=True)
|
||
|
+ @patch("blivet.udev.device_is_nvme_fabrics", return_value=True)
|
||
|
+ def test_match(self, *args):
|
||
|
+ """Test matching of NVMe namespace device populator."""
|
||
|
+ device_is_nvme_fabrics = args[0]
|
||
|
+ self.assertTrue(self.helper_class.match(None))
|
||
|
+ device_is_nvme_fabrics.return_value = False
|
||
|
+ self.assertFalse(self.helper_class.match(None))
|
||
|
+
|
||
|
+ @patch("os.path.join")
|
||
|
+ @patch("blivet.udev.device_is_cdrom", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_dm", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_loop", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_md", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_partition", return_value=False)
|
||
|
+ @patch("blivet.udev.device_is_disk", return_value=True)
|
||
|
+ @patch("blivet.udev.device_is_nvme_namespace", return_value=True)
|
||
|
+ @patch("blivet.udev.device_is_nvme_fabrics", return_value=True)
|
||
|
+ def test_get_helper(self, *args):
|
||
|
+ """Test get_device_helper for NVMe namespaces."""
|
||
|
+ device_is_nvme_fabrics = args[0]
|
||
|
+ data = {}
|
||
|
+ self.assertEqual(get_device_helper(data), self.helper_class)
|
||
|
+
|
||
|
+ # verify that setting one of the required True return values to False prevents success
|
||
|
+ device_is_nvme_fabrics.return_value = False
|
||
|
+ self.assertNotEqual(get_device_helper(data), self.helper_class)
|
||
|
+ device_is_nvme_fabrics.return_value = True
|
||
|
+
|
||
|
+ @patch("blivet.udev.device_get_name")
|
||
|
+ def test_run(self, *args):
|
||
|
+ """Test disk device populator."""
|
||
|
+ device_get_name = args[0]
|
||
|
+
|
||
|
+ devicetree = DeviceTree()
|
||
|
+
|
||
|
+ # set up some fake udev data to verify handling of specific entries
|
||
|
+ data = {'SYS_PATH': 'dummy', 'DEVNAME': 'dummy', 'ID_PATH': 'dummy'}
|
||
|
+
|
||
|
+ device_name = "nop"
|
||
|
+ device_get_name.return_value = device_name
|
||
|
+ helper = self.helper_class(devicetree, data)
|
||
|
+
|
||
|
+ device = helper.run()
|
||
|
+
|
||
|
+ self.assertIsInstance(device, NVMeFabricsNamespaceDevice)
|
||
|
+ self.assertTrue(device.exists)
|
||
|
+ self.assertTrue(device.is_disk)
|
||
|
+ self.assertTrue(device in devicetree.devices)
|
||
|
+
|
||
|
+
|
||
|
class MDDevicePopulatorTestCase(PopulatorHelperTestCase):
|
||
|
helper_class = MDDevicePopulator
|
||
|
|
||
|
--
|
||
|
2.38.1
|
||
|
|
||
|
|
||
|
From af6ad7ff2f08180672690910d453158bcd463936 Mon Sep 17 00:00:00 2001
|
||
|
From: Vojtech Trefny <vtrefny@redhat.com>
|
||
|
Date: Fri, 2 Dec 2022 12:20:47 +0100
|
||
|
Subject: [PATCH 2/3] Add transport and address to NVMeController info
|
||
|
|
||
|
---
|
||
|
blivet/devices/disk.py | 9 +++++++--
|
||
|
1 file changed, 7 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py
|
||
|
index b5e25939..796b5b03 100644
|
||
|
--- a/blivet/devices/disk.py
|
||
|
+++ b/blivet/devices/disk.py
|
||
|
@@ -730,7 +730,8 @@ class NVDIMMNamespaceDevice(DiskDevice):
|
||
|
return self._sector_size
|
||
|
|
||
|
|
||
|
-NVMeController = namedtuple("NVMeController", ["name", "serial", "nvme_ver", "id", "subsysnqn"])
|
||
|
+NVMeController = namedtuple("NVMeController", ["name", "serial", "nvme_ver", "id", "subsysnqn",
|
||
|
+ "transport", "transport_address"])
|
||
|
|
||
|
|
||
|
class NVMeNamespaceDevice(DiskDevice):
|
||
|
@@ -792,11 +793,15 @@ class NVMeNamespaceDevice(DiskDevice):
|
||
|
except GLib.GError as err:
|
||
|
log.debug("Failed to get controller info for %s: %s", cpath, str(err))
|
||
|
continue
|
||
|
+ ctrans = util.get_sysfs_attr(controller, "transport")
|
||
|
+ ctaddr = util.get_sysfs_attr(controller, "address")
|
||
|
self._controllers.append(NVMeController(name=os.path.basename(cpath),
|
||
|
serial=cinfo.serial_number,
|
||
|
nvme_ver=cinfo.nvme_ver,
|
||
|
id=cinfo.ctrl_id,
|
||
|
- subsysnqn=cinfo.subsysnqn))
|
||
|
+ subsysnqn=cinfo.subsysnqn,
|
||
|
+ transport=ctrans,
|
||
|
+ transport_address=ctaddr))
|
||
|
|
||
|
return self._controllers
|
||
|
|
||
|
--
|
||
|
2.38.1
|
||
|
|
||
|
|
||
|
From a04538936ff62958c272b5e2b2657d177df1ef13 Mon Sep 17 00:00:00 2001
|
||
|
From: Vojtech Trefny <vtrefny@redhat.com>
|
||
|
Date: Thu, 8 Dec 2022 13:15:33 +0100
|
||
|
Subject: [PATCH 3/3] Add additional identifiers to NVMeNamespaceDevice
|
||
|
|
||
|
---
|
||
|
blivet/devices/disk.py | 2 ++
|
||
|
blivet/populator/helpers/disk.py | 3 +++
|
||
|
2 files changed, 5 insertions(+)
|
||
|
|
||
|
diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py
|
||
|
index 796b5b03..8842b4dc 100644
|
||
|
--- a/blivet/devices/disk.py
|
||
|
+++ b/blivet/devices/disk.py
|
||
|
@@ -756,6 +756,8 @@ class NVMeNamespaceDevice(DiskDevice):
|
||
|
:type nsid: int
|
||
|
"""
|
||
|
self.nsid = kwargs.pop("nsid", 0)
|
||
|
+ self.eui64 = kwargs.pop("eui64", "")
|
||
|
+ self.nguid = kwargs.pop("nguid", "")
|
||
|
|
||
|
DiskDevice.__init__(self, device, **kwargs)
|
||
|
|
||
|
diff --git a/blivet/populator/helpers/disk.py b/blivet/populator/helpers/disk.py
|
||
|
index 9ed1eebe..cf20d302 100644
|
||
|
--- a/blivet/populator/helpers/disk.py
|
||
|
+++ b/blivet/populator/helpers/disk.py
|
||
|
@@ -282,6 +282,9 @@ class NVMeNamespaceDevicePopulator(DiskDevicePopulator):
|
||
|
log.debug("Failed to get namespace info for %s: %s", path, str(err))
|
||
|
else:
|
||
|
kwargs["nsid"] = ninfo.nsid
|
||
|
+ kwargs["uuid"] = ninfo.uuid
|
||
|
+ kwargs["eui64"] = ninfo.eui64
|
||
|
+ kwargs["nguid"] = ninfo.nguid
|
||
|
|
||
|
log.info("%s is an NVMe local namespace device", udev.device_get_name(self.data))
|
||
|
return kwargs
|
||
|
--
|
||
|
2.38.1
|
||
|
|