[PATCH 1/6] Replace our pyudev with the package python-pyudev.
Anne Mulhern
amulhern at redhat.com
Fri Aug 1 15:34:07 UTC 2014
----- Original Message -----
> From: "David Lehman" <dlehman at redhat.com>
> To: anaconda-patches at 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.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
> --
> 1.9.3
>
> _______________________________________________
> anaconda-patches mailing list
> anaconda-patches at 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
More information about the anaconda-patches
mailing list