[blivet:master 3/5] Use new RaidDevice class in appropriate Device subclasses.

mulhern amulhern at redhat.com
Mon Oct 6 13:14:50 UTC 2014


Signed-off-by: mulhern <amulhern at redhat.com>
---
 blivet/devices/btrfs.py | 57 +++++++++++++++++--------------------------------
 blivet/devices/md.py    | 45 +++++++++++++++++++-------------------
 2 files changed, 43 insertions(+), 59 deletions(-)

diff --git a/blivet/devices/btrfs.py b/blivet/devices/btrfs.py
index 16d0970..e2039d9 100644
--- a/blivet/devices/btrfs.py
+++ b/blivet/devices/btrfs.py
@@ -37,6 +37,7 @@ log = logging.getLogger("blivet")
 
 from .storage import StorageDevice
 from .container import ContainerDevice
+from .raid import RaidDevice
 
 class BTRFSDevice(StorageDevice):
     """ Base class for BTRFS volume and sub-volume devices. """
@@ -165,8 +166,15 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
         self._dataLevel = self._metaDataLevel = None
 
         # assign after constructor to avoid AttributeErrors in setter functions
-        self.dataLevel = dataLevel
-        self.metaDataLevel = metaDataLevel
+        try:
+            self.dataLevel = dataLevel
+            self.metaDataLevel = metaDataLevel
+        except errors.BTRFSValueError as e:
+            # Could not set the levels, so set loose the parents that were
+            # added in superclass constructor.
+            for dev in self.parents:
+                dev.removeChild()
+            raise e
 
         self.subvolumes = []
         self.size_policy = self.size
@@ -183,19 +191,6 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
 
         self._defaultSubVolumeID = None
 
-    def _validateRaidLevel(self, level):
-        """ Returns an error message if the RAID level is invalid for this
-            device, otherwise None.
-
-            :param level: a RAID level
-            :type level: :class:`~.devicelibs.raid.RAIDLevel`
-            :returns: an error message if the RAID level is invalid, else None
-            :rtype: str or NoneType
-        """
-        if not self.exists and len(self.parents) < level.min_members:
-            return "RAID level %s requires that device have at least %d members, but device has only %d members." % (level, level.min_members, len(self.parents))
-        return None
-
     def _setLevel(self, value, data):
         """ Sets a valid level for this device and level type.
 
@@ -210,16 +205,11 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
         """
         level = None
         if value:
+            levels = btrfs.RAID_levels if data else btrfs.metadata_levels
             try:
-                levels = btrfs.RAID_levels if data else btrfs.metadata_levels
-                level = levels.raidLevel(value)
-            except errors.RaidError:
-                data_type_str = "data" if data else "metadata"
-                raise errors.BTRFSValueError("%s is an invalid value for %s RAID level." % (value, data_type_str))
-
-            error_msg = self._validateRaidLevel(level)
-            if error_msg:
-                raise errors.BTRFSValueError(error_msg)
+                level = self._getLevel(value, levels)
+            except ValueError as e:
+                raise errors.BTRFSValueError(e)
 
         if data:
             self._dataLevel = level
@@ -291,18 +281,11 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
         return size
 
     def _removeParent(self, member):
-        """ Raises a DeviceError if the device has a raid level and the
-            resulting number of parents would be fewer than the minimum
-            number required by the raid level.
-
-            Note: btrfs does not permit degrading an array.
-        """
-        levels = [l for l in [self.dataLevel, self.metaDataLevel] if l]
-        if levels:
-            min_level = min(levels, key=lambda l: l.min_members)
-            min_members = min_level.min_members
-            if len(self.parents) - 1 < min_members:
-                raise errors.DeviceError("device %s requires at least %d membersfor raid level %s" % (self.name, min_members, min_level))
+        levels = (l for l in (self.dataLevel, self.metaDataLevel) if l)
+        for l in levels:
+            error_msg = self._validateParentRemoval(l, member)
+            if error_msg:
+                raise errors.DeviceError(error_msg)
         super(BTRFSVolumeDevice, self)._removeParent(member)
 
     def _addSubVolume(self, vol):
