summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--iw/autopart_type.py9
-rw-r--r--iw/partition_gui.py8
-rw-r--r--storage/__init__.py22
-rw-r--r--storage/devices.py202
-rw-r--r--storage/devicetree.py92
-rw-r--r--storage/formats/dmraid.py23
-rw-r--r--storage/partitioning.py4
-rw-r--r--storage/udev.py33
8 files changed, 341 insertions, 52 deletions
diff --git a/iw/autopart_type.py b/iw/autopart_type.py
index ba8c0dc82..700d7da0e 100644
--- a/iw/autopart_type.py
+++ b/iw/autopart_type.py
@@ -381,14 +381,11 @@ class PartitionTypeWindow(InstallWindow):
else:
defaultBoot = None
for disk in self.storage.disks:
- partedDisk = disk.partedDisk
- if partedDisk.device.path[5:] not in self.anaconda.id.bootloader.drivelist:
+ if disk.name not in self.anaconda.id.bootloader.drivelist:
continue
- size = partedDisk.device.getSize(unit="MB")
- dispstr = "%s %8.0f MB %s" %(partedDisk.device.path[5:],
- size, partedDisk.device.model)
+ dispstr = "%s %8.0f MB %s" %(disk.name, disk.size, disk.partedDisk.device.model)
i = bootstore.append(None)
- bootstore[i] = (dispstr, partedDisk.device.path[5:])
+ bootstore[i] = (dispstr, disk.name)
if disk.name == defaultBoot:
self.bootcombo.set_active_iter(i)
diff --git a/iw/partition_gui.py b/iw/partition_gui.py
index c704b0893..9dae43657 100644
--- a/iw/partition_gui.py
+++ b/iw/partition_gui.py
@@ -142,12 +142,12 @@ class DiskStripeSlice:
if self.partition.type & parted.PARTITION_FREESPACE:
rc = "Free\n"
else:
- rc = "%s\n" % (self.partition.getDeviceNodeName(),)
+ rc = "%s\n" % (self.partition.getDeviceNodeName().split("/")[-1],)
rc = rc + "%Ld MB" % (self.partition.getSize(unit="MB"),)
return rc
def getDeviceName(self):
- return self.partition.getDeviceNodeName()
+ return self.partition.getDeviceNodeName().split("/")[-1]
def update(self):
disk = self.parent.getDisk()
@@ -808,7 +808,7 @@ class PartitionWindow(InstallWindow):
part = part.nextPartition()
continue
- partName = part.getDeviceNodeName()
+ partName = part.getDeviceNodeName().split("/")[-1]
device = self.storage.devicetree.getDeviceByName(partName)
if not device and not part.type & parted.PARTITION_FREESPACE:
raise RuntimeError("can't find partition %s in device"
@@ -1054,7 +1054,7 @@ class PartitionWindow(InstallWindow):
self.editLVMVolumeGroup(device)
elif device.type == "lvmlv":
self.editLVMVolumeGroup(device)
- elif device.type == "partition":
+ elif isinstance(device, storage.devices.PartitionDevice):
self.editPartition(device)
# isNew implies that this request has never been successfully used before
diff --git a/storage/__init__.py b/storage/__init__.py
index 7bac367dc..6c241c2c0 100644
--- a/storage/__init__.py
+++ b/storage/__init__.py
@@ -238,7 +238,11 @@ class Storage(object):
does not necessarily reflect the actual on-disk state of the
system's disks.
"""
- disks = self.devicetree.getDevicesByType("disk")
+ disks = []
+ devices = self.devicetree.devices
+ for d in devices:
+ if isinstance(devices[d], DiskDevice):
+ disks.append(devices[d])
disks.sort(key=lambda d: d.name)
return disks
@@ -250,7 +254,11 @@ class Storage(object):
does not necessarily reflect the actual on-disk state of the
system's disks.
"""
- partitions = self.devicetree.getDevicesByType("partition")
+ partitions = []
+ devices = self.devicetree.devices
+ for d in devices:
+ if isinstance(devices[d], PartitionDevice):
+ partitions.append(devices[d])
partitions.sort(key=lambda d: d.name)
return partitions
@@ -423,7 +431,7 @@ class Storage(object):
if device.name in self.protectedPartitions:
return _("This partition is holding the data for the hard "
"drive install.")
- elif device.type == "partition" and device.isProtected:
+ elif isinstance(device, PartitionDevice) and device.isProtected:
# LDL formatted DASDs always have one partition, you'd have to
# reformat the DASD in CDL mode to get rid of it
return _("You cannot delete a partition of a LDL formatted "
@@ -445,7 +453,7 @@ class Storage(object):
else:
return _("This device is part of a LVM volume "
"group.")
- elif device.type == "partition" and device.isExtended:
+ elif isinstance(device, PartitionDevice) and device.isExtended:
reasons = {}
for dep in self.deviceDeps(device):
reason = self.deviceImmutable(dep)
@@ -473,13 +481,17 @@ class Storage(object):
if kwargs.has_key("disks"):
parents = kwargs.pop("disks")
+ if isinstance(parents, Device):
+ kwargs["parents"] = [parents]
+ else:
+ kwargs["parents"] = parents
if kwargs.has_key("name"):
name = kwargs.pop("name")
else:
name = "req%d" % self.nextID
- return PartitionDevice(name, *args, **kwargs)
+ return PartitionDeviceFactory(name, *args, **kwargs)
def newMDArray(self, *args, **kwargs):
""" Return a new MDRaidArrayDevice instance for configuring. """
diff --git a/storage/devices.py b/storage/devices.py
index 84cfe1bb2..dd5a4f19d 100644
--- a/storage/devices.py
+++ b/storage/devices.py
@@ -127,6 +127,74 @@ def get_device_majors():
return majors
device_majors = get_device_majors()
+def PartitionDeviceFactory(*args, **kwargs):
+ """This will decide what PartitionDevice class will be used.
+
+ Arguments:
+
+ name -- the device name (generally a device node's basename)
+
+ Keyword Arguments:
+
+ exists -- indicates whether this is an existing device
+ format -- the device's format (DeviceFormat instance)
+
+ For existing partitions:
+
+ parents -- the disk that contains this partition
+ major -- the device major
+ minor -- the device minor
+ sysfsPath -- sysfs device path
+
+ For new partitions:
+
+ partType -- primary,extended,&c (as parted constant)
+ grow -- whether or not to grow the partition
+ maxsize -- max size for growable partitions (in MB)
+ size -- the device's size (in MB)
+ bootable -- whether the partition is bootable
+ parents -- a list of potential containing disks
+
+ The decision will be made base on finding the disk by name
+ """
+ # FIXME: PRePBootDevice should be here somehow.!!!
+ roots = ["/dev", "/dev/mapper"]
+ # firs lets normalize the name
+ norm_name = args[0].split("/")[-1]
+
+ # We look for the disk in /dev. From PartitionDevice its the [0] one.
+ if (not kwargs.has_key("parents")) or\
+ (kwargs.has_key("exists") and not kwargs["exists"]):
+ # Cant really choose a good type of class, default to PartitionDevice
+ # This will be considered as a request.
+ return PartitionDevice(*args, **kwargs)
+ else:
+ parents = kwargs["parents"]
+ if isinstance(parents, Device):
+ parents = [parents]
+ # we receive a list of parents. look for the disk that contains the name
+ # if we dont find the name we will return PartitionDevice and let it raise
+ # the exception.
+ for root in roots:
+ for parent in parents:
+ path = os.path.join(root,norm_name)
+ log.debug("looking up parted Partition: %s" % path)
+ part = parent.partedDisk.getPartitionByPath(path)
+ if not part:
+ continue
+ else:
+ # we have found a part. no make the decision based on path
+ if path.startswith(roots[1]):
+ #we create a DMPartition
+ return DMRaidPartitionDevice(*args, **kwargs)
+ elif path.startswith(roots[0]):
+ # make sure that the parent is consistent
+ kwargs["parents"] = [parent]
+ return PartitionDevice(*args, **kwargs)
+
+ # If we get here, we did not find anything.
+ return PartitionDevice(*args, **kwargs)
+
class Device(object):
""" A generic device.
@@ -861,14 +929,14 @@ class PartitionDevice(StorageDevice):
# no need to clobber our name
else:
self._partedPartition = partition
- self._name = partition.getDeviceNodeName()
+ self._name = partition.getDeviceNodeName().split("/")[-1]
partedPartition = property(lambda d: d._getPartedPartition(),
lambda d,p: d._setPartedPartition(p))
def dependsOn(self, dep):
""" Return True if this device depends on dep. """
- if dep.type == "partition" and dep.isExtended and self.isLogical:
+ if isinstance(dep, PartitionDevice) and dep.isExtended and self.isLogical:
return True
return Device.dependsOn(self, dep)
@@ -1051,7 +1119,7 @@ class PartitionDevice(StorageDevice):
geometry.length = new_length
def _getDisk(self):
- """ The disk that contains this partition. """
+ """ The disk that contains this partition."""
try:
disk = self.parents[0]
except IndexError:
@@ -1059,12 +1127,27 @@ class PartitionDevice(StorageDevice):
return disk
def _setDisk(self, disk):
+ """Change the parent.
+
+ Setting up a disk is not trivial. It has the potential to change
+ the underlying object. If necessary we must also change this object.
+ """
log_method_call(self, self.name, old=self.disk, new=disk)
if self.disk:
self.disk.removeChild()
self.parents = [disk]
disk.addChild()
+ if isinstance(disk, DMRaidArrayDevice):
+ # modify the partition so it can look like the DMRaidPartitionDevice.
+
+ self._type = "dmraid partition"
+ self._packages = ["dmraid"]
+ self.devDir = "/dev/mapper"
+ self.updateSysfsPath = DMDevice.updateSysfsPath
+ self.getDMNode = DMDevice.getDMNode
+
+
disk = property(lambda p: p._getDisk(), lambda p,d: p._setDisk(d))
@@ -2069,41 +2152,130 @@ class MDRaidArrayDevice(StorageDevice):
self.exists = False
-class DMRaidArrayDevice(DMDevice):
+class DMRaidArrayDevice(DiskDevice):
""" A dmraid (device-mapper RAID) device """
_type = "dm-raid array"
_packages = ["dmraid"]
+ devDir = "/dev/mapper"
- def __init__(self, name, format=None, size=None,
- exists=None, parents=None, sysfsPath=''):
+ def __init__(self, name, raidSet=None, level=None, format=None, size=None,
+ major=None, minor=None, parents=None, sysfsPath=''):
""" Create a DMRaidArrayDevice instance.
Arguments:
- name -- the device name (generally a device node's basename)
+ name -- the dmraid name also the device node's basename
Keyword Arguments:
+ raidSet -- the RaidSet object from block
+ level -- the type of dmraid
parents -- a list of the member devices
sysfsPath -- sysfs device path
size -- the device's size
format -- a DeviceFormat instance
- exists -- indicates whether this is an existing device
"""
if isinstance(parents, list):
for parent in parents:
if not parent.format or parent.format.type != "dmraidmember":
raise ValueError("parent devices must contain dmraidmember format")
- DMDevice.__init__(self, name, format=format, size=size,
- parents=parents, sysfsPath=sysfsPath,
- exists=exists)
+ DiskDevice.__init__(self, name, format=format, size=size,
+ major=major, minor=minor,
+ parents=parents, sysfsPath=sysfsPath)
- def probe(self):
- """ Probe for any missing information about this device.
+ self.formatClass = get_device_format_class("dmraidmember")
+ if not self.formatClass:
+ raise DeviceError("cannot find class for 'dmraidmember'")
- size
+
+ self._raidSet = raidSet
+ self._level = level
+
+ @property
+ def raidSet(self):
+ return self._raidSet
+
+ @raidSet.setter
+ def raidSet(self, val):
+ # If we change self._raidSet, parents list will be invalid.
+ # Don't allow the change.
+ pass
+
+ def _addDevice(self, device):
+ """ Add a new member device to the array.
+
+ XXX This is for use when probing devices, not for modification
+ of arrays.
"""
- raise NotImplementedError("probe method not defined for DMRaidArrayDevice")
+ log_method_call(self, self.name, device=device.name, status=self.status)
+
+ if not self.exists:
+ raise DeviceError("device has not been created")
+
+ if not isinstance(device.format, self.formatClass):
+ raise ValueError("invalid device format for dmraid member")
+
+ if device in self.members:
+ raise ValueError("device is already a member of this array")
+
+ # we added it, so now set up the relations
+ self.devices.append(device)
+ device.addChild()
+
+ @property
+ def members(self):
+ return self.parents
+
+ @property
+ def devices(self):
+ """ Return a list of this array's member device instances. """
+ return self.parents
+
+ def activate(self, mknod=True):
+ self._raidSet.activate(mknod=mknod)
+
+ def deactivate(self):
+ self._raidSet.deactivate()
+
+ # We are more like a disk then a dmdevice, but we are still a dmdevice,
+ # so we need to "inherit" some functions from dmdevice
+ def updateSysfsPath(self):
+ DMDevice.updateSysfsPath(self)
+
+ def getDMNode(self):
+ DMDevice.getDMNode(self)
+
+ def teardown(self, recursive=None):
+ # avoid DiskDevice's overriding of teardown()
+ StorageDevice.teardown(self, recursive)
+
+
+class DMRaidPartitionDevice(PartitionDevice):
+ """ A disk partition in a dmraid array, identical to a general
+ PartitionDevice, except for the device path and sysfs path
+ """
+ _type = "dmraid partition"
+ _packages = ["dmraid"]
+ devDir = "/dev/mapper"
+
+ def __init__(self, name, format=None,
+ size=None, grow=False, maxsize=None,
+ major=None, minor=None, bootable=None,
+ sysfsPath='', parents=None, exists=None,
+ partType=None, primary=False):
+ PartitionDevice.__init__(self, name, format=format, size=size,
+ major=major, minor=minor, bootable=bootable,
+ sysfsPath=sysfsPath, parents=parents,
+ exists=exists, partType=partType,
+ primary=primary)
+
+ # We are more like a partition then a dmdevice, but we are still a dmdevice
+ # so we need to "inherit" some functions from dmdevice
+ def updateSysfsPath(self):
+ DMDevice.updateSysfsPath(self)
+
+ def getDMNode(self):
+ DMDevice.getDMNode(self)
class MultipathDevice(DMDevice):
diff --git a/storage/devicetree.py b/storage/devicetree.py
index 3494d5a1d..a83279df5 100644
--- a/storage/devicetree.py
+++ b/storage/devicetree.py
@@ -21,6 +21,7 @@
#
import os
+import block
from errors import *
from devices import *
@@ -458,7 +459,7 @@ class DeviceTree(object):
raise ValueError("Cannot remove non-leaf device '%s'" % dev.name)
# if this is a partition we need to remove it from the parted.Disk
- if dev.type == "partition":
+ if isinstance(dev, PartitionDevice):
dev.disk.removePartition(dev)
self._devices.remove(dev)
@@ -558,9 +559,9 @@ class DeviceTree(object):
# special handling for extended partitions since the logical
# partitions and their deps effectively depend on the extended
logicals = []
- if dep.type == "partition" and dep.isExtended:
+ if isinstance(dep, PartitionDevice):
# collect all of the logicals on the same disk
- for part in self.getDevicesByType("partition"):
+ for part in self.getDevicesByInstance(PartitionDevice):
if part.isLogical and part.disk == dep.disk:
logicals.append(part)
@@ -601,6 +602,13 @@ class DeviceTree(object):
# this is a partition on a disk in the ignore list
return True
+ # Ignore partitions found on the raw disks which are part of a
+ # dmraidset
+ for set in self.getDevicesByType("dm-raid array"):
+ for disk in set.parents:
+ if disk.name == os.path.basename(os.path.dirname(sysfs_path)):
+ return True
+
# FIXME: check for virtual devices whose slaves are on the ignore list
def addUdevDevice(self, info):
@@ -667,6 +675,19 @@ class DeviceTree(object):
log.error("failure scanning device %s" % name)
return
+ if device is None and \
+ udev_device_is_dmraid_partition(info, self):
+ diskname = udev_device_get_dmraid_partition_disk(info)
+ disk = self.getDeviceByName(diskname)
+ device = PartitionDeviceFactory(name, \
+ sysfsPath=sysfs_path, \
+ major=udev_device_get_major(info), \
+ minor=udev_device_get_minor(info), \
+ exists=True, \
+ parents=[disk])
+ self._addDevice(device)
+ #self.ignoredDisks.append(name)
+
# if we get here, we found all of the slave devices and
# something must be wrong -- if all of the slaves are in
# the tree, this device should be as well
@@ -741,6 +762,17 @@ class DeviceTree(object):
minor=udev_device_get_minor(info),
sysfsPath=sysfs_path)
self._addDevice(device)
+ elif udev_device_is_dmraid(info):
+ # This is just temporary as I need to differentiate between the
+ # device that has partitions and device that dont.
+ log.debug("%s is part of a dmraid" % name)
+ device = self.getDeviceByName(name)
+ if device is None:
+ device = StorageDevice(name,
+ major=udev_device_get_major(info),
+ minor=udev_device_get_minor(info),
+ sysfsPath=sysfs_path, exists=True)
+ self._addDevice(device)
elif udev_device_is_disk(info):
log.debug("%s is a disk" % name)
device = self.getDeviceByName(name)
@@ -793,12 +825,12 @@ class DeviceTree(object):
log.error("failure scanning device %s" % disk_name)
return
- device = PartitionDevice(name,
- sysfsPath=sysfs_path,
- major=udev_device_get_major(info),
- minor=udev_device_get_minor(info),
- exists=True,
- parents=[disk])
+ device = PartitionDeviceFactory(name,
+ sysfsPath=sysfs_path,
+ major=udev_device_get_major(info),
+ minor=udev_device_get_minor(info),
+ exists=True,
+ parents=[disk])
self._addDevice(device)
#
@@ -824,9 +856,8 @@ class DeviceTree(object):
except KeyError:
log.debug("mdraid member %s has no md uuid" % name)
elif format_type == "isw_raid_member":
- # dmraid
- # TODO: collect name of containing raidset
- # TODO: implement dmraid member format class
+ # We dont add any new args because we intend to use the same
+ # block.RaidSet object for all the related devices.
pass
elif format_type == "LVM2_member":
# lvm
@@ -914,8 +945,38 @@ class DeviceTree(object):
parents=[device])
self._addDevice(md_array)
elif format.type == "dmraidmember":
- # look up or create the dmraid array
- pass
+ major = udev_device_get_major(info)
+ minor = udev_device_get_minor(info)
+ # Have we already created the DMRaidArrayDevice?
+ rs = block.getRaidSetFromRelatedMem(uuid=uuid, name=name,
+ major=major, minor=minor)
+ if rs is None:
+ # FIXME: Should handle not finding a dmriad dev better
+ pass
+
+ dm_array = self.getDeviceByName(rs.name)
+ if dm_array is not None:
+ # We add the new device.
+ dm_array._addDevice(device)
+ else:
+ # Activate the Raid set.
+ rs.activate(mknod=True)
+
+ # Create the DMRaidArray
+ dm_array = DMRaidArrayDevice(rs.name,
+ major=major, minor=minor,
+ raidSet=rs,
+ level=rs.level,
+ parents=[device])
+
+ self._addDevice(dm_array)
+
+ # Use the rs's object on the device.
+ # pyblock can return the memebers of a set and the device has
+ # the attribute to hold it. But ATM we are not really using it.
+ # Commenting this out until we really need it.
+ #device.format.raidmem = block.getMemFromRaidSet(dm_array,
+ # major=major, minor=minor, uuid=uuid, name=name)
elif format.type == "lvmpv":
# lookup/create the VG and LVs
try:
@@ -1077,6 +1138,9 @@ class DeviceTree(object):
# TODO: expand this to catch device format types
return [d for d in self._devices if d.type == device_type]
+ def getDevicesByInstance(self, device_class):
+ return [d for d in self._devices if isinstance(d, device_class)]
+
@property
def devices(self):
""" Dict with device path keys and Device values. """
diff --git a/storage/formats/dmraid.py b/storage/formats/dmraid.py
index d458b45c3..ef80902e2 100644
--- a/storage/formats/dmraid.py
+++ b/storage/formats/dmraid.py
@@ -20,6 +20,8 @@
# Red Hat Author(s): Dave Lehman <dlehman@redhat.com>
#
+import block
+
from iutil import log_method_call
#from dm import dm_node_from_name
from ..errors import *
@@ -65,25 +67,34 @@ class DMRaidMember(DeviceFormat):
device -- path to the underlying device
uuid -- this format's UUID
- raidSet -- the name of the raidset this member belongs to
exists -- indicates whether this is an existing format
+ On initialization this format is like DeviceFormat
+
"""
log_method_call(self, *args, **kwargs)
DeviceFormat.__init__(self, *args, **kwargs)
-
- self.raidSet = kwargs.get("raidSet")
+
+ # Initialize the attribute that will hold the block object.
+ self._raidmem = None
+
+ @property
+ def raidmem(self):
+ return self._raidmem
+
+ @raidmem.setter
+ def raidmem(self, raidmem):
+ self._raidmem = raidmem
def create(self, *args, **kwargs):
log_method_call(self, device=self.device,
type=self.type, status=self.status)
- raise DMRaidMemberError("creation of dmraid members is not supported")
+ raise DMRaidMemberError("creation of dmraid members is non-sense")
def destroy(self, *args, **kwargs):
log_method_call(self, device=self.device,
type=self.type, status=self.status)
- raise DMRaidMemberError("destruction of dmraid members is not supported")
-
+ raise DMRaidMemberError("destruction of dmraid members is non-sense")
register_device_format(DMRaidMember)
diff --git a/storage/partitioning.py b/storage/partitioning.py
index d1f2d4d9c..78929cf46 100644
--- a/storage/partitioning.py
+++ b/storage/partitioning.py
@@ -32,7 +32,7 @@ from constants import *
from errors import *
from deviceaction import *
-from devices import PartitionDevice, LUKSDevice
+from devices import PartitionDeviceFactory, LUKSDevice
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
@@ -530,7 +530,7 @@ def doPartitioning(storage, exclusiveDisks=None):
# that does not exist means leaving self.parents empty and instead
# populating self.req_disks. In this case, we need to skip past
# that since this partition is already defined.
- device = PartitionDevice(extended.getDeviceNodeName(),
+ device = PartitionDeviceFactory(extended.getDeviceNodeName(),
parents=disk)
device.parents = [disk]
device.partedPartition = extended
diff --git a/storage/udev.py b/storage/udev.py
index 6df00c855..a39b98c81 100644
--- a/storage/udev.py
+++ b/storage/udev.py
@@ -270,4 +270,37 @@ def udev_device_get_lv_sizes(info):
return [float(s) / 1024 for s in sizes]
+def udev_device_is_dmraid(info):
+ # Note that this function does *not* identify raid sets.
+ # Tests to see if device is parto of a dmraid set.
+ # dmraid and mdriad have the same ID_FS_USAGE string, ID_FS_TYPE has a
+ # string that describes the type of dmraid (isw_raid_member...), I don't
+ # want to maintain a list and mdraid's ID_FS_TYPE='linux_raid_member', so
+ # dmraid will be everything that is raid and not linux_raid_member
+ if info.has_key("ID_FS_USAGE") and info.has_key("ID_FS_TYPE") and \
+ info["ID_FS_USAGE"] == "raid" and \
+ info["ID_FS_TYPE"] != "linux_raid_member":
+ return True
+
+ return False
+
+def udev_device_get_dmraid_partition_disk(info):
+ try:
+ p_index = info["DM_NAME"].rindex("p")
+ except:
+ return None
+
+ if not info["DM_NAME"][p_index+1:].isdigit():
+ return None
+
+ return info["DM_NAME"][:p_index]
+
+def udev_device_is_dmraid_partition(info, devicetree):
+ diskname = udev_device_get_dmraid_partition_disk(info)
+ dmraid_devices = devicetree.getDevicesByType("dm-raid array")
+
+ for device in dmraid_devices:
+ if diskname == device.name:
+ return True
+ return False