[blivet 06/13] Changed devicelibs.mdraid to make use of devicelibs.raid.

mulhern amulhern at redhat.com
Tue Nov 26 18:47:11 UTC 2013


Added an MDCONTAINER class.

Extended raid.RAIDLevels so that it required that all RAIDLevels define
min_members.

Added an MDCONTAINER object to the RAIDLevels object.

Methods changed are:

* raidLevel
* raidLevelString
* get_raid_min_members
* get_raid_max_spares
* get_member_space

All the raid constants now depend on raid.

Methods added are:

* getRaidLevel

* raidLevelString was modified so that it takes a flag to use nicknames
instead of canonical names and so that it accepts any valid descriptor,
not just a numeric one.

Members removed are:

* isRaid
* raid_descriptors
---
 blivet/devicelibs/mdraid.py          | 193 +++++++++++++++++++----------------
 tests/devicelibs_test/mdraid_test.py |  27 +++--
 2 files changed, 117 insertions(+), 103 deletions(-)

diff --git a/blivet/devicelibs/mdraid.py b/blivet/devicelibs/mdraid.py
index 54b7fcf..66cfe9c 100644
--- a/blivet/devicelibs/mdraid.py
+++ b/blivet/devicelibs/mdraid.py
@@ -25,6 +25,8 @@ import os
 from .. import util
 from ..errors import *
 
+from . import raid
+
 import gettext
 _ = lambda x: gettext.ldgettext("blivet", x)
 
@@ -35,72 +37,96 @@ log = logging.getLogger("blivet")
 MD_SUPERBLOCK_SIZE = 2.0    # MB
 MD_CHUNK_SIZE = 0.5         # MB
 
+class MDRaidLevels(raid.RAIDLevels):
+    @classmethod
+    def isRaidLevel(cls, level):
+        """Every mdraid level must define min_members."""
+        try:
+            min_members = level.min_members
+            return super(MDRaidLevels, cls).isRaidLevel(level) and min_members > 0
+        except AttributeError:
+            return False
+
+_RAID_levels = MDRaidLevels()
+
 # raidlevels constants
-RAID10 = 10
-RAID6 = 6
-RAID5 = 5
-RAID4 = 4
-RAID1 = 1
-RAID0 = 0
+RAID10 = _RAID_levels.raidLevel(10).number
+RAID6 = _RAID_levels.raidLevel(6).number
+RAID5 = _RAID_levels.raidLevel(5).number
+RAID4 = _RAID_levels.raidLevel(4).number
+RAID1 = _RAID_levels.raidLevel(1).number
+RAID0 = _RAID_levels.raidLevel(0).number
 
 raid_levels = [ RAID0, RAID1, RAID4, RAID5, RAID6, RAID10 ]
 
-raid_descriptors = {RAID10: ("raid10", "RAID10", "10", 10),
-                    RAID6: ("raid6", "RAID6", "6", 6),
-                    RAID5: ("raid5", "RAID5", "5", 5),
-                    RAID4: ("raid4", "RAID4", "4", 4),
-                    RAID1: ("raid1", "mirror", "RAID1", "1", 1),
-                    RAID0: ("raid0", "stripe", "RAID0", "0", 0)}
+class MDCONTAINER(object):
+    name = "container"
+    names = [name]
+    nick = None
+    min_members = 1
+    def get_recommended_stride(self, member_devices):
+        return None
+    def get_size(self, member_count, smallest_member_size, chunk_size):
+        raise MDRaidError("get_size is not defined for level container.")
+    def get_raw_arraYsize(self, member_count, smallest_member_size):
+        raise MDRaidError("get_raw_array_size is not defined for level container.")
+    def __str__(self):
+        return self.name
+
+MDCONTAINER = MDCONTAINER()
+_RAID_levels.addRaidLevel(MDCONTAINER)
+
+def getRaidLevel(descriptor):
+    """Return an object for this raid level descriptor.
+       Raises an MDRaidError if the descriptor is not valid.
+    """
+    try:
+        return _RAID_levels.raidLevel(descriptor)
+    except RaidError as e:
+        raise MDRaidError(e.message)
 
 def raidLevel(descriptor):
