Previous patch 3 is now part of a separate set.
Patch 1 has the suggested fixes from the list as well as conversion of new logging statements in StorageDevice.updateSysfsPath to pass arguments separately instead of formatting the string in advance.
Patch 2 has added comment disabling pylint warning about defining _mdInfo outside of __init__.
Patch 3 (separate lvm and md metadata...) has added disabling of pylint warnings for unused argument 'info'.
Patch 4 (adapt multipath...) is unchanged.
Patch 5 is new and just removes some things no longer used.
Patch 6 is also new and removes a function that is no longer useful.
David Lehman (6): Replace our pyudev with the package python-pyudev. Cache MD metadata while populating the devicetree. Keep lvm and md metadata separate from udev info. Adapt multipath detection code to external pyudev module. Remove some unused multipath-specific functions from blivet.udev. Remove parse_uevent_file since it won't work with pyudev.
blivet/deviceaction.py | 4 +- blivet/devices.py | 95 +++++++-------------- blivet/devicetree.py | 122 ++++++++++++++------------ blivet/pyudev.py | 226 ------------------------------------------------- blivet/udev.py | 145 ++++++++----------------------- blivet/util.py | 2 +- python-blivet.spec | 1 + tests/udev_test.py | 130 +--------------------------- 8 files changed, 143 insertions(+), 582 deletions(-) delete mode 100644 blivet/pyudev.py
There are two major differences in how we use the module. Each device is represented by a pyudev.Device instance, which is based on collections.abc.Mapping. That means we can no longer change the data to do things like set a "multipath_member" format type or inject LVM or MD metadata.
The other difference is that sysfs paths now include the "/sys", which is great since it's always mounted in the same place. --- blivet/deviceaction.py | 4 +- blivet/devices.py | 95 +++++++-------------- blivet/devicetree.py | 49 +++++------ blivet/pyudev.py | 226 ------------------------------------------------- blivet/udev.py | 122 +++++++++----------------- blivet/util.py | 2 +- python-blivet.spec | 1 + tests/udev_test.py | 91 +------------------- 8 files changed, 99 insertions(+), 491 deletions(-) delete mode 100644 blivet/pyudev.py
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py index db4c7a7..d2818c1 100644 --- a/blivet/deviceaction.py +++ b/blivet/deviceaction.py @@ -553,9 +553,7 @@ class ActionCreateFormat(DeviceAction): self.device.format.create(device=self.device.path, options=self.device.formatArgs) # Get the UUID now that the format is created - udev.settle() - self.device.updateSysfsPath() - info = udev.get_block_device(self.device.sysfsPath) + info = udev.get_device(self.device.sysfsPath) # only do this if the format has a device known to udev # (the format might not have a normal device at all) if info: diff --git a/blivet/devices.py b/blivet/devices.py index c238e94..25b7586 100644 --- a/blivet/devices.py +++ b/blivet/devices.py @@ -27,6 +27,7 @@ import tempfile import abc from decimal import Decimal import re +import pyudev
from six import add_metaclass
@@ -107,7 +108,7 @@ def deviceNameToDiskByPath(deviceName=None): return ""
ret = None - for dev in udev.get_block_devices(): + for dev in udev.get_devices(): if udev.device_get_name(dev) == deviceName: ret = udev.device_get_by_path(dev) break @@ -508,7 +509,6 @@ class StorageDevice(Device):
_type = "blivet" _devDir = "/dev" - sysfsBlockDir = "class/block" _formatImmutable = False _partitionable = False _isDisk = False @@ -751,11 +751,22 @@ class StorageDevice(Device):
def updateSysfsPath(self): """ Update this device's sysfs path. """ - log_method_call(self, self.name, status=self.status) - sysfsName = self.name.replace("/", "!") - path = os.path.join("/sys", self.sysfsBlockDir, sysfsName) - self.sysfsPath = os.path.realpath(path)[4:] - log.debug("%s sysfsPath set to %s", self.name, self.sysfsPath) + # We're using os.path.exists as a stand-in for status. We can't use + # the status property directly because MDRaidArrayDevice.status calls + # this method. + log_method_call(self, self.name, status=os.path.exists(self.path)) + if not self.exists: + raise errors.DeviceError("device has not been created", self.name) + + try: + udev_device = pyudev.Device.from_device_file(udev.global_udev, + self.path) + except pyudev.DeviceNotFoundError as e: + log.error("failed to update sysfs path for %s: %s", self.name, e) + self.sysfsPath = '' + else: + self.sysfsPath = udev_device.sys_path + log.debug("%s sysfsPath set to %s", self.name, self.sysfsPath)
@property def formatArgs(self): @@ -780,7 +791,7 @@ class StorageDevice(Device): log.debug("not sending change uevent for inactive device") return
- path = os.path.normpath("/sys/%s" % self.sysfsPath) + path = os.path.normpath(self.sysfsPath) try: util.notify_kernel(path, action="change") except (ValueError, IOError) as e: @@ -1055,7 +1066,7 @@ class StorageDevice(Device):
@property def removable(self): - devpath = os.path.normpath("/sys/%s" % self.sysfsPath) + devpath = os.path.normpath(self.sysfsPath) remfile = os.path.normpath("%s/removable" % devpath) return (self.sysfsPath and os.path.exists(devpath) and os.access(remfile, os.R_OK) and @@ -1575,23 +1586,6 @@ class PartitionDevice(StorageDevice): weight = property(lambda d: d._getWeight(), lambda d,w: d._setWeight(w))
- def updateSysfsPath(self): - """ Update this device's sysfs path. """ - log_method_call(self, self.name, status=self.status) - if not self.parents: - self.sysfsPath = '' - - elif isinstance(self.parents[0], DMDevice): - dm_node = dm.dm_node_from_name(self.name) - path = os.path.join("/sys", self.sysfsBlockDir, dm_node) - self.sysfsPath = os.path.realpath(path)[4:] - elif isinstance(self.parents[0], MDRaidArrayDevice): - md_node = mdraid.md_node_from_name(self.name) - path = os.path.join("/sys", self.sysfsBlockDir, md_node) - self.sysfsPath = os.path.realpath(path)[4:] - else: - StorageDevice.updateSysfsPath(self) - def _setName(self, value): self._name = value # actual name setting is done by parted
@@ -2054,19 +2048,6 @@ class DMDevice(StorageDevice): None) return (match.live_table and not match.suspended) if match else False
- def updateSysfsPath(self): - """ Update this device's sysfs path. """ - log_method_call(self, self.name, status=self.status) - if not self.exists: - raise errors.DeviceError("device has not been created", self.name) - - if self.status: - dm_node = self.getDMNode() - path = os.path.join("/sys", self.sysfsBlockDir, dm_node) - self.sysfsPath = os.path.realpath(path)[4:] - else: - self.sysfsPath = '' - #def getTargetType(self): # return dm.getDmTarget(name=self.name)
@@ -3810,22 +3791,6 @@ class MDRaidArrayDevice(ContainerDevice):
spares = property(_getSpares, _setSpares)
- def updateSysfsPath(self): - """ Update this device's sysfs path. """ - # don't include self.status here since this method is called by - # MDRaidArrayDevice.status - log_method_call(self, self.name) - if not self.exists: - raise errors.DeviceError("device has not been created", self.name) - - # We don't use self.status here because self.status requires a valid - # sysfs path to function correctly. - if os.path.exists(self.path): - md_node = mdraid.md_node_from_name(self.name) - self.sysfsPath = "/devices/virtual/block/%s" % md_node - else: - self.sysfsPath = '' - def _addParent(self, member): super(MDRaidArrayDevice, self)._addParent(member)
@@ -3886,7 +3851,7 @@ class MDRaidArrayDevice(ContainerDevice): self.updateSysfsPath()
# make sure the active array is the one we expect - info = udev.get_block_device(self.sysfsPath) + info = udev.get_device(self.sysfsPath) uuid = udev.device_get_md_uuid(info) if uuid and uuid != self.uuid: log.warning("md array %s is active, but has UUID %s -- not %s", @@ -3894,7 +3859,7 @@ class MDRaidArrayDevice(ContainerDevice): self.sysfsPath = "" return status
- state_file = "/sys/%s/md/array_state" % self.sysfsPath + state_file = "%s/md/array_state" % self.sysfsPath try: state = open(state_file).read().strip() if state in ("clean", "active", "active-idle", "readonly", "read-auto"): @@ -3924,7 +3889,7 @@ class MDRaidArrayDevice(ContainerDevice): def degraded(self): """ Return True if the array is running in degraded mode. """ rc = False - degraded_file = "/sys/%s/md/degraded" % self.sysfsPath + degraded_file = "%s/md/degraded" % self.sysfsPath if os.access(degraded_file, os.R_OK): val = open(degraded_file).read().strip() if val == "1": @@ -3982,7 +3947,7 @@ class MDRaidArrayDevice(ContainerDevice): # mdadm reuses minors indiscriminantly when there is no mdadm.conf, so # we need to clear the sysfs path now so our status method continues to # give valid results - self.updateSysfsPath() + self.sysfsPath = ''
def teardown(self, recursive=None): """ Close, or tear down, a device. """ @@ -4024,15 +3989,13 @@ class MDRaidArrayDevice(ContainerDevice):
def _postCreate(self): # this is critical since our status method requires a valid sysfs path - md_node = mdraid.md_node_from_name(self.name) - self.sysfsPath = "/devices/virtual/block/%s" % md_node - self.exists = True # I think we can remove this. - + self.exists = True # this is needed to run updateSysfsPath + self.updateSysfsPath() StorageDevice._postCreate(self)
# update our uuid attribute with the new array's UUID - info = udev.get_block_device(self.sysfsPath) - self.uuid = udev.device_get_md_uuid(info) + info = mdraid.mddetail(self.path) + self.uuid = info.get("UUID") for member in self.devices: member.format.mdUuid = self.uuid
@@ -5229,7 +5192,7 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
def _postCreate(self): super(BTRFSVolumeDevice, self)._postCreate() - info = udev.get_block_device(self.sysfsPath) + info = udev.get_device(self.sysfsPath) if not info: log.error("failed to get updated udev info for new btrfs volume") else: diff --git a/blivet/devicetree.py b/blivet/devicetree.py index c4cb1b7..755f782 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -660,7 +660,7 @@ class DeviceTree(object):
if self.udevDeviceIsDisk(info): # Ignore any readonly disks - if util.get_sysfs_attr(info["sysfs_path"], 'ro') == '1': + if util.get_sysfs_attr(udev.device_get_sysfs_path(info), 'ro') == '1': log.debug("Ignoring read only device %s", name) # FIXME: We have to handle this better, ie: not ignore these. self.addIgnoredDisk(name) @@ -706,10 +706,10 @@ class DeviceTree(object): if not device: # initiate detection of all PVs and hope that it leads to us having # the VG and LVs in the tree - for pv_name in os.listdir("/sys" + sysfs_path + "/slaves"): - link = os.readlink("/sys" + sysfs_path + "/slaves/" + pv_name) + for pv_name in os.listdir(sysfs_path + "/slaves"): + link = os.readlink(sysfs_path + "/slaves/" + pv_name) pv_sysfs_path = os.path.normpath(sysfs_path + '/slaves/' + link) - pv_info = udev.get_block_device(pv_sysfs_path) + pv_info = udev.get_device(pv_sysfs_path) self.addUdevDevice(pv_info)
vg_name = udev.device_get_lv_vg_name(info) @@ -752,7 +752,7 @@ class DeviceTree(object): if device is None: # we couldn't find it, so create it # first, get a list of the slave devs and look them up - slave_dir = os.path.normpath("/sys/%s/slaves" % sysfs_path) + slave_dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(slave_dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name first @@ -762,7 +762,7 @@ class DeviceTree(object): dev_name = slave_name.replace("!", "/") # handles cciss slave_dev = self.getDeviceByName(dev_name) path = os.path.normpath("%s/%s" % (slave_dir, slave_name)) - new_info = udev.get_block_device(os.path.realpath(path)[4:]) + new_info = udev.get_device(os.path.realpath(path)) if not slave_dev: # we haven't scanned the slave yet, so do it now if new_info: @@ -822,7 +822,7 @@ class DeviceTree(object): # TODO: look for this device by dm-uuid?
# first, get a list of the slave devs and look them up - slave_dir = os.path.normpath("/sys/%s/slaves" % sysfs_path) + slave_dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(slave_dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name first @@ -832,7 +832,7 @@ class DeviceTree(object): dev_name = slave_name.replace("!", "/") # handles cciss slave_dev = self.getDeviceByName(dev_name) path = os.path.normpath("%s/%s" % (slave_dir, slave_name)) - new_info = udev.get_block_device(os.path.realpath(path)[4:]) + new_info = udev.get_device(os.path.realpath(path)) if not slave_dev: # we haven't scanned the slave yet, so do it now if new_info: @@ -865,7 +865,7 @@ class DeviceTree(object): log_method_call(self, name=name) sysfs_path = udev.device_get_sysfs_path(info)
- slave_dir = os.path.normpath("/sys/%s/slaves" % sysfs_path) + slave_dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(slave_dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name @@ -877,7 +877,7 @@ class DeviceTree(object): if not slave_dev: # we haven't scanned the slave yet, so do it now path = os.path.normpath("%s/%s" % (slave_dir, slave_name)) - new_info = udev.get_block_device(os.path.realpath(path)[4:]) + new_info = udev.get_device(os.path.realpath(path)) if new_info: self.addUdevDevice(new_info) if self.getDeviceByName(dev_name) is None: @@ -936,7 +936,7 @@ class DeviceTree(object):
if disk is None: # create a device instance for the disk - new_info = udev.get_block_device(os.path.dirname(sysfs_path)) + new_info = udev.get_device(os.path.dirname(sysfs_path)) if new_info: self.addUdevDevice(new_info) disk = self.getDeviceByName(disk_name) @@ -1030,7 +1030,7 @@ class DeviceTree(object): if not container: parentSysName = mdraid.md_node_from_name(parentName) container_sysfs = "/class/block/" + parentSysName - container_info = udev.get_block_device(container_sysfs) + container_info = udev.get_device(container_sysfs) if not container_info: log.error("failed to find md container %s at %s", parentName, container_sysfs) @@ -1102,7 +1102,7 @@ class DeviceTree(object): name = udev.device_get_name(info) log_method_call(self, name=name) sysfs_path = udev.device_get_sysfs_path(info) - sys_file = "/sys/%s/loop/backing_file" % sysfs_path + sys_file = "%s/loop/backing_file" % sysfs_path backing_file = open(sys_file).read().strip() file_device = self.getDeviceByName(backing_file) if not file_device: @@ -1122,7 +1122,7 @@ class DeviceTree(object):
def addUdevDevice(self, info): name = udev.device_get_name(info) - log_method_call(self, name=name, info=pprint.pformat(info)) + log_method_call(self, name=name, info=pprint.pformat(dict(info))) uuid = udev.device_get_uuid(info) sysfs_path = udev.device_get_sysfs_path(info)
@@ -1490,7 +1490,7 @@ class DeviceTree(object):
if lv_device.status: lv_device.updateSysfsPath() - lv_info = udev.get_block_device(lv_device.sysfsPath) + lv_info = udev.get_device(lv_device.sysfsPath) if not lv_info: log.error("failed to get udev data for lv %s", lv_device.name) return @@ -1587,7 +1587,7 @@ class DeviceTree(object):
# check the list of devices udev knows about to see if the array # this device belongs to is already active - for dev in udev.get_block_devices(): + for dev in udev.get_devices(): if not udev.device_is_md(dev): continue
@@ -1682,13 +1682,13 @@ class DeviceTree(object): self._addDevice(dm_array)
# Wait for udev to scan the just created nodes, to avoid a race - # with the udev.get_block_device() call below. + # with the udev.get_device() call below. udev.settle()
# Get the DMRaidArrayDevice a DiskLabel format *now*, in case # its partitions get scanned before it does. dm_array.updateSysfsPath() - dm_array_info = udev.get_block_device(dm_array.sysfsPath) + dm_array_info = udev.get_device(dm_array.sysfsPath) self.handleUdevDiskLabelFormat(dm_array_info, dm_array)
# Use the rs's object on the device. @@ -1889,7 +1889,7 @@ class DeviceTree(object): def updateDeviceFormat(self, device): log.info("updating format of device: %s", device) try: - util.notify_kernel("/sys%s" % device.sysfsPath) + util.notify_kernel(device.sysfsPath) except (ValueError, IOError) as e: log.warning("failed to notify kernel of change: %s", e)
@@ -2032,7 +2032,7 @@ class DeviceTree(object): self._addDevice(filedev) self._addDevice(loopdev) self._addDevice(dmdev) - info = udev.get_block_device(dmdev.sysfsPath) + info = udev.get_device(dmdev.sysfsPath) self.addUdevDevice(info)
def backupConfigs(self, restore=False): @@ -2146,18 +2146,19 @@ class DeviceTree(object): # blocks or since previous iterations. while True: devices = [] - new_devices = udev.get_block_devices() + new_devices = udev.get_devices()
for new_device in new_devices: - if new_device['name'] not in old_devices: - old_devices[new_device['name']] = new_device + new_name = udev.device_get_name(new_device) + if new_name not in old_devices: + old_devices[new_name] = new_device devices.append(new_device)
if len(devices) == 0: # nothing is changing -- we are finished building devices break
- log.info("devices to scan: %s", [d['name'] for d in devices]) + log.info("devices to scan: %s", [udev.device_get_name(d) for d in devices]) for dev in devices: self.addUdevDevice(dev)
diff --git a/blivet/pyudev.py b/blivet/pyudev.py deleted file mode 100644 index fa0846f..0000000 --- a/blivet/pyudev.py +++ /dev/null @@ -1,226 +0,0 @@ -from __future__ import print_function - -import sys -import os -import fnmatch -from ctypes import CDLL, c_char_p, c_int, c_void_p - - -# XXX this one may need some tweaking... -def find_library(name, somajor=0): - env = os.environ.get("LD_LIBRARY_PATH") - common = ["/lib64", "/lib"] - - if env: - libdirs = env.split(":") + common - else: - libdirs = common - - for ldir in filter(os.path.isdir, libdirs): - files = fnmatch.filter(os.listdir(ldir), "lib%s.so.%d" % (name, somajor)) - if files: - return next(os.path.join(ldir, lfile) for lfile in files) - - return None - -def get_library(): - name = "udev" - somajor = 1 - lib = find_library(name=name, somajor=somajor) - - if not lib or not os.path.exists(lib): - raise ImportError("No library named %s.%d" % (name, somajor)) - return lib - -# load the udev library -libudev = CDLL(get_library()) - - -# create aliases for needed functions and set the return types where needed -libudev_udev_new = libudev.udev_new -libudev_udev_new.argtypes = [] -libudev_udev_new.restype = c_void_p -libudev_udev_unref = libudev.udev_unref -libudev_udev_unref.argtypes = [ c_void_p ] - -libudev_udev_device_new_from_syspath = libudev.udev_device_new_from_syspath -libudev_udev_device_new_from_syspath.restype = c_void_p -libudev_udev_device_new_from_syspath.argtypes = [ c_void_p, c_char_p ] -libudev_udev_device_unref = libudev.udev_device_unref -libudev_udev_device_unref.argtypes = [ c_void_p ] - -libudev_udev_device_get_syspath = libudev.udev_device_get_syspath -libudev_udev_device_get_syspath.restype = c_char_p -libudev_udev_device_get_syspath.argtypes = [ c_void_p ] -libudev_udev_device_get_sysname = libudev.udev_device_get_sysname -libudev_udev_device_get_sysname.restype = c_char_p -libudev_udev_device_get_sysname.argtypes = [ c_void_p ] -libudev_udev_device_get_devpath = libudev.udev_device_get_devpath -libudev_udev_device_get_devpath.restype = c_char_p -libudev_udev_device_get_devpath.argtypes = [ c_void_p ] -libudev_udev_device_get_devtype = libudev.udev_device_get_devtype -libudev_udev_device_get_devtype.restype = c_char_p -libudev_udev_device_get_devtype.argtypes = [ c_void_p ] -libudev_udev_device_get_devnode = libudev.udev_device_get_devnode -libudev_udev_device_get_devnode.restype = c_char_p -libudev_udev_device_get_devnode.argtypes = [ c_void_p ] -libudev_udev_device_get_subsystem = libudev.udev_device_get_subsystem -libudev_udev_device_get_subsystem.restype = c_char_p -libudev_udev_device_get_subsystem.argtypes = [ c_void_p ] -libudev_udev_device_get_sysnum = libudev.udev_device_get_sysnum -libudev_udev_device_get_sysnum.restype = c_char_p -libudev_udev_device_get_sysnum.argtypes = [ c_void_p ] - -libudev_udev_device_get_properties_list_entry = libudev.udev_device_get_properties_list_entry -libudev_udev_device_get_properties_list_entry.restype = c_void_p -libudev_udev_device_get_properties_list_entry.argtypes = [ c_void_p ] -libudev_udev_list_entry_get_next = libudev.udev_list_entry_get_next -libudev_udev_list_entry_get_next.restype = c_void_p -libudev_udev_list_entry_get_next.argtypes = [ c_void_p ] - -libudev_udev_list_entry_get_name = libudev.udev_list_entry_get_name -libudev_udev_list_entry_get_name.restype = c_char_p -libudev_udev_list_entry_get_name.argtypes = [ c_void_p ] -libudev_udev_list_entry_get_value = libudev.udev_list_entry_get_value -libudev_udev_list_entry_get_value.restype = c_char_p -libudev_udev_list_entry_get_value.argtypes = [ c_void_p ] - -libudev_udev_enumerate_new = libudev.udev_enumerate_new -libudev_udev_enumerate_new.restype = c_void_p -libudev_udev_enumerate_new.argtypes = [ c_void_p ] -libudev_udev_enumerate_unref = libudev.udev_enumerate_unref -libudev_udev_enumerate_unref.argtypes = [ c_void_p ] - -libudev_udev_enumerate_add_match_subsystem = libudev.udev_enumerate_add_match_subsystem -libudev_udev_enumerate_add_match_subsystem.restype = c_int -libudev_udev_enumerate_add_match_subsystem.argtypes = [ c_void_p, c_char_p ] -libudev_udev_enumerate_scan_devices = libudev.udev_enumerate_scan_devices -libudev_udev_enumerate_scan_devices.restype = c_int -libudev_udev_enumerate_scan_devices.argtypes = [ c_void_p ] -libudev_udev_enumerate_get_list_entry = libudev.udev_enumerate_get_list_entry -libudev_udev_enumerate_get_list_entry.restype = c_void_p -libudev_udev_enumerate_get_list_entry.argtypes = [ c_void_p ] - -libudev_udev_device_get_devlinks_list_entry = libudev.udev_device_get_devlinks_list_entry -libudev_udev_device_get_devlinks_list_entry.restype = c_void_p -libudev_udev_device_get_devlinks_list_entry.argtypes = [ c_void_p ] - - -class UdevDevice(dict): - - def __init__(self, udev, sysfs_path): - dict.__init__(self) - - # create new udev device from syspath - udev_device = libudev_udev_device_new_from_syspath(udev, sysfs_path) - if not udev_device: - # device does not exist - return - - # set syspath and sysname properties - self.syspath = libudev_udev_device_get_syspath(udev_device) - self.sysname = libudev_udev_device_get_sysname(udev_device) - - # get the devlinks list - devlinks = [] - devlinks_entry = libudev_udev_device_get_devlinks_list_entry(udev_device) - - while devlinks_entry: - path = libudev_udev_list_entry_get_name(devlinks_entry) - devlinks.append(path) - - devlinks_entry = libudev_udev_list_entry_get_next(devlinks_entry) - - # add devlinks list to the dictionary - self["symlinks"] = devlinks - - # get the first property entry - property_entry = libudev_udev_device_get_properties_list_entry(udev_device) - - while property_entry: - name = libudev_udev_list_entry_get_name(property_entry) - value = libudev_udev_list_entry_get_value(property_entry) - - # lvm outputs values for multiple lvs in one line - # we want to split them and make a list - # if the first lv's value is empty we end up with a value starting - # with name=, prepend a space that our split does the right thing - if value.startswith("%s=" % name): - value = " " + value - - if value.count(" %s=" % name): - value = value.split(" %s=" % name) - - self[name] = value - - # get next property entry - property_entry = libudev_udev_list_entry_get_next(property_entry) - - # set additional properties - self.devpath = libudev_udev_device_get_devpath(udev_device) - self.subsystem = libudev_udev_device_get_subsystem(udev_device) - self.devtype = libudev_udev_device_get_devtype(udev_device) - self.sysnum = libudev_udev_device_get_sysnum(udev_device) - self.devnode = libudev_udev_device_get_devnode(udev_device) - - # cleanup - libudev_udev_device_unref(udev_device) - - -class Udev(object): - - def __init__(self): - self.udev = libudev_udev_new() - - def create_device(self, sysfs_path): - return UdevDevice(self.udev, sysfs_path) - - def enumerate_devices(self, subsystem=None): - context = libudev_udev_enumerate_new(self.udev) - - # add the match subsystem - if subsystem is not None: - rc = libudev_udev_enumerate_add_match_subsystem(context, subsystem) - if not rc == 0: - print("error: unable to add the match subsystem", file=sys.stderr) - libudev_udev_enumerate_unref(context) - return [] - - # scan the devices - rc = libudev_udev_enumerate_scan_devices(context) - if not rc == 0: - print("error: unable to enumerate the devices", file=sys.stderr) - libudev_udev_enumerate_unref(context) - return [] - - # create the list of sysfs paths - sysfs_paths = [] - - # get the first list entry - list_entry = libudev_udev_enumerate_get_list_entry(context) - - while list_entry: - sysfs_path = libudev_udev_list_entry_get_name(list_entry) - sysfs_paths.append(sysfs_path) - - # get next list entry - list_entry = libudev_udev_list_entry_get_next(list_entry) - - # cleanup - libudev_udev_enumerate_unref(context) - - return sysfs_paths - - def scan_devices(self, sysfs_paths=None): - if sysfs_paths is None: - sysfs_paths = self.enumerate_devices() - - for sysfs_path in sysfs_paths: - device = self.create_device(sysfs_path) - - if device: - yield device - - def unref(self): - libudev_udev_unref(self.udev) - self.udev = None diff --git a/blivet/udev.py b/blivet/udev.py index b66e30b..d0eb543 100644 --- a/blivet/udev.py +++ b/blivet/udev.py @@ -27,45 +27,28 @@ import re from . import util from .size import Size
-from . import pyudev -global_udev = pyudev.Udev() +import pyudev +global_udev = pyudev.Context()
import logging log = logging.getLogger("blivet")
-def enumerate_devices(deviceClass="block"): - devices = global_udev.enumerate_devices(subsystem=deviceClass) - return [path[4:] for path in devices] - def get_device(sysfs_path): - if not os.path.exists("/sys%s" % sysfs_path): - log.debug("%s does not exist", sysfs_path) - return None - - # XXX we remove the /sys part when enumerating devices, - # so we have to prepend it when creating the device - dev = global_udev.create_device("/sys" + sysfs_path) - - if dev: - dev["name"] = dev.sysname - dev["sysfs_path"] = sysfs_path - - # now add in the contents of the uevent file since they're handy - dev = parse_uevent_file(dev) + try: + dev = pyudev.Device.from_sys_path(global_udev, sysfs_path) + except pyudev.DeviceNotFoundError as e: + log.error(e) + dev = None
return dev
-def get_devices(deviceClass="block"): +def get_devices(subsystem="block"): settle() - entries = [] - for path in enumerate_devices(deviceClass): - entry = get_device(path) - if entry: - entries.append(entry) - return entries + return [d for d in global_udev.list_devices(subsystem=subsystem) + if not __is_blacklisted_blockdev(d.sys_name)]
def parse_uevent_file(dev): - path = os.path.normpath("/sys/%s/uevent" % dev['sysfs_path']) + path = os.path.normpath("%s/uevent" % device_get_sysfs_path(dev)) if not os.access(path, os.R_OK): return dev
@@ -103,7 +86,7 @@ def resolve_devspec(devspec): from . import devices
ret = None - for dev in get_block_devices(): + for dev in get_devices(): if devspec.startswith("LABEL="): if device_get_label(dev) == devspec[6:]: ret = dev @@ -120,7 +103,7 @@ def resolve_devspec(devspec): if not spec.startswith("/dev/"): spec = os.path.normpath("/dev/" + spec)
- for link in dev["symlinks"]: + for link in device_get_symlinks(dev): if spec == link: ret = dev break @@ -135,37 +118,18 @@ def resolve_glob(glob): if not glob: return ret
- for dev in get_block_devices(): + for dev in get_devices(): name = device_get_name(dev)
if fnmatch.fnmatch(name, glob): ret.append(name) else: - for link in dev["symlinks"]: + for link in device_get_symlinks(dev): if fnmatch.fnmatch(link, glob): ret.append(name)
return ret
-def get_block_devices(): - settle() - entries = [] - for path in enumerate_block_devices(): - entry = get_block_device(path) - if entry: - if entry["name"].startswith("md"): - # mdraid is really braindead, when a device is stopped - # it is no longer usefull in anyway (and we should not - # probe it) yet it still sticks around, see bug rh523387 - state = None - state_file = "/sys/%s/md/array_state" % entry["sysfs_path"] - if os.access(state_file, os.R_OK): - state = open(state_file).read().strip() - if state == "clear": - continue - entries.append(entry) - return entries - def __is_blacklisted_blockdev(dev_name): """Is this a blockdev we never want for an install?""" if dev_name.startswith("ram") or dev_name.startswith("fd"): @@ -180,17 +144,6 @@ def __is_blacklisted_blockdev(dev_name):
return False
-def enumerate_block_devices(): - return [d for d in enumerate_devices(deviceClass="block") if not __is_blacklisted_blockdev(os.path.basename(d))] - -def get_block_device(sysfs_path): - dev = get_device(sysfs_path) - if not dev or 'name' not in dev: - return None - else: - return dev - - # These are functions for retrieving specific pieces of information from # udev database entries. def device_get_name(udev_info): @@ -198,7 +151,7 @@ def device_get_name(udev_info): if "DM_NAME" in udev_info: name = udev_info["DM_NAME"] else: - name = udev_info["name"] + name = udev_info.sys_name
return name
@@ -236,7 +189,7 @@ def device_is_md(info):
# The udev information keeps shifting around. Only md arrays have a # /sys/class/block/<name>/md/ subdirectory. - md_dir = "/sys" + device_get_sysfs_path(info) + "/md" + md_dir = device_get_sysfs_path(info) + "/md" return os.path.exists(md_dir)
def device_is_cciss(info): @@ -256,7 +209,7 @@ def device_is_zfcp(info): if info.get("DEVTYPE") != "disk": return False
- subsystem = "/sys" + info.get("sysfs_path") + subsystem = device_get_sysfs_path(info)
while True: topdir = os.path.realpath(os.path.dirname(subsystem)) @@ -284,7 +237,7 @@ def device_get_zfcp_attribute(info, attr=None): log.debug("device_get_zfcp_attribute() called with attr=None") return None
- attribute = "/sys%s/device/%s" % (info.get("sysfs_path"), attr,) + attribute = "%s/device/%s" % (device_get_sysfs_path(info), attr) attribute = os.path.realpath(attribute)
if not os.path.isfile(attribute): @@ -295,14 +248,14 @@ def device_get_zfcp_attribute(info, attr=None):
def device_get_dasd_bus_id(info): """ Return the CCW bus ID of the dasd device. """ - return info.get("sysfs_path").split("/")[-3] + return device_get_sysfs_path(info).split("/")[-3]
def device_get_dasd_flag(info, flag=None): """ Return the specified flag for the dasd device. """ if flag is None: return None
- path = "/sys" + info.get("sysfs_path") + "/device/" + flag + path = device_get_sysfs_path(info) + "/device/" + flag if not os.path.isfile(path): return None
@@ -318,17 +271,17 @@ def device_is_disk(info): """ Return True is the device is a disk. """ if device_is_cdrom(info): return False - has_range = os.path.exists("/sys/%s/range" % info['sysfs_path']) + has_range = os.path.exists("%s/range" % device_get_sysfs_path(info)) return info.get("DEVTYPE") == "disk" or has_range
def device_is_partition(info): - has_start = os.path.exists("/sys/%s/start" % info['sysfs_path']) + has_start = os.path.exists("%s/start" % device_get_sysfs_path(info)) return info.get("DEVTYPE") == "partition" or has_start
def device_is_loop(info): """ Return True if the device is a configured loop device. """ return (device_get_name(info).startswith("loop") and - os.path.isdir("/sys/%s/loop" % info['sysfs_path'])) + os.path.isdir("%s/loop" % device_get_sysfs_path(info)))
def device_get_serial(udev_info): """ Get the serial number/UUID from the device as reported by udev. """ @@ -356,7 +309,7 @@ def device_get_path(info): return info["ID_PATH"]
def device_get_symlinks(info): - return info.get("symlinks", []) + return info.get("DEVLINKS", [])
def device_get_by_path(info): for link in device_get_symlinks(info): @@ -366,7 +319,7 @@ def device_get_by_path(info): return device_get_name(info)
def device_get_sysfs_path(info): - return info['sysfs_path'] + return info.sys_path
def device_get_major(info): return int(info["MAJOR"]) @@ -675,7 +628,7 @@ def device_get_iscsi_session(info): # The position of sessionX part depends on device # (e.g. offload vs. sw; also varies for different offload devs) session = None - match = re.match(r'/.*/(session\d+)', info["sysfs_path"]) + match = re.match(r'/.*/(session\d+)', device_get_sysfs_path(info)) if match: session = match.groups()[0] else: @@ -694,7 +647,7 @@ def device_get_iscsi_nic(info): def device_get_iscsi_initiator(info): initiator = None if device_is_partoff_iscsi(info): - host = re.match(r'.*/(host\d+)', info["sysfs_path"]).groups()[0] + host = re.match(r'.*/(host\d+)', device_get_sysfs_path(info)).groups()[0] if host: initiator_file = "/sys/class/iscsi_host/%s/initiatorname" % host if os.access(initiator_file, os.R_OK): @@ -738,10 +691,10 @@ def device_get_iscsi_initiator(info):
def _detect_broadcom_fcoe(info): re_pci_host=re.compile(r'/(.*)/(host\d+)') - match = re_pci_host.match(info["sysfs_path"]) + match = re_pci_host.match(device_get_sysfs_path(info)) if match: sysfs_pci, host = match.groups() - if os.access('/sys/%s/%s/fc_host' %(sysfs_pci, host), os.X_OK) and \ + if os.access('%s/%s/fc_host' %(sysfs_pci, host), os.X_OK) and \ 'net' in sysfs_pci: return (sysfs_pci, host) return (None, None) @@ -757,7 +710,7 @@ def device_is_fcoe(info): path_components[2] == "fc": return True
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]: + if path.startswith("fc-") and "fcoe" in device_get_sysfs_path(info): return True
if _detect_broadcom_fcoe(info) != (None, None): @@ -768,20 +721,21 @@ def device_is_fcoe(info): def device_get_fcoe_nic(info): path = info.get("ID_PATH", "") path_components = path.split("-") + sysfs_path = device_get_sysfs_path(info)
if path.startswith("pci-eth") and len(path_components) >= 4 and \ path_components[2] == "fc": return path_components[1]
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]: - return info["sysfs_path"].split("/")[4].split(".")[0] + if path.startswith("fc-") and "fcoe" in sysfs_path: + return sysfs_path.split("/")[4].split(".")[0]
(sysfs_pci, host) = _detect_broadcom_fcoe(info) if (sysfs_pci, host) != (None, None): - net, iface = info['sysfs_path'].split("/")[5:7] + net, iface = sysfs_path.split("/")[5:7] if net != "net": - log.warning("unexpected sysfs_path of bnx2fc device: %s", info['sysfs_path']) - match = re.compile(r'.*/net/([^/]*)').match(info['sysfs_path']) + log.warning("unexpected sysfs_path of bnx2fc device: %s", sysfs_path) + match = re.compile(r'.*/net/([^/]*)').match(sysfs_path) if match: return match.groups()[0].split(".")[0] else: @@ -795,7 +749,7 @@ def device_get_fcoe_identifier(info): path_components[2] == "fc": return path_components[3]
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]: + if path.startswith("fc-") and "fcoe" in device_get_sysfs_path(info): return path_components[1]
if device_is_fcoe(info) and len(path_components) >= 4 and \ diff --git a/blivet/util.py b/blivet/util.py index a15bb4a..28dc125 100644 --- a/blivet/util.py +++ b/blivet/util.py @@ -178,7 +178,7 @@ def get_sysfs_attr(path, attr): log.debug("get_sysfs_attr() called with attr=None") return None
- attribute = "/sys%s/%s" % (path, attr) + attribute = "%s/%s" % (path, attr) attribute = os.path.realpath(attribute)
if not os.path.isfile(attribute) and not os.path.islink(attribute): diff --git a/python-blivet.spec b/python-blivet.spec index abbbb0f..b668d94 100644 --- a/python-blivet.spec +++ b/python-blivet.spec @@ -28,6 +28,7 @@ Requires: python Requires: python-six Requires: pykickstart >= %{pykickstartver} Requires: util-linux >= %{utillinuxver} +Requires: python-pyudev Requires: parted >= %{partedver} Requires: pyparted >= %{pypartedver} Requires: device-mapper >= %{dmver} diff --git a/tests/udev_test.py b/tests/udev_test.py index a7b09ab..86cc434 100644 --- a/tests/udev_test.py +++ b/tests/udev_test.py @@ -11,94 +11,11 @@ class UdevTest(unittest.TestCase): blivet.udev.os = mock.Mock() blivet.udev.log = mock.Mock()
- def test_udev_enumerate_devices(self): + def test_udev_get_device(self): import blivet.udev - ENUMERATE_LIST = [ - '/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda', - '/sys/devices/virtual/block/loop0', - '/sys/devices/virtual/block/loop1', - '/sys/devices/virtual/block/ram0', - '/sys/devices/virtual/block/ram1', - '/sys/devices/virtual/block/dm-0', - ] - blivet.udev.global_udev.enumerate_devices = mock.Mock(return_value=ENUMERATE_LIST) - ret = blivet.udev.enumerate_devices() - self.assertEqual(set(ret), - set(['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda', - '/devices/virtual/block/loop0', '/devices/virtual/block/loop1', - '/devices/virtual/block/ram0', '/devices/virtual/block/ram1', - '/devices/virtual/block/dm-0']) - ) - - def test_udev_get_device_1(self): - import blivet.udev - - class Device(object): - def __init__(self): - self.sysname = 'loop1' - self.dict = {'symlinks': ['/dev/block/7:1'], - 'SUBSYSTEM': 'block', - 'MAJOR': '7', - 'DEVPATH': '/devices/virtual/block/loop1', - 'UDISKS_PRESENTATION_NOPOLICY': '1', - 'UDEV_LOG': '3', - 'DEVNAME': '/dev/loop1', - 'DEVTYPE': 'disk', - 'DEVLINKS': '/dev/block/7:1', - 'MINOR': '1' - } - - def __getitem__(self, key): - return self.dict[key] - - def __setitem__(self, key, value): - self.dict[key] = value - - blivet.udev.os.path.exists.return_value = True - DEV_PATH = '/devices/virtual/block/loop1' - dev = Device() - blivet.udev.global_udev = mock.Mock() - blivet.udev.global_udev.create_device.return_value = dev - - saved = blivet.udev.parse_uevent_file - blivet.udev.parse_uevent_file = mock.Mock(return_value=dev) - - ret = blivet.udev.get_device(DEV_PATH) - self.assertTrue(isinstance(ret, Device)) - self.assertEqual(ret['name'], ret.sysname) - self.assertEqual(ret['sysfs_path'], DEV_PATH) - self.assertTrue(blivet.udev.parse_uevent_file.called) - - blivet.udev.parse_uevent_file = saved - - def test_udev_get_device_2(self): - import blivet.udev - blivet.udev.os.path.exists.return_value = False - ret = blivet.udev.get_device('') - self.assertEqual(ret, None) - - def test_udev_get_device_3(self): - import blivet.udev - blivet.udev.os.path.exists.return_value = True - blivet.udev.global_udev = mock.Mock() - blivet.udev.global_udev.create_device.return_value = None - ret = blivet.udev.get_device('') - self.assertEqual(ret, None) - - def test_udev_get_devices(self): - import blivet.udev - saved = blivet.udev.settle - blivet.udev.settle = mock.Mock() - DEVS = \ - ['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda', - '/devices/virtual/block/loop0', '/devices/virtual/block/loop1', - '/devices/virtual/block/ram0', '/devices/virtual/block/ram1', - '/devices/virtual/block/dm-0'] - blivet.udev.enumerate_devices = mock.Mock(return_value=DEVS) - blivet.udev.get_device = lambda x: x - ret = blivet.udev.get_devices() - self.assertEqual(ret, DEVS) - blivet.udev.settle = saved + devices = blivet.udev.global_udev.list_devices(subsystem="block") + for device in devices: + self.assertNotEqual(blivet.udev.get_device(device.sys_path), None)
def test_udev_parse_uevent_file_1(self): import blivet.udev
On Thu, Jul 31, 2014 at 06:22:29PM -0500, David Lehman wrote:
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]:
return info["sysfs_path"].split("/")[4].split(".")[0]
if path.startswith("fc-") and "fcoe" in sysfs_path:
return sysfs_path.split("/")[4].split(".")[0](sysfs_pci, host) = _detect_broadcom_fcoe(info) if (sysfs_pci, host) != (None, None):
net, iface = info['sysfs_path'].split("/")[5:7]
net, iface = sysfs_path.split("/")[5:7]
Shouldn't these indexes be bumped up by 1 for /sys/ now being included?
On 07/31/2014 07:23 PM, Brian C. Lane wrote:
On Thu, Jul 31, 2014 at 06:22:29PM -0500, David Lehman wrote:
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]:
return info["sysfs_path"].split("/")[4].split(".")[0]
if path.startswith("fc-") and "fcoe" in sysfs_path:
return sysfs_path.split("/")[4].split(".")[0] (sysfs_pci, host) = _detect_broadcom_fcoe(info) if (sysfs_pci, host) != (None, None):
net, iface = info['sysfs_path'].split("/")[5:7]
net, iface = sysfs_path.split("/")[5:7]Shouldn't these indexes be bumped up by 1 for /sys/ now being included?
Yes -- fixed locally. Thanks for spotting that.
----- Original Message -----
From: "David Lehman" dlehman@redhat.com To: anaconda-patches@lists.fedorahosted.org Sent: Friday, August 1, 2014 1:22:29 AM Subject: [PATCH 1/6] Replace our pyudev with the package python-pyudev.
There are two major differences in how we use the module. Each device is represented by a pyudev.Device instance, which is based on collections.abc.Mapping. That means we can no longer change the data to do things like set a "multipath_member" format type or inject LVM or MD metadata.
The other difference is that sysfs paths now include the "/sys", which is great since it's always mounted in the same place.
blivet/deviceaction.py | 4 +- blivet/devices.py | 95 +++++++-------------- blivet/devicetree.py | 49 +++++------ blivet/pyudev.py | 226
blivet/udev.py | 122 +++++++++----------------- blivet/util.py | 2 +- python-blivet.spec | 1 + tests/udev_test.py | 91 +------------------- 8 files changed, 99 insertions(+), 491 deletions(-) delete mode 100644 blivet/pyudev.py
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py index db4c7a7..d2818c1 100644 --- a/blivet/deviceaction.py +++ b/blivet/deviceaction.py @@ -553,9 +553,7 @@ class ActionCreateFormat(DeviceAction): self.device.format.create(device=self.device.path, options=self.device.formatArgs) # Get the UUID now that the format is created
udev.settle()self.device.updateSysfsPath()info = udev.get_block_device(self.device.sysfsPath)
info = udev.get_device(self.device.sysfsPath) # only do this if the format has a device known to udev # (the format might not have a normal device at all) if info:diff --git a/blivet/devices.py b/blivet/devices.py index c238e94..25b7586 100644 --- a/blivet/devices.py +++ b/blivet/devices.py @@ -27,6 +27,7 @@ import tempfile import abc from decimal import Decimal import re +import pyudev
from six import add_metaclass
@@ -107,7 +108,7 @@ def deviceNameToDiskByPath(deviceName=None): return ""
ret = None
- for dev in udev.get_block_devices():
- for dev in udev.get_devices(): if udev.device_get_name(dev) == deviceName: ret = udev.device_get_by_path(dev) break
@@ -508,7 +509,6 @@ class StorageDevice(Device):
_type = "blivet" _devDir = "/dev"
- sysfsBlockDir = "class/block" _formatImmutable = False _partitionable = False _isDisk = False
@@ -751,11 +751,22 @@ class StorageDevice(Device):
def updateSysfsPath(self): """ Update this device's sysfs path. """
log_method_call(self, self.name, status=self.status)sysfsName = self.name.replace("/", "!")path = os.path.join("/sys", self.sysfsBlockDir, sysfsName)self.sysfsPath = os.path.realpath(path)[4:]log.debug("%s sysfsPath set to %s", self.name, self.sysfsPath)
# We're using os.path.exists as a stand-in for status. We can't use# the status property directly because MDRaidArrayDevice.statuscalls
# this method.log_method_call(self, self.name, status=os.path.exists(self.path))if not self.exists:raise errors.DeviceError("device has not been created",self.name)
try:udev_device = pyudev.Device.from_device_file(udev.global_udev,self.path)except pyudev.DeviceNotFoundError as e:log.error("failed to update sysfs path for %s: %s", self.name,e)
self.sysfsPath = ''else:self.sysfsPath = udev_device.sys_pathlog.debug("%s sysfsPath set to %s", self.name, self.sysfsPath)@property def formatArgs(self):
@@ -780,7 +791,7 @@ class StorageDevice(Device): log.debug("not sending change uevent for inactive device") return
path = os.path.normpath("/sys/%s" % self.sysfsPath)
path = os.path.normpath(self.sysfsPath) try: util.notify_kernel(path, action="change") except (ValueError, IOError) as e:@@ -1055,7 +1066,7 @@ class StorageDevice(Device):
@property def removable(self):
devpath = os.path.normpath("/sys/%s" % self.sysfsPath)
devpath = os.path.normpath(self.sysfsPath) remfile = os.path.normpath("%s/removable" % devpath) return (self.sysfsPath and os.path.exists(devpath) and os.access(remfile, os.R_OK) and@@ -1575,23 +1586,6 @@ class PartitionDevice(StorageDevice): weight = property(lambda d: d._getWeight(), lambda d,w: d._setWeight(w))
- def updateSysfsPath(self):
""" Update this device's sysfs path. """log_method_call(self, self.name, status=self.status)if not self.parents:self.sysfsPath = ''elif isinstance(self.parents[0], DMDevice):dm_node = dm.dm_node_from_name(self.name)path = os.path.join("/sys", self.sysfsBlockDir, dm_node)self.sysfsPath = os.path.realpath(path)[4:]elif isinstance(self.parents[0], MDRaidArrayDevice):md_node = mdraid.md_node_from_name(self.name)path = os.path.join("/sys", self.sysfsBlockDir, md_node)self.sysfsPath = os.path.realpath(path)[4:]else:StorageDevice.updateSysfsPath(self)- def _setName(self, value): self._name = value # actual name setting is done by parted
@@ -2054,19 +2048,6 @@ class DMDevice(StorageDevice): None) return (match.live_table and not match.suspended) if match else False
- def updateSysfsPath(self):
""" Update this device's sysfs path. """log_method_call(self, self.name, status=self.status)if not self.exists:raise errors.DeviceError("device has not been created",self.name)
if self.status:dm_node = self.getDMNode()path = os.path.join("/sys", self.sysfsBlockDir, dm_node)self.sysfsPath = os.path.realpath(path)[4:]else:self.sysfsPath = ''- #def getTargetType(self): # return dm.getDmTarget(name=self.name)
@@ -3810,22 +3791,6 @@ class MDRaidArrayDevice(ContainerDevice):
spares = property(_getSpares, _setSpares)
- def updateSysfsPath(self):
""" Update this device's sysfs path. """# don't include self.status here since this method is called by# MDRaidArrayDevice.statuslog_method_call(self, self.name)if not self.exists:raise errors.DeviceError("device has not been created",self.name)
# We don't use self.status here because self.status requires a valid# sysfs path to function correctly.if os.path.exists(self.path):md_node = mdraid.md_node_from_name(self.name)self.sysfsPath = "/devices/virtual/block/%s" % md_nodeelse:self.sysfsPath = ''- def _addParent(self, member): super(MDRaidArrayDevice, self)._addParent(member)
@@ -3886,7 +3851,7 @@ class MDRaidArrayDevice(ContainerDevice): self.updateSysfsPath()
# make sure the active array is the one we expect
info = udev.get_block_device(self.sysfsPath)
info = udev.get_device(self.sysfsPath) uuid = udev.device_get_md_uuid(info) if uuid and uuid != self.uuid: log.warning("md array %s is active, but has UUID %s -- not %s",@@ -3894,7 +3859,7 @@ class MDRaidArrayDevice(ContainerDevice): self.sysfsPath = "" return status
state_file = "/sys/%s/md/array_state" % self.sysfsPath
state_file = "%s/md/array_state" % self.sysfsPath try: state = open(state_file).read().strip() if state in ("clean", "active", "active-idle", "readonly", "read-auto"):@@ -3924,7 +3889,7 @@ class MDRaidArrayDevice(ContainerDevice): def degraded(self): """ Return True if the array is running in degraded mode. """ rc = False
degraded_file = "/sys/%s/md/degraded" % self.sysfsPath
degraded_file = "%s/md/degraded" % self.sysfsPath if os.access(degraded_file, os.R_OK): val = open(degraded_file).read().strip() if val == "1":@@ -3982,7 +3947,7 @@ class MDRaidArrayDevice(ContainerDevice): # mdadm reuses minors indiscriminantly when there is no mdadm.conf, so # we need to clear the sysfs path now so our status method continues to # give valid results
self.updateSysfsPath()
self.sysfsPath = ''def teardown(self, recursive=None): """ Close, or tear down, a device. """
@@ -4024,15 +3989,13 @@ class MDRaidArrayDevice(ContainerDevice):
def _postCreate(self): # this is critical since our status method requires a valid sysfs path
md_node = mdraid.md_node_from_name(self.name)self.sysfsPath = "/devices/virtual/block/%s" % md_nodeself.exists = True # I think we can remove this.
self.exists = True # this is needed to run updateSysfsPathself.updateSysfsPath() StorageDevice._postCreate(self) # update our uuid attribute with the new array's UUID
info = udev.get_block_device(self.sysfsPath)self.uuid = udev.device_get_md_uuid(info)
info = mdraid.mddetail(self.path)self.uuid = info.get("UUID") for member in self.devices: member.format.mdUuid = self.uuid@@ -5229,7 +5192,7 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
def _postCreate(self): super(BTRFSVolumeDevice, self)._postCreate()
info = udev.get_block_device(self.sysfsPath)
info = udev.get_device(self.sysfsPath) if not info: log.error("failed to get updated udev info for new btrfs volume") else:diff --git a/blivet/devicetree.py b/blivet/devicetree.py index c4cb1b7..755f782 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -660,7 +660,7 @@ class DeviceTree(object):
if self.udevDeviceIsDisk(info): # Ignore any readonly disks
if util.get_sysfs_attr(info["sysfs_path"], 'ro') == '1':
if util.get_sysfs_attr(udev.device_get_sysfs_path(info), 'ro')== '1': log.debug("Ignoring read only device %s", name) # FIXME: We have to handle this better, ie: not ignore these. self.addIgnoredDisk(name) @@ -706,10 +706,10 @@ class DeviceTree(object): if not device: # initiate detection of all PVs and hope that it leads to us having # the VG and LVs in the tree
for pv_name in os.listdir("/sys" + sysfs_path + "/slaves"):link = os.readlink("/sys" + sysfs_path + "/slaves/" +pv_name)
for pv_name in os.listdir(sysfs_path + "/slaves"):link = os.readlink(sysfs_path + "/slaves/" + pv_name) pv_sysfs_path = os.path.normpath(sysfs_path + '/slaves/' + link)
pv_info = udev.get_block_device(pv_sysfs_path)
pv_info = udev.get_device(pv_sysfs_path) self.addUdevDevice(pv_info) vg_name = udev.device_get_lv_vg_name(info)@@ -752,7 +752,7 @@ class DeviceTree(object): if device is None: # we couldn't find it, so create it # first, get a list of the slave devs and look them up
slave_dir = os.path.normpath("/sys/%s/slaves" % sysfs_path)
slave_dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(slave_dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name first@@ -762,7 +762,7 @@ class DeviceTree(object): dev_name = slave_name.replace("!", "/") # handles cciss slave_dev = self.getDeviceByName(dev_name) path = os.path.normpath("%s/%s" % (slave_dir, slave_name))
new_info = udev.get_block_device(os.path.realpath(path)[4:])
new_info = udev.get_device(os.path.realpath(path)) if not slave_dev: # we haven't scanned the slave yet, so do it now if new_info:@@ -822,7 +822,7 @@ class DeviceTree(object): # TODO: look for this device by dm-uuid?
# first, get a list of the slave devs and look them up
slave_dir = os.path.normpath("/sys/%s/slaves" % sysfs_path)
slave_dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(slave_dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name first@@ -832,7 +832,7 @@ class DeviceTree(object): dev_name = slave_name.replace("!", "/") # handles cciss slave_dev = self.getDeviceByName(dev_name) path = os.path.normpath("%s/%s" % (slave_dir, slave_name))
new_info = udev.get_block_device(os.path.realpath(path)[4:])
new_info = udev.get_device(os.path.realpath(path)) if not slave_dev: # we haven't scanned the slave yet, so do it now if new_info:@@ -865,7 +865,7 @@ class DeviceTree(object): log_method_call(self, name=name) sysfs_path = udev.device_get_sysfs_path(info)
slave_dir = os.path.normpath("/sys/%s/slaves" % sysfs_path)
slave_dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(slave_dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name@@ -877,7 +877,7 @@ class DeviceTree(object): if not slave_dev: # we haven't scanned the slave yet, so do it now path = os.path.normpath("%s/%s" % (slave_dir, slave_name))
new_info = udev.get_block_device(os.path.realpath(path)[4:])
new_info = udev.get_device(os.path.realpath(path)) if new_info: self.addUdevDevice(new_info) if self.getDeviceByName(dev_name) is None:@@ -936,7 +936,7 @@ class DeviceTree(object):
if disk is None: # create a device instance for the disk
new_info = udev.get_block_device(os.path.dirname(sysfs_path))
new_info = udev.get_device(os.path.dirname(sysfs_path)) if new_info: self.addUdevDevice(new_info) disk = self.getDeviceByName(disk_name)@@ -1030,7 +1030,7 @@ class DeviceTree(object): if not container: parentSysName = mdraid.md_node_from_name(parentName) container_sysfs = "/class/block/" + parentSysName
container_info = udev.get_block_device(container_sysfs)
container_info = udev.get_device(container_sysfs) if not container_info: log.error("failed to find md container %s at %s", parentName, container_sysfs)@@ -1102,7 +1102,7 @@ class DeviceTree(object): name = udev.device_get_name(info) log_method_call(self, name=name) sysfs_path = udev.device_get_sysfs_path(info)
sys_file = "/sys/%s/loop/backing_file" % sysfs_path
sys_file = "%s/loop/backing_file" % sysfs_path backing_file = open(sys_file).read().strip() file_device = self.getDeviceByName(backing_file) if not file_device:@@ -1122,7 +1122,7 @@ class DeviceTree(object):
def addUdevDevice(self, info): name = udev.device_get_name(info)
log_method_call(self, name=name, info=pprint.pformat(info))
log_method_call(self, name=name, info=pprint.pformat(dict(info))) uuid = udev.device_get_uuid(info) sysfs_path = udev.device_get_sysfs_path(info)@@ -1490,7 +1490,7 @@ class DeviceTree(object):
if lv_device.status: lv_device.updateSysfsPath()
lv_info = udev.get_block_device(lv_device.sysfsPath)
lv_info = udev.get_device(lv_device.sysfsPath) if not lv_info: log.error("failed to get udev data for lv %s", lv_device.name) return@@ -1587,7 +1587,7 @@ class DeviceTree(object):
# check the list of devices udev knows about to see if the array # this device belongs to is already active
for dev in udev.get_block_devices():
for dev in udev.get_devices(): if not udev.device_is_md(dev): continue@@ -1682,13 +1682,13 @@ class DeviceTree(object): self._addDevice(dm_array)
# Wait for udev to scan the just created nodes, to avoid a race
# with the udev.get_block_device() call below.
# with the udev.get_device() call below. udev.settle() # Get the DMRaidArrayDevice a DiskLabel format *now*, in case # its partitions get scanned before it does. dm_array.updateSysfsPath()
dm_array_info = udev.get_block_device(dm_array.sysfsPath)
dm_array_info = udev.get_device(dm_array.sysfsPath) self.handleUdevDiskLabelFormat(dm_array_info, dm_array) # Use the rs's object on the device.@@ -1889,7 +1889,7 @@ class DeviceTree(object): def updateDeviceFormat(self, device): log.info("updating format of device: %s", device) try:
util.notify_kernel("/sys%s" % device.sysfsPath)
util.notify_kernel(device.sysfsPath) except (ValueError, IOError) as e: log.warning("failed to notify kernel of change: %s", e)@@ -2032,7 +2032,7 @@ class DeviceTree(object): self._addDevice(filedev) self._addDevice(loopdev) self._addDevice(dmdev)
info = udev.get_block_device(dmdev.sysfsPath)
info = udev.get_device(dmdev.sysfsPath) self.addUdevDevice(info)def backupConfigs(self, restore=False):
@@ -2146,18 +2146,19 @@ class DeviceTree(object): # blocks or since previous iterations. while True: devices = []
new_devices = udev.get_block_devices()
new_devices = udev.get_devices() for new_device in new_devices:
if new_device['name'] not in old_devices:old_devices[new_device['name']] = new_device
new_name = udev.device_get_name(new_device)if new_name not in old_devices:old_devices[new_name] = new_device devices.append(new_device) if len(devices) == 0: # nothing is changing -- we are finished building devices break
log.info("devices to scan: %s", [d['name'] for d in devices])
log.info("devices to scan: %s", [udev.device_get_name(d) for din devices]) for dev in devices: self.addUdevDevice(dev)
diff --git a/blivet/pyudev.py b/blivet/pyudev.py deleted file mode 100644 index fa0846f..0000000 --- a/blivet/pyudev.py +++ /dev/null @@ -1,226 +0,0 @@ -from __future__ import print_function
-import sys -import os -import fnmatch -from ctypes import CDLL, c_char_p, c_int, c_void_p
-# XXX this one may need some tweaking... -def find_library(name, somajor=0):
- env = os.environ.get("LD_LIBRARY_PATH")
- common = ["/lib64", "/lib"]
- if env:
libdirs = env.split(":") + common- else:
libdirs = common- for ldir in filter(os.path.isdir, libdirs):
files = fnmatch.filter(os.listdir(ldir), "lib%s.so.%d" % (name,somajor))
if files:return next(os.path.join(ldir, lfile) for lfile in files)- return None
-def get_library():
- name = "udev"
- somajor = 1
- lib = find_library(name=name, somajor=somajor)
- if not lib or not os.path.exists(lib):
raise ImportError("No library named %s.%d" % (name, somajor))- return lib
-# load the udev library -libudev = CDLL(get_library())
-# create aliases for needed functions and set the return types where needed -libudev_udev_new = libudev.udev_new -libudev_udev_new.argtypes = [] -libudev_udev_new.restype = c_void_p -libudev_udev_unref = libudev.udev_unref -libudev_udev_unref.argtypes = [ c_void_p ]
-libudev_udev_device_new_from_syspath = libudev.udev_device_new_from_syspath -libudev_udev_device_new_from_syspath.restype = c_void_p -libudev_udev_device_new_from_syspath.argtypes = [ c_void_p, c_char_p ] -libudev_udev_device_unref = libudev.udev_device_unref -libudev_udev_device_unref.argtypes = [ c_void_p ]
-libudev_udev_device_get_syspath = libudev.udev_device_get_syspath -libudev_udev_device_get_syspath.restype = c_char_p -libudev_udev_device_get_syspath.argtypes = [ c_void_p ] -libudev_udev_device_get_sysname = libudev.udev_device_get_sysname -libudev_udev_device_get_sysname.restype = c_char_p -libudev_udev_device_get_sysname.argtypes = [ c_void_p ] -libudev_udev_device_get_devpath = libudev.udev_device_get_devpath -libudev_udev_device_get_devpath.restype = c_char_p -libudev_udev_device_get_devpath.argtypes = [ c_void_p ] -libudev_udev_device_get_devtype = libudev.udev_device_get_devtype -libudev_udev_device_get_devtype.restype = c_char_p -libudev_udev_device_get_devtype.argtypes = [ c_void_p ] -libudev_udev_device_get_devnode = libudev.udev_device_get_devnode -libudev_udev_device_get_devnode.restype = c_char_p -libudev_udev_device_get_devnode.argtypes = [ c_void_p ] -libudev_udev_device_get_subsystem = libudev.udev_device_get_subsystem -libudev_udev_device_get_subsystem.restype = c_char_p -libudev_udev_device_get_subsystem.argtypes = [ c_void_p ] -libudev_udev_device_get_sysnum = libudev.udev_device_get_sysnum -libudev_udev_device_get_sysnum.restype = c_char_p -libudev_udev_device_get_sysnum.argtypes = [ c_void_p ]
-libudev_udev_device_get_properties_list_entry = libudev.udev_device_get_properties_list_entry -libudev_udev_device_get_properties_list_entry.restype = c_void_p -libudev_udev_device_get_properties_list_entry.argtypes = [ c_void_p ] -libudev_udev_list_entry_get_next = libudev.udev_list_entry_get_next -libudev_udev_list_entry_get_next.restype = c_void_p -libudev_udev_list_entry_get_next.argtypes = [ c_void_p ]
-libudev_udev_list_entry_get_name = libudev.udev_list_entry_get_name -libudev_udev_list_entry_get_name.restype = c_char_p -libudev_udev_list_entry_get_name.argtypes = [ c_void_p ] -libudev_udev_list_entry_get_value = libudev.udev_list_entry_get_value -libudev_udev_list_entry_get_value.restype = c_char_p -libudev_udev_list_entry_get_value.argtypes = [ c_void_p ]
-libudev_udev_enumerate_new = libudev.udev_enumerate_new -libudev_udev_enumerate_new.restype = c_void_p -libudev_udev_enumerate_new.argtypes = [ c_void_p ] -libudev_udev_enumerate_unref = libudev.udev_enumerate_unref -libudev_udev_enumerate_unref.argtypes = [ c_void_p ]
-libudev_udev_enumerate_add_match_subsystem = libudev.udev_enumerate_add_match_subsystem -libudev_udev_enumerate_add_match_subsystem.restype = c_int -libudev_udev_enumerate_add_match_subsystem.argtypes = [ c_void_p, c_char_p ] -libudev_udev_enumerate_scan_devices = libudev.udev_enumerate_scan_devices -libudev_udev_enumerate_scan_devices.restype = c_int -libudev_udev_enumerate_scan_devices.argtypes = [ c_void_p ] -libudev_udev_enumerate_get_list_entry = libudev.udev_enumerate_get_list_entry -libudev_udev_enumerate_get_list_entry.restype = c_void_p -libudev_udev_enumerate_get_list_entry.argtypes = [ c_void_p ]
-libudev_udev_device_get_devlinks_list_entry = libudev.udev_device_get_devlinks_list_entry -libudev_udev_device_get_devlinks_list_entry.restype = c_void_p -libudev_udev_device_get_devlinks_list_entry.argtypes = [ c_void_p ]
-class UdevDevice(dict):
- def __init__(self, udev, sysfs_path):
dict.__init__(self)# create new udev device from syspathudev_device = libudev_udev_device_new_from_syspath(udev, sysfs_path)if not udev_device:# device does not existreturn# set syspath and sysname propertiesself.syspath = libudev_udev_device_get_syspath(udev_device)self.sysname = libudev_udev_device_get_sysname(udev_device)# get the devlinks listdevlinks = []devlinks_entry =libudev_udev_device_get_devlinks_list_entry(udev_device)
while devlinks_entry:path = libudev_udev_list_entry_get_name(devlinks_entry)devlinks.append(path)devlinks_entry =libudev_udev_list_entry_get_next(devlinks_entry)
# add devlinks list to the dictionaryself["symlinks"] = devlinks# get the first property entryproperty_entry =libudev_udev_device_get_properties_list_entry(udev_device)
while property_entry:name = libudev_udev_list_entry_get_name(property_entry)value = libudev_udev_list_entry_get_value(property_entry)# lvm outputs values for multiple lvs in one line# we want to split them and make a list# if the first lv's value is empty we end up with a valuestarting
# with name=, prepend a space that our split does the rightthing
if value.startswith("%s=" % name):value = " " + valueif value.count(" %s=" % name):value = value.split(" %s=" % name)self[name] = value# get next property entryproperty_entry =libudev_udev_list_entry_get_next(property_entry)
# set additional propertiesself.devpath = libudev_udev_device_get_devpath(udev_device)self.subsystem = libudev_udev_device_get_subsystem(udev_device)self.devtype = libudev_udev_device_get_devtype(udev_device)self.sysnum = libudev_udev_device_get_sysnum(udev_device)self.devnode = libudev_udev_device_get_devnode(udev_device)# cleanuplibudev_udev_device_unref(udev_device)-class Udev(object):
- def __init__(self):
self.udev = libudev_udev_new()- def create_device(self, sysfs_path):
return UdevDevice(self.udev, sysfs_path)- def enumerate_devices(self, subsystem=None):
context = libudev_udev_enumerate_new(self.udev)# add the match subsystemif subsystem is not None:rc = libudev_udev_enumerate_add_match_subsystem(context,subsystem)
if not rc == 0:print("error: unable to add the match subsystem",file=sys.stderr)
libudev_udev_enumerate_unref(context)return []# scan the devicesrc = libudev_udev_enumerate_scan_devices(context)if not rc == 0:print("error: unable to enumerate the devices", file=sys.stderr)libudev_udev_enumerate_unref(context)return []# create the list of sysfs pathssysfs_paths = []# get the first list entrylist_entry = libudev_udev_enumerate_get_list_entry(context)while list_entry:sysfs_path = libudev_udev_list_entry_get_name(list_entry)sysfs_paths.append(sysfs_path)# get next list entrylist_entry = libudev_udev_list_entry_get_next(list_entry)# cleanuplibudev_udev_enumerate_unref(context)return sysfs_paths- def scan_devices(self, sysfs_paths=None):
if sysfs_paths is None:sysfs_paths = self.enumerate_devices()for sysfs_path in sysfs_paths:device = self.create_device(sysfs_path)if device:yield device- def unref(self):
libudev_udev_unref(self.udev)self.udev = Nonediff --git a/blivet/udev.py b/blivet/udev.py index b66e30b..d0eb543 100644 --- a/blivet/udev.py +++ b/blivet/udev.py @@ -27,45 +27,28 @@ import re from . import util from .size import Size
-from . import pyudev -global_udev = pyudev.Udev() +import pyudev +global_udev = pyudev.Context()
import logging log = logging.getLogger("blivet")
-def enumerate_devices(deviceClass="block"):
- devices = global_udev.enumerate_devices(subsystem=deviceClass)
- return [path[4:] for path in devices]
def get_device(sysfs_path):
- if not os.path.exists("/sys%s" % sysfs_path):
log.debug("%s does not exist", sysfs_path)return None- # XXX we remove the /sys part when enumerating devices,
- # so we have to prepend it when creating the device
- dev = global_udev.create_device("/sys" + sysfs_path)
- if dev:
dev["name"] = dev.sysnamedev["sysfs_path"] = sysfs_path# now add in the contents of the uevent file since they're handydev = parse_uevent_file(dev)
try:
dev = pyudev.Device.from_sys_path(global_udev, sysfs_path)except pyudev.DeviceNotFoundError as e:
log.error(e)dev = Nonereturn dev
-def get_devices(deviceClass="block"): +def get_devices(subsystem="block"): settle()
- entries = []
- for path in enumerate_devices(deviceClass):
entry = get_device(path)if entry:entries.append(entry)- return entries
- return [d for d in global_udev.list_devices(subsystem=subsystem)
if not __is_blacklisted_blockdev(d.sys_name)]def parse_uevent_file(dev):
- path = os.path.normpath("/sys/%s/uevent" % dev['sysfs_path'])
- path = os.path.normpath("%s/uevent" % device_get_sysfs_path(dev)) if not os.access(path, os.R_OK): return dev
@@ -103,7 +86,7 @@ def resolve_devspec(devspec): from . import devices
ret = None
- for dev in get_block_devices():
- for dev in get_devices(): if devspec.startswith("LABEL="): if device_get_label(dev) == devspec[6:]: ret = dev
@@ -120,7 +103,7 @@ def resolve_devspec(devspec): if not spec.startswith("/dev/"): spec = os.path.normpath("/dev/" + spec)
for link in dev["symlinks"]:
for link in device_get_symlinks(dev): if spec == link: ret = dev break@@ -135,37 +118,18 @@ def resolve_glob(glob): if not glob: return ret
- for dev in get_block_devices():
for dev in get_devices(): name = device_get_name(dev)
if fnmatch.fnmatch(name, glob): ret.append(name) else:
for link in dev["symlinks"]:
for link in device_get_symlinks(dev): if fnmatch.fnmatch(link, glob): ret.append(name)return ret
-def get_block_devices():
- settle()
- entries = []
- for path in enumerate_block_devices():
entry = get_block_device(path)if entry:if entry["name"].startswith("md"):# mdraid is really braindead, when a device is stopped# it is no longer usefull in anyway (and we should not# probe it) yet it still sticks around, see bug rh523387state = Nonestate_file = "/sys/%s/md/array_state" % entry["sysfs_path"]if os.access(state_file, os.R_OK):state = open(state_file).read().strip()if state == "clear":continueentries.append(entry)- return entries
def __is_blacklisted_blockdev(dev_name): """Is this a blockdev we never want for an install?""" if dev_name.startswith("ram") or dev_name.startswith("fd"): @@ -180,17 +144,6 @@ def __is_blacklisted_blockdev(dev_name):
return False-def enumerate_block_devices():
- return [d for d in enumerate_devices(deviceClass="block") if not
__is_blacklisted_blockdev(os.path.basename(d))]
-def get_block_device(sysfs_path):
- dev = get_device(sysfs_path)
- if not dev or 'name' not in dev:
return None- else:
return dev# These are functions for retrieving specific pieces of information from # udev database entries. def device_get_name(udev_info): @@ -198,7 +151,7 @@ def device_get_name(udev_info): if "DM_NAME" in udev_info: name = udev_info["DM_NAME"] else:
name = udev_info["name"]
name = udev_info.sys_namereturn name
@@ -236,7 +189,7 @@ def device_is_md(info):
# The udev information keeps shifting around. Only md arrays have a # /sys/class/block/<name>/md/ subdirectory.
- md_dir = "/sys" + device_get_sysfs_path(info) + "/md"
- md_dir = device_get_sysfs_path(info) + "/md" return os.path.exists(md_dir)
def device_is_cciss(info): @@ -256,7 +209,7 @@ def device_is_zfcp(info): if info.get("DEVTYPE") != "disk": return False
- subsystem = "/sys" + info.get("sysfs_path")
subsystem = device_get_sysfs_path(info)
while True: topdir = os.path.realpath(os.path.dirname(subsystem))
@@ -284,7 +237,7 @@ def device_get_zfcp_attribute(info, attr=None): log.debug("device_get_zfcp_attribute() called with attr=None") return None
- attribute = "/sys%s/device/%s" % (info.get("sysfs_path"), attr,)
attribute = "%s/device/%s" % (device_get_sysfs_path(info), attr) attribute = os.path.realpath(attribute)
if not os.path.isfile(attribute):
@@ -295,14 +248,14 @@ def device_get_zfcp_attribute(info, attr=None):
def device_get_dasd_bus_id(info): """ Return the CCW bus ID of the dasd device. """
- return info.get("sysfs_path").split("/")[-3]
- return device_get_sysfs_path(info).split("/")[-3]
def device_get_dasd_flag(info, flag=None): """ Return the specified flag for the dasd device. """ if flag is None: return None
- path = "/sys" + info.get("sysfs_path") + "/device/" + flag
- path = device_get_sysfs_path(info) + "/device/" + flag if not os.path.isfile(path): return None
@@ -318,17 +271,17 @@ def device_is_disk(info): """ Return True is the device is a disk. """ if device_is_cdrom(info): return False
- has_range = os.path.exists("/sys/%s/range" % info['sysfs_path'])
- has_range = os.path.exists("%s/range" % device_get_sysfs_path(info)) return info.get("DEVTYPE") == "disk" or has_range
def device_is_partition(info):
- has_start = os.path.exists("/sys/%s/start" % info['sysfs_path'])
- has_start = os.path.exists("%s/start" % device_get_sysfs_path(info)) return info.get("DEVTYPE") == "partition" or has_start
def device_is_loop(info): """ Return True if the device is a configured loop device. """ return (device_get_name(info).startswith("loop") and
os.path.isdir("/sys/%s/loop" % info['sysfs_path']))
os.path.isdir("%s/loop" % device_get_sysfs_path(info)))def device_get_serial(udev_info): """ Get the serial number/UUID from the device as reported by udev. """ @@ -356,7 +309,7 @@ def device_get_path(info): return info["ID_PATH"]
def device_get_symlinks(info):
- return info.get("symlinks", [])
- return info.get("DEVLINKS", [])
def device_get_by_path(info): for link in device_get_symlinks(info): @@ -366,7 +319,7 @@ def device_get_by_path(info): return device_get_name(info)
def device_get_sysfs_path(info):
- return info['sysfs_path']
- return info.sys_path
def device_get_major(info): return int(info["MAJOR"]) @@ -675,7 +628,7 @@ def device_get_iscsi_session(info): # The position of sessionX part depends on device # (e.g. offload vs. sw; also varies for different offload devs) session = None
- match = re.match(r'/.*/(session\d+)', info["sysfs_path"])
- match = re.match(r'/.*/(session\d+)', device_get_sysfs_path(info)) if match: session = match.groups()[0] else:
@@ -694,7 +647,7 @@ def device_get_iscsi_nic(info): def device_get_iscsi_initiator(info): initiator = None if device_is_partoff_iscsi(info):
host = re.match(r'.*/(host\d+)', info["sysfs_path"]).groups()[0]
host = re.match(r'.*/(host\d+)',device_get_sysfs_path(info)).groups()[0] if host: initiator_file = "/sys/class/iscsi_host/%s/initiatorname" % host if os.access(initiator_file, os.R_OK): @@ -738,10 +691,10 @@ def device_get_iscsi_initiator(info):
def _detect_broadcom_fcoe(info): re_pci_host=re.compile(r'/(.*)/(host\d+)')
- match = re_pci_host.match(info["sysfs_path"])
- match = re_pci_host.match(device_get_sysfs_path(info)) if match: sysfs_pci, host = match.groups()
if os.access('/sys/%s/%s/fc_host' %(sysfs_pci, host), os.X_OK) and \
return (None, None)if os.access('%s/%s/fc_host' %(sysfs_pci, host), os.X_OK) and \ 'net' in sysfs_pci: return (sysfs_pci, host)@@ -757,7 +710,7 @@ def device_is_fcoe(info): path_components[2] == "fc": return True
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]:
if path.startswith("fc-") and "fcoe" in device_get_sysfs_path(info): return True
if _detect_broadcom_fcoe(info) != (None, None):
@@ -768,20 +721,21 @@ def device_is_fcoe(info): def device_get_fcoe_nic(info): path = info.get("ID_PATH", "") path_components = path.split("-")
sysfs_path = device_get_sysfs_path(info)
if path.startswith("pci-eth") and len(path_components) >= 4 and \ path_components[2] == "fc": return path_components[1]
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]:
return info["sysfs_path"].split("/")[4].split(".")[0]
if path.startswith("fc-") and "fcoe" in sysfs_path:
return sysfs_path.split("/")[4].split(".")[0](sysfs_pci, host) = _detect_broadcom_fcoe(info) if (sysfs_pci, host) != (None, None):
net, iface = info['sysfs_path'].split("/")[5:7]
net, iface = sysfs_path.split("/")[5:7] if net != "net":
log.warning("unexpected sysfs_path of bnx2fc device: %s",info['sysfs_path'])
match = re.compile(r'.*/net/([^/]*)').match(info['sysfs_path'])
log.warning("unexpected sysfs_path of bnx2fc device: %s",sysfs_path)
match = re.compile(r'.*/net/([^/]*)').match(sysfs_path) if match: return match.groups()[0].split(".")[0] else:@@ -795,7 +749,7 @@ def device_get_fcoe_identifier(info): path_components[2] == "fc": return path_components[3]
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]:
if path.startswith("fc-") and "fcoe" in device_get_sysfs_path(info): return path_components[1]
if device_is_fcoe(info) and len(path_components) >= 4 and \
diff --git a/blivet/util.py b/blivet/util.py index a15bb4a..28dc125 100644 --- a/blivet/util.py +++ b/blivet/util.py @@ -178,7 +178,7 @@ def get_sysfs_attr(path, attr): log.debug("get_sysfs_attr() called with attr=None") return None
- attribute = "/sys%s/%s" % (path, attr)
attribute = "%s/%s" % (path, attr) attribute = os.path.realpath(attribute)
if not os.path.isfile(attribute) and not os.path.islink(attribute):
diff --git a/python-blivet.spec b/python-blivet.spec index abbbb0f..b668d94 100644 --- a/python-blivet.spec +++ b/python-blivet.spec @@ -28,6 +28,7 @@ Requires: python Requires: python-six Requires: pykickstart >= %{pykickstartver} Requires: util-linux >= %{utillinuxver} +Requires: python-pyudev Requires: parted >= %{partedver} Requires: pyparted >= %{pypartedver} Requires: device-mapper >= %{dmver} diff --git a/tests/udev_test.py b/tests/udev_test.py index a7b09ab..86cc434 100644 --- a/tests/udev_test.py +++ b/tests/udev_test.py @@ -11,94 +11,11 @@ class UdevTest(unittest.TestCase): blivet.udev.os = mock.Mock() blivet.udev.log = mock.Mock()
- def test_udev_enumerate_devices(self):
- def test_udev_get_device(self): import blivet.udev
ENUMERATE_LIST = ['/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
'/sys/devices/virtual/block/loop0','/sys/devices/virtual/block/loop1','/sys/devices/virtual/block/ram0','/sys/devices/virtual/block/ram1','/sys/devices/virtual/block/dm-0',]blivet.udev.global_udev.enumerate_devices =mock.Mock(return_value=ENUMERATE_LIST)
ret = blivet.udev.enumerate_devices()self.assertEqual(set(ret),set(['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
'/devices/virtual/block/loop0', '/devices/virtual/block/loop1','/devices/virtual/block/ram0', '/devices/virtual/block/ram1','/devices/virtual/block/dm-0']))- def test_udev_get_device_1(self):
import blivet.udevclass Device(object):def __init__(self):self.sysname = 'loop1'self.dict = {'symlinks': ['/dev/block/7:1'],'SUBSYSTEM': 'block','MAJOR': '7','DEVPATH': '/devices/virtual/block/loop1','UDISKS_PRESENTATION_NOPOLICY': '1','UDEV_LOG': '3','DEVNAME': '/dev/loop1','DEVTYPE': 'disk','DEVLINKS': '/dev/block/7:1','MINOR': '1'}def __getitem__(self, key):return self.dict[key]def __setitem__(self, key, value):self.dict[key] = valueblivet.udev.os.path.exists.return_value = TrueDEV_PATH = '/devices/virtual/block/loop1'dev = Device()blivet.udev.global_udev = mock.Mock()blivet.udev.global_udev.create_device.return_value = devsaved = blivet.udev.parse_uevent_fileblivet.udev.parse_uevent_file = mock.Mock(return_value=dev)ret = blivet.udev.get_device(DEV_PATH)self.assertTrue(isinstance(ret, Device))self.assertEqual(ret['name'], ret.sysname)self.assertEqual(ret['sysfs_path'], DEV_PATH)self.assertTrue(blivet.udev.parse_uevent_file.called)blivet.udev.parse_uevent_file = saved- def test_udev_get_device_2(self):
import blivet.udevblivet.udev.os.path.exists.return_value = Falseret = blivet.udev.get_device('')self.assertEqual(ret, None)- def test_udev_get_device_3(self):
import blivet.udevblivet.udev.os.path.exists.return_value = Trueblivet.udev.global_udev = mock.Mock()blivet.udev.global_udev.create_device.return_value = Noneret = blivet.udev.get_device('')self.assertEqual(ret, None)- def test_udev_get_devices(self):
import blivet.udevsaved = blivet.udev.settleblivet.udev.settle = mock.Mock()DEVS = \['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
'/devices/virtual/block/loop0', '/devices/virtual/block/loop1','/devices/virtual/block/ram0', '/devices/virtual/block/ram1','/devices/virtual/block/dm-0']blivet.udev.enumerate_devices = mock.Mock(return_value=DEVS)blivet.udev.get_device = lambda x: xret = blivet.udev.get_devices()self.assertEqual(ret, DEVS)blivet.udev.settle = saved
devices = blivet.udev.global_udev.list_devices(subsystem="block")for device in devices:self.assertNotEqual(blivet.udev.get_device(device.sys_path),None)
def test_udev_parse_uevent_file_1(self): import blivet.udev-- 1.9.3
anaconda-patches mailing list anaconda-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
A couple of comments:
* mddetail will not have UUID if the level is Container. * It might be a good idea to attach docstrings to the udev.py methods, since they've been worked over so much otherwise. * You get rid of the use of parse_uevent_file. Apparently, parsing the uevent file was a way of obtaining additional information not obtained from pyudev/libudev. Can we guarantee that the pyudev library obtains all the data previously obtained by our pyudev library + parse_uevent_file() method.
- mulhern
On 08/01/2014 10:34 AM, Anne Mulhern wrote:
----- Original Message -----
From: "David Lehman" dlehman@redhat.com To: anaconda-patches@lists.fedorahosted.org Sent: Friday, August 1, 2014 1:22:29 AM Subject: [PATCH 1/6] Replace our pyudev with the package python-pyudev.
There are two major differences in how we use the module. Each device is represented by a pyudev.Device instance, which is based on collections.abc.Mapping. That means we can no longer change the data to do things like set a "multipath_member" format type or inject LVM or MD metadata.
The other difference is that sysfs paths now include the "/sys", which is great since it's always mounted in the same place.
blivet/deviceaction.py | 4 +- blivet/devices.py | 95 +++++++-------------- blivet/devicetree.py | 49 +++++------ blivet/pyudev.py | 226
blivet/udev.py | 122 +++++++++----------------- blivet/util.py | 2 +- python-blivet.spec | 1 + tests/udev_test.py | 91 +------------------- 8 files changed, 99 insertions(+), 491 deletions(-) delete mode 100644 blivet/pyudev.py
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py index db4c7a7..d2818c1 100644 --- a/blivet/deviceaction.py +++ b/blivet/deviceaction.py @@ -553,9 +553,7 @@ class ActionCreateFormat(DeviceAction): self.device.format.create(device=self.device.path, options=self.device.formatArgs) # Get the UUID now that the format is created
udev.settle()self.device.updateSysfsPath()info = udev.get_block_device(self.device.sysfsPath)
info = udev.get_device(self.device.sysfsPath) # only do this if the format has a device known to udev # (the format might not have a normal device at all) if info:diff --git a/blivet/devices.py b/blivet/devices.py index c238e94..25b7586 100644 --- a/blivet/devices.py +++ b/blivet/devices.py @@ -27,6 +27,7 @@ import tempfile import abc from decimal import Decimal import re +import pyudev
from six import add_metaclass
@@ -107,7 +108,7 @@ def deviceNameToDiskByPath(deviceName=None): return ""
ret = None
- for dev in udev.get_block_devices():
- for dev in udev.get_devices(): if udev.device_get_name(dev) == deviceName: ret = udev.device_get_by_path(dev) break
@@ -508,7 +509,6 @@ class StorageDevice(Device):
_type = "blivet" _devDir = "/dev"
- sysfsBlockDir = "class/block" _formatImmutable = False _partitionable = False _isDisk = False
@@ -751,11 +751,22 @@ class StorageDevice(Device):
def updateSysfsPath(self): """ Update this device's sysfs path. """
log_method_call(self, self.name, status=self.status)sysfsName = self.name.replace("/", "!")path = os.path.join("/sys", self.sysfsBlockDir, sysfsName)self.sysfsPath = os.path.realpath(path)[4:]log.debug("%s sysfsPath set to %s", self.name, self.sysfsPath)
# We're using os.path.exists as a stand-in for status. We can't use# the status property directly because MDRaidArrayDevice.statuscalls
# this method.log_method_call(self, self.name, status=os.path.exists(self.path))if not self.exists:raise errors.DeviceError("device has not been created",self.name)
try:udev_device = pyudev.Device.from_device_file(udev.global_udev,self.path)except pyudev.DeviceNotFoundError as e:log.error("failed to update sysfs path for %s: %s", self.name,e)
self.sysfsPath = ''else:self.sysfsPath = udev_device.sys_pathlog.debug("%s sysfsPath set to %s", self.name, self.sysfsPath) @property def formatArgs(self):@@ -780,7 +791,7 @@ class StorageDevice(Device): log.debug("not sending change uevent for inactive device") return
path = os.path.normpath("/sys/%s" % self.sysfsPath)
path = os.path.normpath(self.sysfsPath) try: util.notify_kernel(path, action="change") except (ValueError, IOError) as e:@@ -1055,7 +1066,7 @@ class StorageDevice(Device):
@property def removable(self):
devpath = os.path.normpath("/sys/%s" % self.sysfsPath)
devpath = os.path.normpath(self.sysfsPath) remfile = os.path.normpath("%s/removable" % devpath) return (self.sysfsPath and os.path.exists(devpath) and os.access(remfile, os.R_OK) and@@ -1575,23 +1586,6 @@ class PartitionDevice(StorageDevice): weight = property(lambda d: d._getWeight(), lambda d,w: d._setWeight(w))
- def updateSysfsPath(self):
""" Update this device's sysfs path. """log_method_call(self, self.name, status=self.status)if not self.parents:self.sysfsPath = ''elif isinstance(self.parents[0], DMDevice):dm_node = dm.dm_node_from_name(self.name)path = os.path.join("/sys", self.sysfsBlockDir, dm_node)self.sysfsPath = os.path.realpath(path)[4:]elif isinstance(self.parents[0], MDRaidArrayDevice):md_node = mdraid.md_node_from_name(self.name)path = os.path.join("/sys", self.sysfsBlockDir, md_node)self.sysfsPath = os.path.realpath(path)[4:]else:StorageDevice.updateSysfsPath(self)def _setName(self, value): self._name = value # actual name setting is done by parted@@ -2054,19 +2048,6 @@ class DMDevice(StorageDevice): None) return (match.live_table and not match.suspended) if match else False
- def updateSysfsPath(self):
""" Update this device's sysfs path. """log_method_call(self, self.name, status=self.status)if not self.exists:raise errors.DeviceError("device has not been created",self.name)
if self.status:dm_node = self.getDMNode()path = os.path.join("/sys", self.sysfsBlockDir, dm_node)self.sysfsPath = os.path.realpath(path)[4:]else:self.sysfsPath = ''#def getTargetType(self): # return dm.getDmTarget(name=self.name)@@ -3810,22 +3791,6 @@ class MDRaidArrayDevice(ContainerDevice):
spares = property(_getSpares, _setSpares)
- def updateSysfsPath(self):
""" Update this device's sysfs path. """# don't include self.status here since this method is called by# MDRaidArrayDevice.statuslog_method_call(self, self.name)if not self.exists:raise errors.DeviceError("device has not been created",self.name)
# We don't use self.status here because self.status requires a valid# sysfs path to function correctly.if os.path.exists(self.path):md_node = mdraid.md_node_from_name(self.name)self.sysfsPath = "/devices/virtual/block/%s" % md_nodeelse:self.sysfsPath = ''def _addParent(self, member): super(MDRaidArrayDevice, self)._addParent(member)@@ -3886,7 +3851,7 @@ class MDRaidArrayDevice(ContainerDevice): self.updateSysfsPath()
# make sure the active array is the one we expect
info = udev.get_block_device(self.sysfsPath)
info = udev.get_device(self.sysfsPath) uuid = udev.device_get_md_uuid(info) if uuid and uuid != self.uuid: log.warning("md array %s is active, but has UUID %s -- not %s",@@ -3894,7 +3859,7 @@ class MDRaidArrayDevice(ContainerDevice): self.sysfsPath = "" return status
state_file = "/sys/%s/md/array_state" % self.sysfsPath
state_file = "%s/md/array_state" % self.sysfsPath try: state = open(state_file).read().strip() if state in ("clean", "active", "active-idle", "readonly", "read-auto"):@@ -3924,7 +3889,7 @@ class MDRaidArrayDevice(ContainerDevice): def degraded(self): """ Return True if the array is running in degraded mode. """ rc = False
degraded_file = "/sys/%s/md/degraded" % self.sysfsPath
degraded_file = "%s/md/degraded" % self.sysfsPath if os.access(degraded_file, os.R_OK): val = open(degraded_file).read().strip() if val == "1":@@ -3982,7 +3947,7 @@ class MDRaidArrayDevice(ContainerDevice): # mdadm reuses minors indiscriminantly when there is no mdadm.conf, so # we need to clear the sysfs path now so our status method continues to # give valid results
self.updateSysfsPath()
self.sysfsPath = '' def teardown(self, recursive=None): """ Close, or tear down, a device. """@@ -4024,15 +3989,13 @@ class MDRaidArrayDevice(ContainerDevice):
def _postCreate(self): # this is critical since our status method requires a valid sysfs path
md_node = mdraid.md_node_from_name(self.name)self.sysfsPath = "/devices/virtual/block/%s" % md_nodeself.exists = True # I think we can remove this.
self.exists = True # this is needed to run updateSysfsPathself.updateSysfsPath() StorageDevice._postCreate(self) # update our uuid attribute with the new array's UUID
info = udev.get_block_device(self.sysfsPath)self.uuid = udev.device_get_md_uuid(info)
info = mdraid.mddetail(self.path)self.uuid = info.get("UUID") for member in self.devices: member.format.mdUuid = self.uuid@@ -5229,7 +5192,7 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
def _postCreate(self): super(BTRFSVolumeDevice, self)._postCreate()
info = udev.get_block_device(self.sysfsPath)
info = udev.get_device(self.sysfsPath) if not info: log.error("failed to get updated udev info for new btrfs volume") else:diff --git a/blivet/devicetree.py b/blivet/devicetree.py index c4cb1b7..755f782 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -660,7 +660,7 @@ class DeviceTree(object):
if self.udevDeviceIsDisk(info): # Ignore any readonly disks
if util.get_sysfs_attr(info["sysfs_path"], 'ro') == '1':
if util.get_sysfs_attr(udev.device_get_sysfs_path(info), 'ro')== '1': log.debug("Ignoring read only device %s", name) # FIXME: We have to handle this better, ie: not ignore these. self.addIgnoredDisk(name) @@ -706,10 +706,10 @@ class DeviceTree(object): if not device: # initiate detection of all PVs and hope that it leads to us having # the VG and LVs in the tree
for pv_name in os.listdir("/sys" + sysfs_path + "/slaves"):link = os.readlink("/sys" + sysfs_path + "/slaves/" +pv_name)
for pv_name in os.listdir(sysfs_path + "/slaves"):link = os.readlink(sysfs_path + "/slaves/" + pv_name) pv_sysfs_path = os.path.normpath(sysfs_path + '/slaves/' + link)
pv_info = udev.get_block_device(pv_sysfs_path)
pv_info = udev.get_device(pv_sysfs_path) self.addUdevDevice(pv_info) vg_name = udev.device_get_lv_vg_name(info)@@ -752,7 +752,7 @@ class DeviceTree(object): if device is None: # we couldn't find it, so create it # first, get a list of the slave devs and look them up
slave_dir = os.path.normpath("/sys/%s/slaves" % sysfs_path)
slave_dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(slave_dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name first@@ -762,7 +762,7 @@ class DeviceTree(object): dev_name = slave_name.replace("!", "/") # handles cciss slave_dev = self.getDeviceByName(dev_name) path = os.path.normpath("%s/%s" % (slave_dir, slave_name))
new_info = udev.get_block_device(os.path.realpath(path)[4:])
new_info = udev.get_device(os.path.realpath(path)) if not slave_dev: # we haven't scanned the slave yet, so do it now if new_info:@@ -822,7 +822,7 @@ class DeviceTree(object): # TODO: look for this device by dm-uuid?
# first, get a list of the slave devs and look them up
slave_dir = os.path.normpath("/sys/%s/slaves" % sysfs_path)
slave_dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(slave_dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name first@@ -832,7 +832,7 @@ class DeviceTree(object): dev_name = slave_name.replace("!", "/") # handles cciss slave_dev = self.getDeviceByName(dev_name) path = os.path.normpath("%s/%s" % (slave_dir, slave_name))
new_info = udev.get_block_device(os.path.realpath(path)[4:])
new_info = udev.get_device(os.path.realpath(path)) if not slave_dev: # we haven't scanned the slave yet, so do it now if new_info:@@ -865,7 +865,7 @@ class DeviceTree(object): log_method_call(self, name=name) sysfs_path = udev.device_get_sysfs_path(info)
slave_dir = os.path.normpath("/sys/%s/slaves" % sysfs_path)
slave_dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(slave_dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name@@ -877,7 +877,7 @@ class DeviceTree(object): if not slave_dev: # we haven't scanned the slave yet, so do it now path = os.path.normpath("%s/%s" % (slave_dir, slave_name))
new_info = udev.get_block_device(os.path.realpath(path)[4:])
new_info = udev.get_device(os.path.realpath(path)) if new_info: self.addUdevDevice(new_info) if self.getDeviceByName(dev_name) is None:@@ -936,7 +936,7 @@ class DeviceTree(object):
if disk is None: # create a device instance for the disk
new_info = udev.get_block_device(os.path.dirname(sysfs_path))
new_info = udev.get_device(os.path.dirname(sysfs_path)) if new_info: self.addUdevDevice(new_info) disk = self.getDeviceByName(disk_name)@@ -1030,7 +1030,7 @@ class DeviceTree(object): if not container: parentSysName = mdraid.md_node_from_name(parentName) container_sysfs = "/class/block/" + parentSysName
container_info = udev.get_block_device(container_sysfs)
container_info = udev.get_device(container_sysfs) if not container_info: log.error("failed to find md container %s at %s", parentName, container_sysfs)@@ -1102,7 +1102,7 @@ class DeviceTree(object): name = udev.device_get_name(info) log_method_call(self, name=name) sysfs_path = udev.device_get_sysfs_path(info)
sys_file = "/sys/%s/loop/backing_file" % sysfs_path
sys_file = "%s/loop/backing_file" % sysfs_path backing_file = open(sys_file).read().strip() file_device = self.getDeviceByName(backing_file) if not file_device:@@ -1122,7 +1122,7 @@ class DeviceTree(object):
def addUdevDevice(self, info): name = udev.device_get_name(info)
log_method_call(self, name=name, info=pprint.pformat(info))
log_method_call(self, name=name, info=pprint.pformat(dict(info))) uuid = udev.device_get_uuid(info) sysfs_path = udev.device_get_sysfs_path(info)@@ -1490,7 +1490,7 @@ class DeviceTree(object):
if lv_device.status: lv_device.updateSysfsPath()
lv_info = udev.get_block_device(lv_device.sysfsPath)
lv_info = udev.get_device(lv_device.sysfsPath) if not lv_info: log.error("failed to get udev data for lv %s", lv_device.name) return@@ -1587,7 +1587,7 @@ class DeviceTree(object):
# check the list of devices udev knows about to see if the array # this device belongs to is already active
for dev in udev.get_block_devices():
for dev in udev.get_devices(): if not udev.device_is_md(dev): continue@@ -1682,13 +1682,13 @@ class DeviceTree(object): self._addDevice(dm_array)
# Wait for udev to scan the just created nodes, to avoid a race
# with the udev.get_block_device() call below.
# with the udev.get_device() call below. udev.settle() # Get the DMRaidArrayDevice a DiskLabel format *now*, in case # its partitions get scanned before it does. dm_array.updateSysfsPath()
dm_array_info = udev.get_block_device(dm_array.sysfsPath)
dm_array_info = udev.get_device(dm_array.sysfsPath) self.handleUdevDiskLabelFormat(dm_array_info, dm_array) # Use the rs's object on the device.@@ -1889,7 +1889,7 @@ class DeviceTree(object): def updateDeviceFormat(self, device): log.info("updating format of device: %s", device) try:
util.notify_kernel("/sys%s" % device.sysfsPath)
util.notify_kernel(device.sysfsPath) except (ValueError, IOError) as e: log.warning("failed to notify kernel of change: %s", e)@@ -2032,7 +2032,7 @@ class DeviceTree(object): self._addDevice(filedev) self._addDevice(loopdev) self._addDevice(dmdev)
info = udev.get_block_device(dmdev.sysfsPath)
info = udev.get_device(dmdev.sysfsPath) self.addUdevDevice(info) def backupConfigs(self, restore=False):@@ -2146,18 +2146,19 @@ class DeviceTree(object): # blocks or since previous iterations. while True: devices = []
new_devices = udev.get_block_devices()
new_devices = udev.get_devices() for new_device in new_devices:
if new_device['name'] not in old_devices:old_devices[new_device['name']] = new_device
new_name = udev.device_get_name(new_device)if new_name not in old_devices:old_devices[new_name] = new_device devices.append(new_device) if len(devices) == 0: # nothing is changing -- we are finished building devices break
log.info("devices to scan: %s", [d['name'] for d in devices])
log.info("devices to scan: %s", [udev.device_get_name(d) for din devices]) for dev in devices: self.addUdevDevice(dev)
diff --git a/blivet/pyudev.py b/blivet/pyudev.py deleted file mode 100644 index fa0846f..0000000 --- a/blivet/pyudev.py +++ /dev/null @@ -1,226 +0,0 @@ -from __future__ import print_function
-import sys -import os -import fnmatch -from ctypes import CDLL, c_char_p, c_int, c_void_p
-# XXX this one may need some tweaking... -def find_library(name, somajor=0):
- env = os.environ.get("LD_LIBRARY_PATH")
- common = ["/lib64", "/lib"]
- if env:
libdirs = env.split(":") + common- else:
libdirs = common- for ldir in filter(os.path.isdir, libdirs):
files = fnmatch.filter(os.listdir(ldir), "lib%s.so.%d" % (name,somajor))
if files:return next(os.path.join(ldir, lfile) for lfile in files)- return None
-def get_library():
- name = "udev"
- somajor = 1
- lib = find_library(name=name, somajor=somajor)
- if not lib or not os.path.exists(lib):
raise ImportError("No library named %s.%d" % (name, somajor))- return lib
-# load the udev library -libudev = CDLL(get_library())
-# create aliases for needed functions and set the return types where needed -libudev_udev_new = libudev.udev_new -libudev_udev_new.argtypes = [] -libudev_udev_new.restype = c_void_p -libudev_udev_unref = libudev.udev_unref -libudev_udev_unref.argtypes = [ c_void_p ]
-libudev_udev_device_new_from_syspath = libudev.udev_device_new_from_syspath -libudev_udev_device_new_from_syspath.restype = c_void_p -libudev_udev_device_new_from_syspath.argtypes = [ c_void_p, c_char_p ] -libudev_udev_device_unref = libudev.udev_device_unref -libudev_udev_device_unref.argtypes = [ c_void_p ]
-libudev_udev_device_get_syspath = libudev.udev_device_get_syspath -libudev_udev_device_get_syspath.restype = c_char_p -libudev_udev_device_get_syspath.argtypes = [ c_void_p ] -libudev_udev_device_get_sysname = libudev.udev_device_get_sysname -libudev_udev_device_get_sysname.restype = c_char_p -libudev_udev_device_get_sysname.argtypes = [ c_void_p ] -libudev_udev_device_get_devpath = libudev.udev_device_get_devpath -libudev_udev_device_get_devpath.restype = c_char_p -libudev_udev_device_get_devpath.argtypes = [ c_void_p ] -libudev_udev_device_get_devtype = libudev.udev_device_get_devtype -libudev_udev_device_get_devtype.restype = c_char_p -libudev_udev_device_get_devtype.argtypes = [ c_void_p ] -libudev_udev_device_get_devnode = libudev.udev_device_get_devnode -libudev_udev_device_get_devnode.restype = c_char_p -libudev_udev_device_get_devnode.argtypes = [ c_void_p ] -libudev_udev_device_get_subsystem = libudev.udev_device_get_subsystem -libudev_udev_device_get_subsystem.restype = c_char_p -libudev_udev_device_get_subsystem.argtypes = [ c_void_p ] -libudev_udev_device_get_sysnum = libudev.udev_device_get_sysnum -libudev_udev_device_get_sysnum.restype = c_char_p -libudev_udev_device_get_sysnum.argtypes = [ c_void_p ]
-libudev_udev_device_get_properties_list_entry = libudev.udev_device_get_properties_list_entry -libudev_udev_device_get_properties_list_entry.restype = c_void_p -libudev_udev_device_get_properties_list_entry.argtypes = [ c_void_p ] -libudev_udev_list_entry_get_next = libudev.udev_list_entry_get_next -libudev_udev_list_entry_get_next.restype = c_void_p -libudev_udev_list_entry_get_next.argtypes = [ c_void_p ]
-libudev_udev_list_entry_get_name = libudev.udev_list_entry_get_name -libudev_udev_list_entry_get_name.restype = c_char_p -libudev_udev_list_entry_get_name.argtypes = [ c_void_p ] -libudev_udev_list_entry_get_value = libudev.udev_list_entry_get_value -libudev_udev_list_entry_get_value.restype = c_char_p -libudev_udev_list_entry_get_value.argtypes = [ c_void_p ]
-libudev_udev_enumerate_new = libudev.udev_enumerate_new -libudev_udev_enumerate_new.restype = c_void_p -libudev_udev_enumerate_new.argtypes = [ c_void_p ] -libudev_udev_enumerate_unref = libudev.udev_enumerate_unref -libudev_udev_enumerate_unref.argtypes = [ c_void_p ]
-libudev_udev_enumerate_add_match_subsystem = libudev.udev_enumerate_add_match_subsystem -libudev_udev_enumerate_add_match_subsystem.restype = c_int -libudev_udev_enumerate_add_match_subsystem.argtypes = [ c_void_p, c_char_p ] -libudev_udev_enumerate_scan_devices = libudev.udev_enumerate_scan_devices -libudev_udev_enumerate_scan_devices.restype = c_int -libudev_udev_enumerate_scan_devices.argtypes = [ c_void_p ] -libudev_udev_enumerate_get_list_entry = libudev.udev_enumerate_get_list_entry -libudev_udev_enumerate_get_list_entry.restype = c_void_p -libudev_udev_enumerate_get_list_entry.argtypes = [ c_void_p ]
-libudev_udev_device_get_devlinks_list_entry = libudev.udev_device_get_devlinks_list_entry -libudev_udev_device_get_devlinks_list_entry.restype = c_void_p -libudev_udev_device_get_devlinks_list_entry.argtypes = [ c_void_p ]
-class UdevDevice(dict):
- def __init__(self, udev, sysfs_path):
dict.__init__(self)# create new udev device from syspathudev_device = libudev_udev_device_new_from_syspath(udev, sysfs_path)if not udev_device:# device does not existreturn# set syspath and sysname propertiesself.syspath = libudev_udev_device_get_syspath(udev_device)self.sysname = libudev_udev_device_get_sysname(udev_device)# get the devlinks listdevlinks = []devlinks_entry =libudev_udev_device_get_devlinks_list_entry(udev_device)
while devlinks_entry:path = libudev_udev_list_entry_get_name(devlinks_entry)devlinks.append(path)devlinks_entry =libudev_udev_list_entry_get_next(devlinks_entry)
# add devlinks list to the dictionaryself["symlinks"] = devlinks# get the first property entryproperty_entry =libudev_udev_device_get_properties_list_entry(udev_device)
while property_entry:name = libudev_udev_list_entry_get_name(property_entry)value = libudev_udev_list_entry_get_value(property_entry)# lvm outputs values for multiple lvs in one line# we want to split them and make a list# if the first lv's value is empty we end up with a valuestarting
# with name=, prepend a space that our split does the rightthing
if value.startswith("%s=" % name):value = " " + valueif value.count(" %s=" % name):value = value.split(" %s=" % name)self[name] = value# get next property entryproperty_entry =libudev_udev_list_entry_get_next(property_entry)
# set additional propertiesself.devpath = libudev_udev_device_get_devpath(udev_device)self.subsystem = libudev_udev_device_get_subsystem(udev_device)self.devtype = libudev_udev_device_get_devtype(udev_device)self.sysnum = libudev_udev_device_get_sysnum(udev_device)self.devnode = libudev_udev_device_get_devnode(udev_device)# cleanuplibudev_udev_device_unref(udev_device)-class Udev(object):
- def __init__(self):
self.udev = libudev_udev_new()- def create_device(self, sysfs_path):
return UdevDevice(self.udev, sysfs_path)- def enumerate_devices(self, subsystem=None):
context = libudev_udev_enumerate_new(self.udev)# add the match subsystemif subsystem is not None:rc = libudev_udev_enumerate_add_match_subsystem(context,subsystem)
if not rc == 0:print("error: unable to add the match subsystem",file=sys.stderr)
libudev_udev_enumerate_unref(context)return []# scan the devicesrc = libudev_udev_enumerate_scan_devices(context)if not rc == 0:print("error: unable to enumerate the devices", file=sys.stderr)libudev_udev_enumerate_unref(context)return []# create the list of sysfs pathssysfs_paths = []# get the first list entrylist_entry = libudev_udev_enumerate_get_list_entry(context)while list_entry:sysfs_path = libudev_udev_list_entry_get_name(list_entry)sysfs_paths.append(sysfs_path)# get next list entrylist_entry = libudev_udev_list_entry_get_next(list_entry)# cleanuplibudev_udev_enumerate_unref(context)return sysfs_paths- def scan_devices(self, sysfs_paths=None):
if sysfs_paths is None:sysfs_paths = self.enumerate_devices()for sysfs_path in sysfs_paths:device = self.create_device(sysfs_path)if device:yield device- def unref(self):
libudev_udev_unref(self.udev)self.udev = Nonediff --git a/blivet/udev.py b/blivet/udev.py index b66e30b..d0eb543 100644 --- a/blivet/udev.py +++ b/blivet/udev.py @@ -27,45 +27,28 @@ import re from . import util from .size import Size
-from . import pyudev -global_udev = pyudev.Udev() +import pyudev +global_udev = pyudev.Context()
import logging log = logging.getLogger("blivet")
-def enumerate_devices(deviceClass="block"):
- devices = global_udev.enumerate_devices(subsystem=deviceClass)
- return [path[4:] for path in devices]
- def get_device(sysfs_path):
- if not os.path.exists("/sys%s" % sysfs_path):
log.debug("%s does not exist", sysfs_path)return None- # XXX we remove the /sys part when enumerating devices,
- # so we have to prepend it when creating the device
- dev = global_udev.create_device("/sys" + sysfs_path)
- if dev:
dev["name"] = dev.sysnamedev["sysfs_path"] = sysfs_path# now add in the contents of the uevent file since they're handydev = parse_uevent_file(dev)
try:
dev = pyudev.Device.from_sys_path(global_udev, sysfs_path)except pyudev.DeviceNotFoundError as e:
log.error(e)dev = None return dev-def get_devices(deviceClass="block"): +def get_devices(subsystem="block"): settle()
- entries = []
- for path in enumerate_devices(deviceClass):
entry = get_device(path)if entry:entries.append(entry)- return entries
return [d for d in global_udev.list_devices(subsystem=subsystem)
if not __is_blacklisted_blockdev(d.sys_name)]def parse_uevent_file(dev):
- path = os.path.normpath("/sys/%s/uevent" % dev['sysfs_path'])
- path = os.path.normpath("%s/uevent" % device_get_sysfs_path(dev)) if not os.access(path, os.R_OK): return dev
@@ -103,7 +86,7 @@ def resolve_devspec(devspec): from . import devices
ret = None
- for dev in get_block_devices():
- for dev in get_devices(): if devspec.startswith("LABEL="): if device_get_label(dev) == devspec[6:]: ret = dev
@@ -120,7 +103,7 @@ def resolve_devspec(devspec): if not spec.startswith("/dev/"): spec = os.path.normpath("/dev/" + spec)
for link in dev["symlinks"]:
for link in device_get_symlinks(dev): if spec == link: ret = dev break@@ -135,37 +118,18 @@ def resolve_glob(glob): if not glob: return ret
- for dev in get_block_devices():
for dev in get_devices(): name = device_get_name(dev)
if fnmatch.fnmatch(name, glob): ret.append(name) else:
for link in dev["symlinks"]:
for link in device_get_symlinks(dev): if fnmatch.fnmatch(link, glob): ret.append(name) return ret-def get_block_devices():
- settle()
- entries = []
- for path in enumerate_block_devices():
entry = get_block_device(path)if entry:if entry["name"].startswith("md"):# mdraid is really braindead, when a device is stopped# it is no longer usefull in anyway (and we should not# probe it) yet it still sticks around, see bug rh523387state = Nonestate_file = "/sys/%s/md/array_state" % entry["sysfs_path"]if os.access(state_file, os.R_OK):state = open(state_file).read().strip()if state == "clear":continueentries.append(entry)- return entries
- def __is_blacklisted_blockdev(dev_name): """Is this a blockdev we never want for an install?""" if dev_name.startswith("ram") or dev_name.startswith("fd"):
@@ -180,17 +144,6 @@ def __is_blacklisted_blockdev(dev_name):
return False-def enumerate_block_devices():
- return [d for d in enumerate_devices(deviceClass="block") if not
__is_blacklisted_blockdev(os.path.basename(d))]
-def get_block_device(sysfs_path):
- dev = get_device(sysfs_path)
- if not dev or 'name' not in dev:
return None- else:
return dev- # These are functions for retrieving specific pieces of information from # udev database entries. def device_get_name(udev_info):
@@ -198,7 +151,7 @@ def device_get_name(udev_info): if "DM_NAME" in udev_info: name = udev_info["DM_NAME"] else:
name = udev_info["name"]
name = udev_info.sys_name return name@@ -236,7 +189,7 @@ def device_is_md(info):
# The udev information keeps shifting around. Only md arrays have a # /sys/class/block/<name>/md/ subdirectory.
- md_dir = "/sys" + device_get_sysfs_path(info) + "/md"
md_dir = device_get_sysfs_path(info) + "/md" return os.path.exists(md_dir)
def device_is_cciss(info):
@@ -256,7 +209,7 @@ def device_is_zfcp(info): if info.get("DEVTYPE") != "disk": return False
- subsystem = "/sys" + info.get("sysfs_path")
subsystem = device_get_sysfs_path(info)
while True: topdir = os.path.realpath(os.path.dirname(subsystem))
@@ -284,7 +237,7 @@ def device_get_zfcp_attribute(info, attr=None): log.debug("device_get_zfcp_attribute() called with attr=None") return None
- attribute = "/sys%s/device/%s" % (info.get("sysfs_path"), attr,)
attribute = "%s/device/%s" % (device_get_sysfs_path(info), attr) attribute = os.path.realpath(attribute)
if not os.path.isfile(attribute):
@@ -295,14 +248,14 @@ def device_get_zfcp_attribute(info, attr=None):
def device_get_dasd_bus_id(info): """ Return the CCW bus ID of the dasd device. """
- return info.get("sysfs_path").split("/")[-3]
return device_get_sysfs_path(info).split("/")[-3]
def device_get_dasd_flag(info, flag=None): """ Return the specified flag for the dasd device. """ if flag is None: return None
- path = "/sys" + info.get("sysfs_path") + "/device/" + flag
- path = device_get_sysfs_path(info) + "/device/" + flag if not os.path.isfile(path): return None
@@ -318,17 +271,17 @@ def device_is_disk(info): """ Return True is the device is a disk. """ if device_is_cdrom(info): return False
- has_range = os.path.exists("/sys/%s/range" % info['sysfs_path'])
has_range = os.path.exists("%s/range" % device_get_sysfs_path(info)) return info.get("DEVTYPE") == "disk" or has_range
def device_is_partition(info):
- has_start = os.path.exists("/sys/%s/start" % info['sysfs_path'])
has_start = os.path.exists("%s/start" % device_get_sysfs_path(info)) return info.get("DEVTYPE") == "partition" or has_start
def device_is_loop(info): """ Return True if the device is a configured loop device. """ return (device_get_name(info).startswith("loop") and
os.path.isdir("/sys/%s/loop" % info['sysfs_path']))
os.path.isdir("%s/loop" % device_get_sysfs_path(info)))def device_get_serial(udev_info): """ Get the serial number/UUID from the device as reported by udev. """
@@ -356,7 +309,7 @@ def device_get_path(info): return info["ID_PATH"]
def device_get_symlinks(info):
- return info.get("symlinks", [])
return info.get("DEVLINKS", [])
def device_get_by_path(info): for link in device_get_symlinks(info):
@@ -366,7 +319,7 @@ def device_get_by_path(info): return device_get_name(info)
def device_get_sysfs_path(info):
- return info['sysfs_path']
return info.sys_path
def device_get_major(info): return int(info["MAJOR"])
@@ -675,7 +628,7 @@ def device_get_iscsi_session(info): # The position of sessionX part depends on device # (e.g. offload vs. sw; also varies for different offload devs) session = None
- match = re.match(r'/.*/(session\d+)', info["sysfs_path"])
- match = re.match(r'/.*/(session\d+)', device_get_sysfs_path(info)) if match: session = match.groups()[0] else:
@@ -694,7 +647,7 @@ def device_get_iscsi_nic(info): def device_get_iscsi_initiator(info): initiator = None if device_is_partoff_iscsi(info):
host = re.match(r'.*/(host\d+)', info["sysfs_path"]).groups()[0]
host = re.match(r'.*/(host\d+)',device_get_sysfs_path(info)).groups()[0] if host: initiator_file = "/sys/class/iscsi_host/%s/initiatorname" % host if os.access(initiator_file, os.R_OK): @@ -738,10 +691,10 @@ def device_get_iscsi_initiator(info):
def _detect_broadcom_fcoe(info): re_pci_host=re.compile(r'/(.*)/(host\d+)')
- match = re_pci_host.match(info["sysfs_path"])
- match = re_pci_host.match(device_get_sysfs_path(info)) if match: sysfs_pci, host = match.groups()
if os.access('/sys/%s/%s/fc_host' %(sysfs_pci, host), os.X_OK) and \
if os.access('%s/%s/fc_host' %(sysfs_pci, host), os.X_OK) and \ 'net' in sysfs_pci: return (sysfs_pci, host) return (None, None)@@ -757,7 +710,7 @@ def device_is_fcoe(info): path_components[2] == "fc": return True
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]:
if path.startswith("fc-") and "fcoe" in device_get_sysfs_path(info): return True
if _detect_broadcom_fcoe(info) != (None, None):
@@ -768,20 +721,21 @@ def device_is_fcoe(info): def device_get_fcoe_nic(info): path = info.get("ID_PATH", "") path_components = path.split("-")
sysfs_path = device_get_sysfs_path(info)
if path.startswith("pci-eth") and len(path_components) >= 4 and \ path_components[2] == "fc": return path_components[1]
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]:
return info["sysfs_path"].split("/")[4].split(".")[0]
if path.startswith("fc-") and "fcoe" in sysfs_path:
return sysfs_path.split("/")[4].split(".")[0] (sysfs_pci, host) = _detect_broadcom_fcoe(info) if (sysfs_pci, host) != (None, None):
net, iface = info['sysfs_path'].split("/")[5:7]
net, iface = sysfs_path.split("/")[5:7] if net != "net":
log.warning("unexpected sysfs_path of bnx2fc device: %s",info['sysfs_path'])
match = re.compile(r'.*/net/([^/]*)').match(info['sysfs_path'])
log.warning("unexpected sysfs_path of bnx2fc device: %s",sysfs_path)
match = re.compile(r'.*/net/([^/]*)').match(sysfs_path) if match: return match.groups()[0].split(".")[0] else:@@ -795,7 +749,7 @@ def device_get_fcoe_identifier(info): path_components[2] == "fc": return path_components[3]
- if path.startswith("fc-") and "fcoe" in info["sysfs_path"]:
if path.startswith("fc-") and "fcoe" in device_get_sysfs_path(info): return path_components[1]
if device_is_fcoe(info) and len(path_components) >= 4 and \
diff --git a/blivet/util.py b/blivet/util.py index a15bb4a..28dc125 100644 --- a/blivet/util.py +++ b/blivet/util.py @@ -178,7 +178,7 @@ def get_sysfs_attr(path, attr): log.debug("get_sysfs_attr() called with attr=None") return None
- attribute = "/sys%s/%s" % (path, attr)
attribute = "%s/%s" % (path, attr) attribute = os.path.realpath(attribute)
if not os.path.isfile(attribute) and not os.path.islink(attribute):
diff --git a/python-blivet.spec b/python-blivet.spec index abbbb0f..b668d94 100644 --- a/python-blivet.spec +++ b/python-blivet.spec @@ -28,6 +28,7 @@ Requires: python Requires: python-six Requires: pykickstart >= %{pykickstartver} Requires: util-linux >= %{utillinuxver} +Requires: python-pyudev Requires: parted >= %{partedver} Requires: pyparted >= %{pypartedver} Requires: device-mapper >= %{dmver} diff --git a/tests/udev_test.py b/tests/udev_test.py index a7b09ab..86cc434 100644 --- a/tests/udev_test.py +++ b/tests/udev_test.py @@ -11,94 +11,11 @@ class UdevTest(unittest.TestCase): blivet.udev.os = mock.Mock() blivet.udev.log = mock.Mock()
- def test_udev_enumerate_devices(self):
- def test_udev_get_device(self): import blivet.udev
ENUMERATE_LIST = ['/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
'/sys/devices/virtual/block/loop0','/sys/devices/virtual/block/loop1','/sys/devices/virtual/block/ram0','/sys/devices/virtual/block/ram1','/sys/devices/virtual/block/dm-0',]blivet.udev.global_udev.enumerate_devices =mock.Mock(return_value=ENUMERATE_LIST)
ret = blivet.udev.enumerate_devices()self.assertEqual(set(ret),set(['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
'/devices/virtual/block/loop0', '/devices/virtual/block/loop1','/devices/virtual/block/ram0', '/devices/virtual/block/ram1','/devices/virtual/block/dm-0']))- def test_udev_get_device_1(self):
import blivet.udevclass Device(object):def __init__(self):self.sysname = 'loop1'self.dict = {'symlinks': ['/dev/block/7:1'],'SUBSYSTEM': 'block','MAJOR': '7','DEVPATH': '/devices/virtual/block/loop1','UDISKS_PRESENTATION_NOPOLICY': '1','UDEV_LOG': '3','DEVNAME': '/dev/loop1','DEVTYPE': 'disk','DEVLINKS': '/dev/block/7:1','MINOR': '1'}def __getitem__(self, key):return self.dict[key]def __setitem__(self, key, value):self.dict[key] = valueblivet.udev.os.path.exists.return_value = TrueDEV_PATH = '/devices/virtual/block/loop1'dev = Device()blivet.udev.global_udev = mock.Mock()blivet.udev.global_udev.create_device.return_value = devsaved = blivet.udev.parse_uevent_fileblivet.udev.parse_uevent_file = mock.Mock(return_value=dev)ret = blivet.udev.get_device(DEV_PATH)self.assertTrue(isinstance(ret, Device))self.assertEqual(ret['name'], ret.sysname)self.assertEqual(ret['sysfs_path'], DEV_PATH)self.assertTrue(blivet.udev.parse_uevent_file.called)blivet.udev.parse_uevent_file = saved- def test_udev_get_device_2(self):
import blivet.udevblivet.udev.os.path.exists.return_value = Falseret = blivet.udev.get_device('')self.assertEqual(ret, None)- def test_udev_get_device_3(self):
import blivet.udevblivet.udev.os.path.exists.return_value = Trueblivet.udev.global_udev = mock.Mock()blivet.udev.global_udev.create_device.return_value = Noneret = blivet.udev.get_device('')self.assertEqual(ret, None)- def test_udev_get_devices(self):
import blivet.udevsaved = blivet.udev.settleblivet.udev.settle = mock.Mock()DEVS = \['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
'/devices/virtual/block/loop0', '/devices/virtual/block/loop1','/devices/virtual/block/ram0', '/devices/virtual/block/ram1','/devices/virtual/block/dm-0']blivet.udev.enumerate_devices = mock.Mock(return_value=DEVS)blivet.udev.get_device = lambda x: xret = blivet.udev.get_devices()self.assertEqual(ret, DEVS)blivet.udev.settle = saved
devices = blivet.udev.global_udev.list_devices(subsystem="block")for device in devices:self.assertNotEqual(blivet.udev.get_device(device.sys_path),None)
def test_udev_parse_uevent_file_1(self): import blivet.udev-- 1.9.3
anaconda-patches mailing list anaconda-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
A couple of comments:
- mddetail will not have UUID if the level is Container.
That doesn't matter since we don't create md containers, but I can note that in MDRaidArrayDevice._postCreate for future reference.
- It might be a good idea to attach docstrings to the udev.py
methods, since they've been worked over so much otherwise.
Maybe so, but that's outside the scope of this patch set.
- You get rid of the use of parse_uevent_file. Apparently,
parsing the uevent file was a way of obtaining additional information not obtained from pyudev/libudev. Can we guarantee that the pyudev library obtains all the data previously obtained by our pyudev library + parse_uevent_file() method.
It's all in there. The only difference, which I've accounted for in one place (udev.device_is_dasd) locally, is that DEVNAME is a full path in pyudev, whereas it was a basename in the uevent file.
- mulhern
anaconda-patches mailing list anaconda-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
Since we cannot inject data into pyudev's Device entries we have to store the metadata for use from various places unless we want to call mdexamine multiple times per device. --- blivet/devicetree.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/blivet/devicetree.py b/blivet/devicetree.py index 755f782..d6f0e25 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -134,7 +134,7 @@ class DeviceTree(object): self.unusedRaidMembers = []
# initialize attributes that may later hold cached lvm info - self.dropLVMCache() + self.dropCache()
self.__passphrases = [] if passphrase: @@ -188,6 +188,20 @@ class DeviceTree(object): self._pvInfo = None # pylint: disable=attribute-defined-outside-init self._lvInfo = None # pylint: disable=attribute-defined-outside-init
+ @property + def mdInfo(self): + if self._mdInfo is None: + self._mdInfo = {} + + return self._mdInfo + + def dropMDCache(self): + self._mdInfo = None # pylint: disable=attribute-defined-outside-init + + def dropCache(self): + self.dropLVMCache() + self.dropMDCache() + def pruneActions(self): """ Remove redundant/obsolete actions from the action list. """ for action in reversed(self._actions[:]): @@ -1808,11 +1822,12 @@ class DeviceTree(object): # luks/dmcrypt kwargs["name"] = "luks-%s" % uuid elif format_type in formats.mdraid.MDRaidMember._udevTypes: - info.update(mdraid.mdexamine(device.path)) + md_info = mdraid.mdexamine(device.path) + self.mdInfo[device.path] = md_info
# mdraid try: - kwargs["mdUuid"] = udev.device_get_md_uuid(info) + kwargs["mdUuid"] = udev.device_get_md_uuid(md_info) except KeyError: log.warning("mdraid member %s has no md uuid", name)
@@ -2108,7 +2123,7 @@ class DeviceTree(object): # this has proven useful when populating after opening a LUKS device udev.settle()
- self.dropLVMCache() + self.dropCache()
if flags.installer_mode and not flags.image_install: mpath.set_friendly_names(enabled=flags.multipath_friendly_names)
We can't inject data into pyudev.Device instances like we could when the udev db entries were plain dicts. --- blivet/devicetree.py | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-)
diff --git a/blivet/devicetree.py b/blivet/devicetree.py index d6f0e25..2c52a40 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -1533,11 +1533,13 @@ class DeviceTree(object): lv_dev.logSize, lv_dev.vgSpaceUsed)
def handleUdevLVMPVFormat(self, info, device): + # pylint: disable=unused-argument log_method_call(self, name=device.name, type=device.format.type) + pv_info = self.pvInfo.get(device.path, {}) # lookup/create the VG and LVs try: - vg_name = udev.device_get_vg_name(info) - vg_uuid = udev.device_get_vg_uuid(info) + vg_name = udev.device_get_vg_name(pv_info) + vg_uuid = udev.device_get_vg_uuid(pv_info) except KeyError: # no vg name means no vg -- we're done with this pv return @@ -1551,12 +1553,12 @@ class DeviceTree(object): vg_device.parents.append(device) else: try: - vg_size = udev.device_get_vg_size(info) - vg_free = udev.device_get_vg_free(info) - pe_size = udev.device_get_vg_extent_size(info) - pe_count = udev.device_get_vg_extent_count(info) - pe_free = udev.device_get_vg_free_extents(info) - pv_count = udev.device_get_vg_pv_count(info) + vg_size = udev.device_get_vg_size(pv_info) + vg_free = udev.device_get_vg_free(pv_info) + pe_size = udev.device_get_vg_extent_size(pv_info) + pe_count = udev.device_get_vg_extent_count(pv_info) + pe_free = udev.device_get_vg_free_extents(pv_info) + pv_count = udev.device_get_vg_pv_count(pv_info) except (KeyError, ValueError) as e: log.warning("invalid data for %s: %s", device.name, e) return @@ -1576,8 +1578,9 @@ class DeviceTree(object): self.handleVgLvs(vg_device)
def handleUdevMDMemberFormat(self, info, device): + # pylint: disable=unused-argument log_method_call(self, name=device.name, type=device.format.type) - + md_info = self.mdInfo.get(device.path, {}) md_array = self.getDeviceByUuid(device.format.mdUuid, incomplete=True) if device.format.mdUuid and md_array: md_array.parents.append(device) @@ -1585,9 +1588,9 @@ class DeviceTree(object): # create the array with just this one member try: # level is reported as, eg: "raid1" - md_level = udev.device_get_md_level(info) - md_devices = udev.device_get_md_devices(info) - md_uuid = udev.device_get_md_uuid(info) + md_level = udev.device_get_md_level(md_info) + md_devices = udev.device_get_md_devices(md_info) + md_uuid = udev.device_get_md_uuid(md_info) except (KeyError, ValueError) as e: log.warning("invalid data for %s: %s", device.name, e) return @@ -1630,10 +1633,10 @@ class DeviceTree(object):
# mdexamine yields MD_METADATA only for metadata version > 0.90 # if MD_METADATA is missing, assume metadata version is 0.90 - md_metadata = md_metadata or udev.device_get_md_metadata(info) or "0.90" + md_metadata = md_metadata or udev.device_get_md_metadata(md_info) or "0.90"
if not md_name: - md_path = info.get("DEVICE", "") + md_path = md_info.get("DEVICE", "") if md_path: md_name = devicePathToName(md_path) if re.match(r'md\d+$', md_name): @@ -1838,18 +1841,18 @@ class DeviceTree(object): kwargs["biosraid"] = udev.device_is_biosraid_member(info) elif format_type == "LVM2_member": # lvm - info.update(self.pvInfo.get(device.path, {})) + pv_info = self.pvInfo.get(device.path, {})
try: - kwargs["vgName"] = udev.device_get_vg_name(info) + kwargs["vgName"] = udev.device_get_vg_name(pv_info) except KeyError: log.warning("PV %s has no vg_name", name) try: - kwargs["vgUuid"] = udev.device_get_vg_uuid(info) + kwargs["vgUuid"] = udev.device_get_vg_uuid(pv_info) except KeyError: log.warning("PV %s has no vg_uuid", name) try: - kwargs["peStart"] = udev.device_get_pv_pe_start(info) + kwargs["peStart"] = udev.device_get_pv_pe_start(pv_info) except KeyError: log.warning("PV %s has no pe_start", name) elif format_type == "vfat":
----- Original Message -----
From: "David Lehman" dlehman@redhat.com To: anaconda-patches@lists.fedorahosted.org Sent: Friday, August 1, 2014 1:22:31 AM Subject: [PATCH 3/6] Keep lvm and md metadata separate from udev info.
We can't inject data into pyudev.Device instances like we could when the udev db entries were plain dicts.
blivet/devicetree.py | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-)
diff --git a/blivet/devicetree.py b/blivet/devicetree.py index d6f0e25..2c52a40 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -1533,11 +1533,13 @@ class DeviceTree(object): lv_dev.logSize, lv_dev.vgSpaceUsed)
def handleUdevLVMPVFormat(self, info, device):
# pylint: disable=unused-argument log_method_call(self, name=device.name, type=device.format.type)pv_info = self.pvInfo.get(device.path, {}) # lookup/create the VG and LVs try:
vg_name = udev.device_get_vg_name(info)vg_uuid = udev.device_get_vg_uuid(info)
vg_name = udev.device_get_vg_name(pv_info)vg_uuid = udev.device_get_vg_uuid(pv_info) except KeyError: # no vg name means no vg -- we're done with this pv return@@ -1551,12 +1553,12 @@ class DeviceTree(object): vg_device.parents.append(device) else: try:
vg_size = udev.device_get_vg_size(info)vg_free = udev.device_get_vg_free(info)pe_size = udev.device_get_vg_extent_size(info)pe_count = udev.device_get_vg_extent_count(info)pe_free = udev.device_get_vg_free_extents(info)pv_count = udev.device_get_vg_pv_count(info)
vg_size = udev.device_get_vg_size(pv_info)vg_free = udev.device_get_vg_free(pv_info)pe_size = udev.device_get_vg_extent_size(pv_info)pe_count = udev.device_get_vg_extent_count(pv_info)pe_free = udev.device_get_vg_free_extents(pv_info)pv_count = udev.device_get_vg_pv_count(pv_info) except (KeyError, ValueError) as e: log.warning("invalid data for %s: %s", device.name, e) return@@ -1576,8 +1578,9 @@ class DeviceTree(object): self.handleVgLvs(vg_device)
def handleUdevMDMemberFormat(self, info, device):
# pylint: disable=unused-argument log_method_call(self, name=device.name, type=device.format.type)
md_info = self.mdInfo.get(device.path, {}) md_array = self.getDeviceByUuid(device.format.mdUuid, incomplete=True) if device.format.mdUuid and md_array: md_array.parents.append(device)@@ -1585,9 +1588,9 @@ class DeviceTree(object): # create the array with just this one member try: # level is reported as, eg: "raid1"
md_level = udev.device_get_md_level(info)md_devices = udev.device_get_md_devices(info)md_uuid = udev.device_get_md_uuid(info)
md_level = udev.device_get_md_level(md_info)md_devices = udev.device_get_md_devices(md_info)md_uuid = udev.device_get_md_uuid(md_info) except (KeyError, ValueError) as e: log.warning("invalid data for %s: %s", device.name, e) return@@ -1630,10 +1633,10 @@ class DeviceTree(object):
# mdexamine yields MD_METADATA only for metadata version > 0.90 # if MD_METADATA is missing, assume metadata version is 0.90
md_metadata = md_metadata or udev.device_get_md_metadata(info)or "0.90"
md_metadata = md_metadata orudev.device_get_md_metadata(md_info) or "0.90"
if not md_name:
md_path = info.get("DEVICE", "")
md_path = md_info.get("DEVICE", "") if md_path: md_name = devicePathToName(md_path) if re.match(r'md\d+$', md_name):@@ -1838,18 +1841,18 @@ class DeviceTree(object): kwargs["biosraid"] = udev.device_is_biosraid_member(info) elif format_type == "LVM2_member": # lvm
info.update(self.pvInfo.get(device.path, {}))
pv_info = self.pvInfo.get(device.path, {}) try:
kwargs["vgName"] = udev.device_get_vg_name(info)
kwargs["vgName"] = udev.device_get_vg_name(pv_info) except KeyError: log.warning("PV %s has no vg_name", name) try:
kwargs["vgUuid"] = udev.device_get_vg_uuid(info)
kwargs["vgUuid"] = udev.device_get_vg_uuid(pv_info) except KeyError: log.warning("PV %s has no vg_uuid", name) try:
kwargs["peStart"] = udev.device_get_pv_pe_start(info)
kwargs["peStart"] = udev.device_get_pv_pe_start(pv_info) except KeyError: log.warning("PV %s has no pe_start", name) elif format_type == "vfat":-- 1.9.3
anaconda-patches mailing list anaconda-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
I have a couple of comments:
*) I'm not sure why it is that it makes sense just to proceed if no information at all is obtained about the device. It feels like that ought to be distinguished somehow from just a value or two missing.
*) I think we're at the place where abstracting cacheing of metadata would be a good step.
Here's a _rough_ outline of the classes I'm thinking of.
@abc.metaclass class DeviceInfoCache(object):
""" An abstract class for device information. """
@abc.abstractmethod def __getitem__(self, devname): # overridden as appropriate by subclasses raise NotImplementedException()
@abc.abstractmethod def clear(self): # overridden by subclasses in the appropriate way, not shown raise NotImplementedException()
class LVInfoCache(DeviceInfoCache): """ Cache for logical volume information obtained from lv. """
def __init__(self): """ Until lvs is called, the cache does not exist. """ self._cache = None
def __getitem__(self, devname): """ Initialize the cache if it does not exist, then obtain the info from the cache if available. """ if self._cache is None: for k, v in lvm.lvs(): self._cache[k] = DeviceInfo(v)
try: return self._cache[devname] except KeyError: return None
class MDInfoCache(DeviceInfoCache):
def __init__(self): """ Initialize an empty cache. """ self._cache = {}
def __getitem__(self, devname): if devname not in self._cache: try: self._cache[devname] = DeviceInfo(mdexamine(devname)) except: return None return self._cache[devname]
etc. The most important gain here is that the cache's underlying utilities can behave differently, since lvs gets info for all devices but mdexamine only for one device, but the classes can abstract the details of that behavior. Currently, the situation for mdexamine is particularly brittle; it is guaranteed that the mdexamine call will occur for that device before the lookup occurs, but that guarantee is not documented or enforced. It would be more robust to rely on an automatic cacheing mechanism.
I'm not certain that there won't come a time when replacing items instead of clearing all items might not arrive someday, and the abstraction will allow this to be handled better.
*) It might be a good idea to abstract the info for each device as well. I've used DeviceInfo class to represent that idea in the example above, allthough the issue is orthogonal.
Here's another rough outline.
@abc.metaclass class DeviceInfo(object):
@abc.abstractmethod def validKey(self, key): """ Returns True if this is a key that ought to be in the database. """ raise NotImplementedError()
def __init__(self, info): self._info = info
def __getitem__(self, key): """ Raises AppropriateError if the key value is bad. Raises KeyError if the key value is missing, but good. """ if not self.validKey(key): raise AppropriateError() return self._info[key]
class MDDeviceInfo(DeviceInfo):
def validKey(self, key): ...
class LVDeviceInfo(DeviceInfo):
def validKey(self, key): ...
class UdevInfo(DeviceInfo):
def validKey(self, key): ...
Even though we can't statically check that the keys are expected, we can dynamically check them this way. This would catch some of the kinds of errors that I've actually been seeing and would give a reasonable place for documenting these keys. Also, we could do this gradually, since validKey() can just return True when there is doubt.
*) We may someday just want to ask for a key, instead of specifying the particular database, udev, mdexamine result, etc. to obtain it from. In that case, there might be a reason to put all the databases into a bag and have some kind of rule for looking up the interesting value. I think that the suggested abstractions would help out for that as well.
I imagine something like
class SuperCache(object):
_caches = {'mdexamine' : MDInfoCache(), 'udev' : UdevInfoCache(), ...}
def lookup(self, devname, key, mode): """ :param str devname: the device for which this info should be obtained :param str key: the key for that info :param int mode: something indicating lvm, md, or basic udev
The algorithm would use the mode to determine which databases to search and in what order. It could make decisions based on whether such data was expected to be present or not. """ ...
This last is more near future than now, though.
- mulhern
The main difference is that we can't write to pyudev.Device instances. --- blivet/devicetree.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/blivet/devicetree.py b/blivet/devicetree.py index 2c52a40..a6b14d8 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -1089,9 +1089,6 @@ class DeviceTree(object): minor=udev.device_get_minor(info), sysfsPath=sysfs_path, **kwargs)
- if mpath.is_multipath_member(device.path): - info["ID_FS_TYPE"] = "multipath_member" - if diskType == DASDDevice: self.dasd.append(device)
@@ -1177,8 +1174,6 @@ class DeviceTree(object):
if device and device.isDisk and \ mpath.is_multipath_member(device.path): - # mark as multipath_member also when repopulating devicetree - info["ID_FS_TYPE"] = "multipath_member" # newly added device (eg iSCSI) could make this one a multipath member if device.format and device.format.type != "multipath_member": log.debug("%s newly detected as multipath member, dropping old format and removing kids", device.name) @@ -1790,11 +1785,15 @@ class DeviceTree(object): format_type = udev.device_get_format(info) serial = udev.device_get_serial(info)
+ is_multipath_member = mpath.is_multipath_member(device.path) + if is_multipath_member: + format_type = "multipath_member" + # Now, if the device is a disk, see if there is a usable disklabel. # If not, see if the user would like to create one. # XXX ignore disklabels on multipath or biosraid member disks if not udev.device_is_biosraid_member(info) and \ - not udev.device_is_multipath_member(info) and \ + not is_multipath_member and \ format_type != "iso9660": self.handleUdevDiskLabelFormat(info, device) if device.partitioned or self.isIgnored(info) or \
--- blivet/udev.py | 10 ---------- 1 file changed, 10 deletions(-)
diff --git a/blivet/udev.py b/blivet/udev.py index d0eb543..7517ffe 100644 --- a/blivet/udev.py +++ b/blivet/udev.py @@ -536,16 +536,6 @@ def device_is_dm_partition(info): return (device_is_dm(info) and info.get("DM_UUID", "").split("-")[0].startswith("part"))
-def device_is_multipath_member(info): - """ Return True if the device is part of a multipath. """ - return info.get("ID_FS_TYPE") == "multipath_member" - -def device_get_multipath_name(info): - """ Return the name of the multipath that the device is a member of. """ - if device_is_multipath_member(info): - return info['ID_MPATH_NAME'] - return None - def device_get_disklabel_type(info): """ Return the type of disklabel on the device or None. """ if device_is_partition(info) or device_is_dm_partition(info):
We can't add data to pyudev.Device instances so this function has no use. --- blivet/udev.py | 15 --------------- tests/udev_test.py | 39 --------------------------------------- 2 files changed, 54 deletions(-)
diff --git a/blivet/udev.py b/blivet/udev.py index 7517ffe..6c3fd17 100644 --- a/blivet/udev.py +++ b/blivet/udev.py @@ -47,21 +47,6 @@ def get_devices(subsystem="block"): return [d for d in global_udev.list_devices(subsystem=subsystem) if not __is_blacklisted_blockdev(d.sys_name)]
-def parse_uevent_file(dev): - path = os.path.normpath("%s/uevent" % device_get_sysfs_path(dev)) - if not os.access(path, os.R_OK): - return dev - - with open(path) as f: - for line in f.readlines(): - (key, equals, value) = line.strip().partition("=") - if not equals: - continue - - dev[key] = value - - return dev - def settle(): # wait maximal 300 seconds for udev to be done running blkid, lvm, # mdadm etc. This large timeout is needed when running on machines with diff --git a/tests/udev_test.py b/tests/udev_test.py index 86cc434..a930031 100644 --- a/tests/udev_test.py +++ b/tests/udev_test.py @@ -2,7 +2,6 @@
import unittest import mock -import os
class UdevTest(unittest.TestCase):
@@ -17,44 +16,6 @@ class UdevTest(unittest.TestCase): for device in devices: self.assertNotEqual(blivet.udev.get_device(device.sys_path), None)
- def test_udev_parse_uevent_file_1(self): - import blivet.udev - # For this one we're accessing the real uevent file (twice). - path = '/devices/virtual/block/loop1' - if not os.path.exists("/sys" + path): - self.skipTest("this test requires the presence of /dev/loop1") - - info = {'sysfs_path': path} - for line in open('/sys' + path + '/uevent').readlines(): - (name, equals, value) = line.strip().partition("=") - if not equals: - continue - - info[name] = value - - dev = {'sysfs_path': path} - blivet.udev.os.path.normpath = os.path.normpath - blivet.udev.os.access = os.access - blivet.udev.os.R_OK = os.R_OK - ret = blivet.udev.parse_uevent_file(dev) - self.assertEqual(ret, info) - blivet.udev.os.path.normpath = mock.Mock() - blivet.udev.os.access = mock.Mock() - blivet.udev.os.R_OK = mock.Mock() - - def test_udev_parse_uevent_file_2(self): - import blivet.udev - blivet.udev.os.path.normpath = os.path.normpath - blivet.udev.os.access.return_value = False - path = '/devices/virtual/block/loop1' - if not os.path.exists("/sys" + path): - self.skipTest("this test requires the presence of /dev/loop1") - - dev = {'sysfs_path': path} - - ret = blivet.udev.parse_uevent_file(dev) - self.assertEqual(ret, {'sysfs_path': '/devices/virtual/block/loop1'}) - def udev_settle_test(self): import blivet.udev blivet.udev.util = mock.Mock()
----- Original Message -----
From: "David Lehman" dlehman@redhat.com To: anaconda-patches@lists.fedorahosted.org Sent: Friday, August 1, 2014 1:22:34 AM Subject: [PATCH 6/6] Remove parse_uevent_file since it won't work with pyudev.
We can't add data to pyudev.Device instances so this function has no use.
blivet/udev.py | 15 --------------- tests/udev_test.py | 39 --------------------------------------- 2 files changed, 54 deletions(-)
diff --git a/blivet/udev.py b/blivet/udev.py index 7517ffe..6c3fd17 100644 --- a/blivet/udev.py +++ b/blivet/udev.py @@ -47,21 +47,6 @@ def get_devices(subsystem="block"): return [d for d in global_udev.list_devices(subsystem=subsystem) if not __is_blacklisted_blockdev(d.sys_name)]
-def parse_uevent_file(dev):
- path = os.path.normpath("%s/uevent" % device_get_sysfs_path(dev))
- if not os.access(path, os.R_OK):
return dev- with open(path) as f:
for line in f.readlines():(key, equals, value) = line.strip().partition("=")if not equals:continuedev[key] = value- return dev
def settle(): # wait maximal 300 seconds for udev to be done running blkid, lvm, # mdadm etc. This large timeout is needed when running on machines with diff --git a/tests/udev_test.py b/tests/udev_test.py index 86cc434..a930031 100644 --- a/tests/udev_test.py +++ b/tests/udev_test.py @@ -2,7 +2,6 @@
import unittest import mock -import os
class UdevTest(unittest.TestCase):
@@ -17,44 +16,6 @@ class UdevTest(unittest.TestCase): for device in devices: self.assertNotEqual(blivet.udev.get_device(device.sys_path), None)
- def test_udev_parse_uevent_file_1(self):
import blivet.udev# For this one we're accessing the real uevent file (twice).path = '/devices/virtual/block/loop1'if not os.path.exists("/sys" + path):self.skipTest("this test requires the presence of /dev/loop1")info = {'sysfs_path': path}for line in open('/sys' + path + '/uevent').readlines():(name, equals, value) = line.strip().partition("=")if not equals:continueinfo[name] = valuedev = {'sysfs_path': path}blivet.udev.os.path.normpath = os.path.normpathblivet.udev.os.access = os.accessblivet.udev.os.R_OK = os.R_OKret = blivet.udev.parse_uevent_file(dev)self.assertEqual(ret, info)blivet.udev.os.path.normpath = mock.Mock()blivet.udev.os.access = mock.Mock()blivet.udev.os.R_OK = mock.Mock()- def test_udev_parse_uevent_file_2(self):
import blivet.udevblivet.udev.os.path.normpath = os.path.normpathblivet.udev.os.access.return_value = Falsepath = '/devices/virtual/block/loop1'if not os.path.exists("/sys" + path):self.skipTest("this test requires the presence of /dev/loop1")dev = {'sysfs_path': path}ret = blivet.udev.parse_uevent_file(dev)self.assertEqual(ret, {'sysfs_path':'/devices/virtual/block/loop1'})
- def udev_settle_test(self): import blivet.udev blivet.udev.util = mock.Mock()
-- 1.9.3
anaconda-patches mailing list anaconda-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
Assuming all else is good, it probably makes sense to squash this patch with patch (1) for push.
Otherwise, Ack.
- mulhern
On Thu, Jul 31, 2014 at 06:22:28PM -0500, David Lehman wrote:
Previous patch 3 is now part of a separate set.
Patch 1 has the suggested fixes from the list as well as conversion of new logging statements in StorageDevice.updateSysfsPath to pass arguments separately instead of formatting the string in advance.
Patch 2 has added comment disabling pylint warning about defining _mdInfo outside of __init__.
Patch 3 (separate lvm and md metadata...) has added disabling of pylint warnings for unused argument 'info'.
Patch 4 (adapt multipath...) is unchanged.
Patch 5 is new and just removes some things no longer used.
Patch 6 is also new and removes a function that is no longer useful.
David Lehman (6): Replace our pyudev with the package python-pyudev. Cache MD metadata while populating the devicetree. Keep lvm and md metadata separate from udev info. Adapt multipath detection code to external pyudev module. Remove some unused multipath-specific functions from blivet.udev. Remove parse_uevent_file since it won't work with pyudev.
blivet/deviceaction.py | 4 +- blivet/devices.py | 95 +++++++-------------- blivet/devicetree.py | 122 ++++++++++++++------------ blivet/pyudev.py | 226 ------------------------------------------------- blivet/udev.py | 145 ++++++++----------------------- blivet/util.py | 2 +- python-blivet.spec | 1 + tests/udev_test.py | 130 +--------------------------- 8 files changed, 143 insertions(+), 582 deletions(-) delete mode 100644 blivet/pyudev.py
-- 1.9.3
These look OK to me other than my 1 question.
anaconda-patches@lists.fedorahosted.org