[PATCH 1/4] Replace our pyudev with the package python-pyudev.
David Lehman
dlehman at redhat.com
Mon Aug 4 15:15:21 UTC 2014
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 | 96 +++++++--------------
blivet/devicetree.py | 49 +++++------
blivet/pyudev.py | 226 -------------------------------------------------
blivet/udev.py | 142 +++++++++----------------------
blivet/util.py | 2 +-
python-blivet.spec | 1 +
tests/udev_test.py | 130 +---------------------------
8 files changed, 101 insertions(+), 549 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..d17942f 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,14 @@ 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)
+ # XXX this won't work for containers since no UUID is reported for them
+ info = mdraid.mddetail(self.path)
+ self.uuid = info.get("UUID")
for member in self.devices:
member.format.mdUuid = self.uuid
@@ -5229,7 +5193,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..453a561 100644
--- a/blivet/udev.py
+++ b/blivet/udev.py
@@ -27,57 +27,25 @@ 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
-
-def parse_uevent_file(dev):
- path = os.path.normpath("/sys/%s/uevent" % dev['sysfs_path'])
- 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
+ return [d for d in global_udev.list_devices(subsystem=subsystem)
+ if not __is_blacklisted_blockdev(d.sys_name)]
def settle():
# wait maximal 300 seconds for udev to be done running blkid, lvm,
@@ -103,7 +71,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 +88,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 +103,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 +129,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 +136,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 +174,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):
@@ -245,18 +183,15 @@ def device_is_cciss(info):
def device_is_dasd(info):
""" Return True if the device is a dasd device. """
- devname = info.get("DEVNAME")
- if devname:
- return devname.startswith("dasd")
- else:
- return False
+ devname = info.get("DEVNAME", '').split("/")[-1]
+ return devname.startswith("dasd")
def device_is_zfcp(info):
""" Return True if the device is a zfcp device. """
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 +219,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 +230,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 +253,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 +291,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 +301,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 +610,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 +629,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 +673,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 +692,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 +703,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("/")[5].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("/")[6:8]
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 +731,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..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):
@@ -11,132 +10,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
-
- 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'})
+ devices = blivet.udev.global_udev.list_devices(subsystem="block")
+ for device in devices:
+ self.assertNotEqual(blivet.udev.get_device(device.sys_path), None)
def udev_settle_test(self):
import blivet.udev
--
1.9.3
More information about the anaconda-patches
mailing list