-    for level in raid_levels:
-        if isRaid(level, descriptor):
-            return level
-    else:
-        raise MDRaidError("invalid raid level descriptor %s" % descriptor)
+    """Return an integer code corresponding to this raid level descriptor.
+       Raises an MDRaidError if the descriptor is not valid or does not
+       have a corresponding numeric code.
+    """
+    try:
+        return _RAID_levels.raidLevel(descriptor).number
+    except RaidError as e:
+        raise MDRaidError(e.message)
+    except ValueError:
+        raise MDRaidError(e.message)
 
-def raidLevelString(level):
-    if level in raid_descriptors.keys():
-        return raid_descriptors[level][0]
-    else:
-        raise MDRaidError("invalid raid level constant %s" % level)
+def raidLevelString(descriptor, use_nick=False):
+    """Returns the canonical name for the descriptor. Raises an
+       MDRaidError if there is no corresponding level for the descriptor.
 
-def isRaid(raid, raidlevel):
-    """Return whether raidlevel is a valid descriptor of raid"""
-    if raid in raid_descriptors:
-        return raidlevel in raid_descriptors[raid]
-    else:
-        raise MDRaidError("invalid raid level %d" % raid)
-
-def get_raid_min_members(raidlevel):
-    """Return the minimum number of raid members required for raid level"""
-    raid_min_members = {RAID10: 4,
-                        RAID6: 4,
-                        RAID5: 3,
-                        RAID4: 3,
-                        RAID1: 2,
-                        RAID0: 2}
-
-    for raid, min_members in raid_min_members.items():
-        if isRaid(raid, raidlevel):
-            return min_members
-
-    raise MDRaidError("invalid raid level %s" % raidlevel)
-
-def get_raid_max_spares(raidlevel, nummembers):
-    """Return the maximum number of raid spares for raidlevel."""
-    raid_max_spares = {RAID10: lambda: max(0, nummembers - get_raid_min_members(RAID10)),
-                       RAID6: lambda: max(0, nummembers - get_raid_min_members(RAID6)),
-                       RAID5: lambda: max(0, nummembers - get_raid_min_members(RAID5)),
-                       RAID4: lambda: max(0, nummembers - get_raid_min_members(RAID4)),
-                       RAID1: lambda: max(0, nummembers - get_raid_min_members(RAID1)),
-                       RAID0: lambda: 0}
-
-    for raid, max_spares_func in raid_max_spares.items():
-        if isRaid(raid, raidlevel):
-            return max_spares_func()
-
-    raise MDRaidError("invalid raid level %d" % raidlevel)
+       Return the nickname if use_nick is True.
+    """
+    try:
+        return _RAID_levels.raidLevelString(descriptor, use_nick)
+    except RaidError as e:
+        raise MDRaidError(e.message)
+
+def get_raid_min_members(descriptor):
+    """Return the minimum number of raid members required for this raid
+       level descriptor. Raises an MDRaidError if the descriptor is
+       invalid.
+    """
+    try:
+        return _RAID_levels.raidLevel(descriptor).min_members
+    except RaidError as e:
+        raise MDRaidError(e.message)
+
+def get_raid_max_spares(descriptor, nummembers):
+    """Return the maximum number of raid spares for the descriptor,
+       given nummembers members in the array. Raises an MDRaidError
+       if the descriptor is invalid.
+    """
+    try:
+        return _RAID_levels.raidLevel(descriptor).get_max_spares(nummembers)
+    except RaidError as e:
+        raise MDRaidError(e.message)
 
 def get_raid_superblock_size(size, version=None):
     """ mdadm has different amounts of space reserved for its use depending
@@ -127,37 +153,26 @@ def get_raid_superblock_size(size, version=None):
     return headroom
 
 def get_member_space(size, disks, level=None):
-    space = 0   # size of *each* member device
-
-    if isinstance(level, str):
-        level = raidLevel(level)
-
-    min_members = get_raid_min_members(level)
-    if disks < min_members:
-        raise MDRaidError("raid%d requires at least %d disks"
-                         % (level, min_members))
-
-    if level == RAID0:
-        # you need the sum of the member sizes to equal your desired capacity
-        space = size / disks
-    elif level == RAID1:
-        # you need each member's size to equal your desired capacity
-        space = size
-    elif level in (RAID4, RAID5):
-        # you need the sum of all but one members' sizes to equal your desired
-        # capacity
-        space = size / (disks - 1)
-    elif level == RAID6:
-        # you need the sum of all but two members' sizes to equal your desired
-        # capacity
-        space = size / (disks - 2)
-    elif level == RAID10:
-        # you need the sum of the member sizes to equal twice your desired
-        # capacity
-        space = size / (disks / 2)
-
-    space += get_raid_superblock_size(size)
-
+    """Return the total mB required to store size data.
+       The steps are:
+         * Find the size required for each member
+         * Add to that the superblock size
+         * multiply that by the number of disks to get the required total size.
+       :param size: amount of data
+       :type size: natural number
+
+       :param disks: number of disks
+       :type disks: natural number
+
+       Raises and MDRaidError if there is no level correspondign to level
+       or if the number of disks is less than the minimum number required
+       for the raid level.
+    """
+    try:
+        space = _RAID_levels.raidLevel(level).get_base_member_size(size, disks) + \
+           get_raid_superblock_size(size)
+    except RaidError as e:
+        raise MDRaidError(e.message)
     return space * disks
 
 def mdadm(args):
diff --git a/tests/devicelibs_test/mdraid_test.py b/tests/devicelibs_test/mdraid_test.py
index f6bb72a..c92a0bd 100755
--- a/tests/devicelibs_test/mdraid_test.py
+++ b/tests/devicelibs_test/mdraid_test.py
@@ -11,6 +11,14 @@ class MDRaidTestCase(unittest.TestCase):
 
     def testMDRaid(self):
 
+        self.assertEqual(mdraid.getRaidLevel("container").name, "container")
+        self.assertEqual(mdraid.getRaidLevel("stripe").name, "raid0")
+        self.assertEqual(mdraid.getRaidLevel("mirror").name, "raid1")
+        self.assertEqual(mdraid.getRaidLevel("4").name, "raid4")
+        self.assertEqual(mdraid.getRaidLevel(5).name, "raid5")
+        self.assertEqual(mdraid.getRaidLevel("RAID6").name, "raid6")
+        self.assertEqual(mdraid.getRaidLevel("raid10").name, "raid10")
+
         ##
         ## get_raid_min_members
         ##
@@ -81,18 +89,6 @@ class MDRaidTestCase(unittest.TestCase):
            mdraid.get_member_space, 1024, 0, 0)
 
         ##
-        ## isRaid
-        ##
-        self.assertTrue(mdraid.isRaid(0, "RAID0"))
-        self.assertFalse(mdraid.isRaid(6, "RAID0"))
-
-        # fail
-        # invalid raid
-        self.assertRaisesRegexp(errors.MDRaidError,
-           "invalid raid level",
-           mdraid.isRaid, 7, "RAID")
-
-        ##
         ## raidLevel
         ##
         self.assertEqual(mdraid.raidLevel("RAID0"), 0)
@@ -107,12 +103,15 @@ class MDRaidTestCase(unittest.TestCase):
         ## raidLevelString
         ##
         self.assertEqual(mdraid.raidLevelString(0), "raid0")
+        self.assertEqual(mdraid.raidLevelString(0, True), "stripe")
+        self.assertEqual(mdraid.raidLevelString(1, True), "mirror")
+        self.assertEqual(mdraid.raidLevelString(6, True), "raid6")
 
         # fail
         # invalid constant
         self.assertRaisesRegexp(errors.MDRaidError,
-           "invalid raid level constant",
-          mdraid.raidLevelString, -1)
+           "invalid raid level",
+           mdraid.raidLevelString, -1)
 
 class MDRaidAsRootTestCase(baseclass.DevicelibsTestCase):
 
-- 
1.8.3.1



More information about the anaconda-patches mailing list