@@ -454,7 +437,7 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
         data.devices = ["btrfs.%d" % p.id for p in self.parents]
         data.preexist = self.exists
 
-class BTRFSSubVolumeDevice(BTRFSDevice):
+class BTRFSSubVolumeDevice(BTRFSDevice, RaidDevice):
     """ A btrfs subvolume pseudo-device. """
     _type = "btrfs subvolume"
     _formatImmutable = True
diff --git a/blivet/devices/md.py b/blivet/devices/md.py
index dd4b726..d5ee365 100644
--- a/blivet/devices/md.py
+++ b/blivet/devices/md.py
@@ -29,15 +29,15 @@ from ..flags import flags
 from ..storage_log import log_method_call
 from .. import udev
 from ..size import Size
-from ..i18n import P_
 
 import logging
 log = logging.getLogger("blivet")
 
 from .storage import StorageDevice
 from .container import ContainerDevice
+from .raid import RaidDevice
 
-class MDRaidArrayDevice(ContainerDevice):
+class MDRaidArrayDevice(ContainerDevice, RaidDevice):
     """ An mdraid (Linux RAID) device. """
     _type = "mdarray"
     _packages = ["mdadm"]
@@ -88,16 +88,18 @@ class MDRaidArrayDevice(ContainerDevice):
 
         if level == "container":
             self._type = "mdcontainer"
-        self.level = level
 
-        # For new arrays check if we have enough members
-        if (not exists and parents and len(parents) < self.level.min_members):
+        # avoid attribute-defined-outside-init pylint warning
+        self._level = None
+
+        try:
+            self.level = level
+        except errors.DeviceError as e:
+            # Could not set the level, so set loose the parents that were
+            # added in superclass constructor.
             for dev in self.parents:
                 dev.removeChild()
-            raise errors.DeviceError(P_("A %(raidLevel)s set requires at least %(minMembers)d member",
-                                 "A %(raidLevel)s set requires at least %(minMembers)d members",
-                                 self.level.min_members) % \
-                                 {"raidLevel": self.level, "minMembers": self.level.min_members})
+            raise e
 
         self.uuid = uuid
         self._totalDevices = util.numeric_type(totalDevices)
@@ -136,10 +138,17 @@ class MDRaidArrayDevice(ContainerDevice):
         """ Set the RAID level and enforce restrictions based on it.
 
             :param value: new raid level
-            :param type:  a valid raid level descriptor
+            :param type:  object
+            :raises: :class:`~.errors.DeviceError` if value does not describe
+            a valid RAID level
             :returns:     None
         """
-        self._level = mdraid.RAID_levels.raidLevel(value) # pylint: disable=attribute-defined-outside-init
+        try:
+            level = self._getLevel(value, mdraid.RAID_levels)
+        except ValueError as e:
+            raise errors.DeviceError(e)
+
+        self._level = level
 
     @property
     def createBitmap(self):
@@ -305,17 +314,9 @@ class MDRaidArrayDevice(ContainerDevice):
             self.memberDevices += 1
 
     def _removeParent(self, member):
-        """ If this is a raid array that is not actually redundant and it
-            appears to have formatting and therefore probably data on it,
-            removing one of its devices is a bad idea.
-        """
-        try:
-            if not self.level.has_redundancy() and self.exists and member.format.exists:
-                raise errors.DeviceError("cannot remove members from existing %s array" % self.level)
-        except errors.RaidError:
-            # If the concept of redundancy is meaningless for this device's
-            # raid level, then it is OK to remove a parent device.
-            pass
+        error_msg = self._validateParentRemoval(self.level, member)
+        if error_msg:
+            raise errors.DeviceError(error_msg)
 
         super(MDRaidArrayDevice, self)._removeParent(member)
         self.memberDevices -= 1
-- 
1.9.3



More information about the anaconda-patches mailing list