[anaconda:master] RAID related changes for custom spoke.

David Lehman dlehman at redhat.com
Thu May 29 22:46:32 UTC 2014


This is a first pass through just the commit message. I will read the 
actual patch tomorrow if possible.

On 05/29/2014 01:48 PM, mulhern wrote:
> - RAID objects instead of strings are now used everywhere. Previously,
> the approach was a bit more hybrid, with strings floating around here
> and there.
>
> - Move get_supported_raid_levels to blivet.devicefactory. This method
> is supposed to yield the raid levels that blivet supports, not necessarily
> those that anaconda allows. The return type is changed to a set of RAID
> objects during the move and the return values are somewhat modified.
> * btrfs substitutes single for none
> * lvm omits none
> * RAID adds container and linear
>
> - Currently RAID levels are only offered on the Manual Partitioning screen
> if the user has selected RAID. So, the only options that are ever shown are
> one that RAID allows. There is little point in having other always invisible
> options, so there are none left in the custom.glade file.
> Previously there was "none".

At some point LVM will need a RAID level selector as well on the main 
screen.

>
> - In CustomPartitioningSpoke._validate_mountpoint RAID related validation
> tests have been generalized a bit.
>
> - blivet.devices.Device.raidLevel replaces
> blivet.devicefactory.get_raid_level.

Please consider going the other way on this by moving get_raid_level 
into custom_storage_helpers instead of deeper into blivet.

>
> - In _save_right_side the container raid level validation has been
> generalized a bit.
>
> - CustomPartitioningSpoke._raid_level_visible has been generalized to
> use raidLevelsSupported().

Does this mean that users will see container and linear as options for 
raid now?

>
> - CustomPartitiongSpoke._populate_raid has been simplified a bit,
> and generalized a bit.
>
> - In on_device_type_changed some general methods are used. Previously the
> code sets btrfs's raid_level and passed it to _populate_raid(), but
> _populate_raid() never displays any RAID choices for btrfs on manual
> partitoning screen, so this code had no effect. Btrfs RAID choices are
> shown on the "Configure Volume" screen, reached by pressing the Modify
> button. The effectless code is just removed. This leaves a few unused
> identifiers, which are also removed.
>
> - "none" is removed from the custom_storage_helpers.glade RAID options for
> the "Configure Volume/Configure Volume Group" window, "single" is added
> for btrfs, and linear is added for the mdadm RAID options for lvm. This
> has the added benefit of giving the user at least one RAID choice that
> only requires one disk. "linear" and "single" are the default RAID levels
> for this situation.
> There is a sense in which "none" should be offered for lvm on RAID, since
> if there is only one disk no RAID level is necessary, but that seems unduly
> complicated and "linear" will do just as well.

We have to leave an option to use LVM without RAID.

>
> - selectedRaidLevel() is changed so that it returns a RAIDLevel object or
> None, rather than a string.
>
> - Several methods are added to custom_storage_helpers.py. They are small
> and copiously commented.

Some of this makes me a bit nervous. LVM provides its own container -- 
the volume group. The only sense in which MD/RAID is a container for LVM 
is where it is used as an additional layer to provide container-wide 
RAID. Perhaps it's just that the function names aren't specific enough?

>
> - ContainerDialog._raid_level_visible can be simplified by using
> containerRaidLevelsSupported(), one of the newly introduced methods.
>
> - ContainerDialog._populate_raid() can also be simplified a bit.
>
> Signed-off-by: mulhern <amulhern at redhat.com>
> ---
>   pyanaconda/storage_utils.py                        |  17 ---
>   pyanaconda/ui/gui/spokes/custom.glade              |   4 -
>   pyanaconda/ui/gui/spokes/custom.py                 |  88 ++++++------
>   .../ui/gui/spokes/lib/custom_storage_helpers.glade |   8 +-
>   .../ui/gui/spokes/lib/custom_storage_helpers.py    | 151 +++++++++++++++++----
>   5 files changed, 179 insertions(+), 89 deletions(-)
>
> diff --git a/pyanaconda/storage_utils.py b/pyanaconda/storage_utils.py
> index 6478282..f353c6d 100644
> --- a/pyanaconda/storage_utils.py
> +++ b/pyanaconda/storage_utils.py
> @@ -40,18 +40,6 @@ from pykickstart.constants import AUTOPART_TYPE_LVM, AUTOPART_TYPE_LVM_THINP
>   import logging
>   log = logging.getLogger("anaconda")
>
> -# should this and the get_supported_raid_levels go to blivet.devicefactory???
> -SUPPORTED_RAID_LEVELS = {DEVICE_TYPE_LVM: {"none", "raid0", "raid1"},
> -                         DEVICE_TYPE_LVM_THINP: {"none", "raid0", "raid1"},
> -                         DEVICE_TYPE_MD: {"raid0", "raid1", "raid4", "raid5",
> -                                          "raid6", "raid10"},
> -                         DEVICE_TYPE_BTRFS: {"none", "raid0", "raid1",
> -                                             "raid10"},
> -                         # no device type for LVM VG
> -                         # VG: {"none", "raid0", "raid1", "raid4",
> -                         #      "raid5", "raid6", "raid10"},
> -                        }
> -
>   # TODO: all those constants and mappings should go to blivet
>   DEVICE_TEXT_LVM = N_("LVM")
>   DEVICE_TEXT_LVM_THINP = N_("LVM Thin Provisioning")
> @@ -114,11 +102,6 @@ def size_from_input(input_str):
>
>       return size
>
> -def get_supported_raid_levels(device_type):
> -    """Get supported RAID levels for the given device type."""
> -
> -    return SUPPORTED_RAID_LEVELS.get(device_type, set())
> -
>   def device_type_from_autopart(autopart_type):
>       """Get device type matching the given autopart type."""
>
> diff --git a/pyanaconda/ui/gui/spokes/custom.glade b/pyanaconda/ui/gui/spokes/custom.glade
> index 859712b..4a4900a 100644
> --- a/pyanaconda/ui/gui/spokes/custom.glade
> +++ b/pyanaconda/ui/gui/spokes/custom.glade
> @@ -59,10 +59,6 @@
>       </columns>
>       <data>
>         <row>
> -        <col id="0" translatable="yes">None</col>
> -        <col id="1">none</col>
> -      </row>
> -      <row>
>           <col id="0" translatable="yes">RAID0 &lt;span foreground="grey"&gt;(Performance)&lt;/span&gt;</col>
>           <col id="1">raid0</col>
>         </row>
> diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
> index 328cf61..6f7aa52 100644
> --- a/pyanaconda/ui/gui/spokes/custom.py
> +++ b/pyanaconda/ui/gui/spokes/custom.py
> @@ -50,7 +50,6 @@ from blivet.devicefactory import DEVICE_TYPE_PARTITION
>   from blivet.devicefactory import DEVICE_TYPE_MD
>   from blivet.devicefactory import DEVICE_TYPE_DISK
>   from blivet.devicefactory import DEVICE_TYPE_LVM_THINP
> -from blivet.devicefactory import get_raid_level
>   from blivet.devicefactory import SIZE_POLICY_AUTO
>   from blivet import findExistingInstallations
>   from blivet.partitioning import doAutoPartition
> @@ -60,11 +59,11 @@ from blivet.errors import NotEnoughFreeSpaceError
>   from blivet.errors import SanityError
>   from blivet.errors import SanityWarning
>   from blivet.errors import LUKSDeviceWithoutKeyError
> -from blivet.devicelibs import mdraid
> +from blivet.devicelibs import raid
>   from blivet.devices import LUKSDevice
>
> -from pyanaconda.storage_utils import get_supported_raid_levels, ui_storage_logger, device_type_from_autopart
> -from pyanaconda.storage_utils import DEVICE_TEXT_PARTITION, DEVICE_TEXT_MD, DEVICE_TEXT_MAP
> +from pyanaconda.storage_utils import ui_storage_logger, device_type_from_autopart
> +from pyanaconda.storage_utils import DEVICE_TEXT_PARTITION, DEVICE_TEXT_MAP
>   from pyanaconda.storage_utils import PARTITION_ONLY_FORMAT_TYPES, MOUNTPOINT_DESCRIPTIONS
>   from pyanaconda.storage_utils import NAMED_DEVICE_TYPES, CONTAINER_DEVICE_TYPES
>
> @@ -78,7 +77,8 @@ from pyanaconda.ui.gui.spokes.lib.refresh import RefreshDialog
>   from pyanaconda.ui.gui.spokes.lib.summary import ActionSummaryDialog
>
>   from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import size_from_entry
> -from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import validate_label, validate_mountpoint, selectedRaidLevel
> +from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import validate_label, validate_mountpoint
> +from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import selectedRaidLevel, raidLevelSelection, defaultRaidLevel, requiresRaidSelection, containerRaidLevelsSupported, raidLevelsSupported
>   from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import get_container_type_name, RAID_NOT_ENOUGH_DISKS
>   from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import AddDialog, ConfirmDeleteDialog, DisksDialog, ContainerDialog, HelpDialog
>
> @@ -609,6 +609,16 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>
>       def _validate_mountpoint(self, mountpoint, device, device_type, new_fs_type,
>                               reformat, encrypted, raid_level):
> +        """ Validate various aspects of a mountpoint.
> +
> +            :param str mountpoint: the mountpoint
> +            :param device: blivet.devices.Device instance
> +            :param int device_type: one of an enumeration of device types
> +            :param str new_fs_type: string representing the new filesystem type
> +            :param bool reformat: whether the device is to be reformatted
> +            :param bool encrypted: whether the device is to be encrypted
> +            :param raid_level: instance of blivet.devicelibs.raid.RAIDLevel or None
> +        """
>           error = None
>           if device_type != DEVICE_TYPE_PARTITION and mountpoint == "/boot/efi":
>               error = (_("/boot/efi must be on a device of type %s")
> @@ -623,14 +633,17 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>               error = _("%s cannot be encrypted") % new_fs_type
>           elif mountpoint == "/" and device.format.exists and not reformat:
>               error = _("You must create a new filesystem on the root device.")
> -        elif device_type == DEVICE_TYPE_MD and raid_level in (None, "single"):
> -            error = _("Devices of type %s require a valid RAID level selection.") % _(DEVICE_TEXT_MD)
>
> -        if not error and raid_level not in (None, "single"):
> -            md_level = mdraid.getRaidLevel(raid_level)
> -            min_disks = md_level.min_members
> +        if not error and raid_level is None and requiresRaidSelection(device_type):
> +            error = _("Devices of type %s require a valid RAID level selection.") % _(DEVICE_TEXT_MAP[device_type])
> +
> +        if not error and raid_level is not None and raid_level not in raidLevelsSupported(device_type):
> +            error = _("Device of type %s does not support RAID level selection %s.") % (_(DEVICE_TEXT_MAP[device_type]), raid_level)
> +
> +        if not error and raid_level is not None:
> +            min_disks = raid_level.min_members
>               if len(self._device_disks) < min_disks:
> -                error = _(RAID_NOT_ENOUGH_DISKS) % {"level": md_level,
> +                error = _(RAID_NOT_ENOUGH_DISKS) % {"level": raid_level,
>                                                       "min" : min_disks,
>                                                       "count": len(self._device_disks)}
>
> @@ -962,7 +975,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>
>           # RAID LEVEL
>           raid_level = selectedRaidLevel(self._raidLevelCombo)
> -        old_raid_level = get_raid_level(device)
> +        old_raid_level = device.raidLevel
>           changed_raid_level = (old_device_type == device_type and
>                                 device_type in (DEVICE_TYPE_MD,
>                                                 DEVICE_TYPE_BTRFS) and
> @@ -1014,7 +1027,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>               if old_container:
>                   old_container_name = old_container.name
>                   old_container_encrypted = old_container.encrypted
> -                old_container_raid_level = get_raid_level(old_container)
> +                old_container_raid_level = old_container.raidLevel
>                   old_container_size = getattr(old_container, "size_policy",
>                                                               old_container.size)
>
> @@ -1031,7 +1044,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>           changed_container_encrypted = (container_encrypted != old_container_encrypted)
>
>           container_raid_level = self._device_container_raid_level
> -        if container_raid_level == "single" and device_type != DEVICE_TYPE_BTRFS:
> +        if container_raid_level is not None and container_raid_level not in containerRaidLevelsSupported(device_type):
>               container_raid_level = None
>
>           old_device_info["container_raid_level"] = old_container_raid_level
> @@ -1175,26 +1188,28 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>
>       def _raid_level_visible(self, model, itr, user_data):
>           device_type = self._get_current_device_type()
> -        raid_level = model[itr][1]
> -        return raid_level in get_supported_raid_levels(device_type)
> +        raid_level = raid.ALL_LEVELS.raidLevel(model[itr][1])
> +        return raid_level in raidLevelsSupported(device_type)
>
>       def _populate_raid(self, raid_level):
> -        """ Set up the raid-specific portion of the device details. """
> +        """ Set up the raid-specific portion of the device details.
> +
> +            :param raid_level: RAID level
> +            :type raid_level: instance of blivet.devicelibs.raid.RAIDLevel or None
> +        """
>           device_type = self._get_current_device_type()
>           log.debug("populate_raid: %s, %s", device_type, raid_level)
>
> -        if device_type == DEVICE_TYPE_MD:
> -            base_level = "raid1"
> -        else:
> +        if not raidLevelsSupported(device_type):
>               map(really_hide, [self._raidLevelLabel, self._raidLevelCombo])
>               return
>
> -        if not raid_level:
> -            raid_level = base_level
> +        raid_level = raid_level or defaultRaidLevel(device_type)
> +        raid_level_name = raidLevelSelection(raid_level)
>
>           # Set a default RAID level in the combo.
>           for (i, row) in enumerate(self._raidLevelCombo.get_model()):
> -            if row[1] == raid_level:
> +            if row[1] == raid_level_name:
>                   self._raidLevelCombo.set_active(i)
>                   break
>
> @@ -1211,13 +1226,13 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>       def _update_container_info(self, use_dev):
>           if hasattr(use_dev, "vg"):
>               self._device_container_name = use_dev.vg.name
> -            self._device_container_raid_level = get_raid_level(use_dev.vg)
> +            self._device_container_raid_level = use_dev.vg.raidLevel
>               self._device_container_encrypted = use_dev.vg.encrypted
>               self._device_container_size = use_dev.vg.size_policy
>           elif hasattr(use_dev, "volume") or hasattr(use_dev, "subvolumes"):
>               volume = getattr(use_dev, "volume", use_dev)
>               self._device_container_name = volume.name
> -            self._device_container_raid_level = get_raid_level(volume)
> +            self._device_container_raid_level = volume.raidLevel
>               self._device_container_encrypted = volume.encrypted
>               self._device_container_size = volume.size_policy
>           else:
> @@ -1410,8 +1425,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>           else:
>               self._sizeEntry.set_tooltip_text(_("This file system may not be resized."))
>
> -        raid_level = devicefactory.get_raid_level(device)
> -        self._populate_raid(raid_level)
> +        self._populate_raid(device.raidLevel)
>           self._populate_container(device=use_dev)
>           # do this last in case this was set sensitive in on_device_type_changed
>           if use_dev.exists or use_dev.type == "btrfs volume":
> @@ -1534,7 +1548,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>               # don't override user-initiated changes to a defined container
>               dev_info["disks"] = container.disks
>               dev_info.update({"container_encrypted": container.encrypted,
> -                             "container_raid_level": get_raid_level(container),
> +                             "container_raid_level": container.raidLevel,
>                                "container_size": getattr(container, "size_policy",
>                                                          container.size)})
>
> @@ -1555,7 +1569,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>                   # don't override user-initiated changes to a defined container
>                   dev_info["disks"] = container.disks
>                   dev_info.update({"container_encrypted": container.encrypted,
> -                                 "container_raid_level": get_raid_level(container),
> +                                 "container_raid_level": container.raidLevel,
>                                    "container_size": getattr(container, "size_policy",
>                                                                  container.size),
>                                    "container_name": container.name})
> @@ -1722,7 +1736,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>              self._storage_playground.devicetree.getChildren(container) and \
>              container.size_policy == SIZE_POLICY_AUTO:
>               cont_encrypted = container.encrypted
> -            cont_raid = get_raid_level(container)
> +            cont_raid = container.raidLevel
>               cont_size = container.size_policy
>               cont_name = container.name
>               factory = devicefactory.get_device_factory(self._storage_playground,
> @@ -2042,7 +2056,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>           container_exists = getattr(container, "exists", False)    # might not be in the tree
>
>           if container:
> -            self._device_container_raid_level = get_raid_level(container)
> +            self._device_container_raid_level = container.raidLevel
>               self._device_container_encrypted = container.encrypted
>               self._device_container_size = getattr(container, "size_policy",
>                                                                container.size)
> @@ -2379,18 +2393,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>               test_fmt = getFormat("btrfs")
>               should_be_btrfs = test_fmt.supported and test_fmt.formattable
>               fs_type_sensitive = False
> -            with ui_storage_logger():
> -                factory = devicefactory.get_device_factory(self._storage_playground,
> -                                                         DEVICE_TYPE_BTRFS, 0)
> -                container = factory.get_container()
> -
> -            if container:
> -                raid_level = container.dataLevel or "single"
> -            else:
> -                # here I suppose we could alter the default based on disk count
> -                raid_level = "single"
>           elif new_type == DEVICE_TYPE_MD:
> -            raid_level = "raid1"
> +            raid_level = defaultRaidLevel(new_type)
>
>           # lvm uses the RHS to set disk set. no foolish minds here.
>           exists = self._current_selector and self._current_selector.device.exists
> diff --git a/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.glade b/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.glade
> index ecec01e..fa23c6c 100644
> --- a/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.glade
> +++ b/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.glade
> @@ -21,8 +21,12 @@
>       </columns>
>       <data>
>         <row>
> -        <col id="0" translatable="yes">None</col>
> -        <col id="1">none</col>
> +        <col id="0" translatable="yes">Linear &lt;span foreground="grey"&gt;(No Redundancy, No Striping)&lt;/span&gt;</col>
> +        <col id="1">linear</col>
> +      </row>
> +      <row>
> +        <col id="0" translatable="yes">Single &lt;span foreground="grey"&gt;(No Redundancy, No Striping)&lt;/span&gt;</col>
> +        <col id="1">single</col>
>         </row>
>         <row>
>           <col id="0" translatable="yes">RAID0 &lt;span foreground="grey"&gt;(Performance)&lt;/span&gt;</col>
> diff --git a/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.py b/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.py
> index ed5774d..3d3efa2 100644
> --- a/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.py
> +++ b/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.py
> @@ -24,7 +24,9 @@
>   """Helper functions and classes for custom partitioning."""
>
>   __all__ = ["size_from_entry", "populate_mountpoint_store", "validate_label",
> -           "validate_mountpoint", "selectedRaidLevel", "get_container_type_name",
> +           "validate_mountpoint", "selectedRaidLevel", "raidLevelSelection",
> +           "defaultRaidLevel", "requiresRaidSelection",
> +           "containerRaidLevelsSupported", "raidLevelsSupported", "get_container_type_name",
>              "AddDialog", "ConfirmDeleteDialog", "DisksDialog", "ContainerDialog",
>              "HelpDialog"]
>
> @@ -32,7 +34,7 @@ import re
>
>   from pyanaconda.product import productName
>   from pyanaconda.iutil import lowerASCII
> -from pyanaconda.storage_utils import size_from_input, get_supported_raid_levels
> +from pyanaconda.storage_utils import size_from_input
>   from pyanaconda.ui.helpers import InputCheck
>   from pyanaconda.ui.gui import GUIObject
>   from pyanaconda.ui.gui.helpers import GUIDialogInputCheckHandler
> @@ -45,10 +47,13 @@ from blivet.formats import getFormat
>   from blivet.devicefactory import SIZE_POLICY_AUTO
>   from blivet.devicefactory import SIZE_POLICY_MAX
>   from blivet.devicefactory import DEVICE_TYPE_LVM
> -from blivet.devicefactory import DEVICE_TYPE_MD
>   from blivet.devicefactory import DEVICE_TYPE_BTRFS
>   from blivet.devicefactory import DEVICE_TYPE_LVM_THINP
> +from blivet.devicefactory import DEVICE_TYPE_MD
> +from blivet.devicefactory import get_supported_raid_levels
> +from blivet.devicelibs import btrfs
>   from blivet.devicelibs import mdraid
> +from blivet.devicelibs import raid
>
>   import logging
>   log = logging.getLogger("anaconda")
> @@ -139,7 +144,11 @@ def validate_mountpoint(mountpoint, used_mountpoints, strict=True):
>           return ""
>
>   def selectedRaidLevel(raidLevelCombo):
> -    """Interpret the selection of a RAID level combo box."""
> +    """Interpret the selection of a RAID level combo box.
> +
> +       :returns: the selected raid level, None if none selected
> +       :rtype: instance of blivet.devicelibs.raid.RaidLevel or NoneType
> +    """
>       if not raidLevelCombo.get_property("visible"):
>           # the combo is hidden when raid level isn't applicable
>           return None
> @@ -154,7 +163,106 @@ def selectedRaidLevel(raidLevelCombo):
>       if selected_level == "none":
>           return None
>       else:
> -        return selected_level
> +        return raid.ALL_LEVELS.raidLevel(selected_level)
> +
> +def raidLevelSelection(raid_level):
> +    """ Returns a string corresponding to the RAID level.
> +
> +        :param raid_level: a raid level
> +        :type raid_level: instance of blivet.devicelibs.raid.RAID or None
> +        :returns: a string corresponding to this raid level
> +        :rtype: str
> +    """
> +    return raid_level.name if raid_level else "none"
> +
> +def containerDeviceType(device_type):
> +    """ Returns the container device type used to select RAID options.
> +
> +        Generally this is the same as the device type, except that anaconda
> +        supports lvm on RAID, so that lvm's container device type is actually
> +        that for RAID.
> +
> +        :param int device_type: an int representing the device_type
> +        :returns: the device type for choosing container raid level
> +        :rtype: an int representing a device type
> +    """
> +    if device_type in (DEVICE_TYPE_LVM, DEVICE_TYPE_LVM_THINP):
> +        return DEVICE_TYPE_MD
> +    else:
> +        return device_type
> +
> +def defaultRaidLevel(device_type):
> +    """ Returns the default RAID level for this device type.
> +
> +        :param int device_type: an int representing the device_type
> +        :returns: the default RAID level for this device type or None
> +        :rtype: blivet.devicelibs.raid.RAIDLevel or NoneType
> +    """
> +    if device_type == DEVICE_TYPE_BTRFS:
> +        return btrfs.RAID_levels.raidLevel("single")
> +
> +    if device_type == DEVICE_TYPE_MD:
> +        return mdraid.RAID_levels.raidLevel("raid1")
> +
> +    return None
> +
> +def defaultContainerRaidLevel(device_type):
> +    """ Returns the default RAID level for this device type's container type.
> +
> +        :param int device_type: an int representing the device_type
> +        :returns: the default RAID level for this device type's container or None
> +        :rtype: blivet.devicelibs.raid.RAIDLevel or NoneType
> +    """
> +    container_device_type = containerDeviceType(device_type)
> +
> +    if container_device_type == DEVICE_TYPE_BTRFS:
> +        return btrfs.RAID_levels.raidLevel("single")
> +
> +    if container_device_type == DEVICE_TYPE_MD:
> +        return mdraid.RAID_levels.raidLevel("linear")
> +
> +    return None
> +
> +def requiresRaidSelection(device_type):
> +    """ Whether GUI requires a RAID level be selected for this device type."""
> +    return device_type == DEVICE_TYPE_MD
> +
> +def raidLevelsSupported(device_type):
> +    """ The raid levels anaconda supports for this device type.
> +
> +        It supports all RAID levels that blivet supports for a type,
> +        minus those it doesn't like.
> +
> +        Since anaconda only ever allows the user to choose RAID levels for
> +        device type DEVICE_TYPE_MD, hiding the RAID menu for all other device
> +        types, the function only returns a non-empty set for this device type.
> +        If this changes, then so should this function, but at this time it
> +        is not clear what RAID levels should be offered for other device types.
> +
> +        :param int device_type: one of an enumeration of device types
> +        :returns: a set of supported raid levels
> +        :rtype: a set of instances of blivet.devicelibs.raid.RAIDLevel
> +    """
> +    if device_type == DEVICE_TYPE_MD:
> +        unsupported = set(raid.RAIDLevels(["container", "linear"]))
> +        return get_supported_raid_levels(device_type).difference(unsupported)
> +    else:
> +        return set()
> +
> +def containerRaidLevelsSupported(device_type):
> +    """ The raid levels anaconda supports for a container for this
> +        device_type.
> +
> +        It supports the RAID levels that blivet supports minus some that
> +        it does not like.
> +
> +        :param int device_type: one of an enumeration of device types
> +        :returns: a set of supported raid levels
> +        :rtype: a set of instances of blivet.devicelibs.raid.RAIDLevel
> +    """
> +    container_device_type = containerDeviceType(device_type)
> +    unsupported = set(raid.RAIDLevels(["container"]))
> +    return get_supported_raid_levels(container_device_type).difference(unsupported)
>
>   def get_container_type_name(device_type):
>       return CONTAINER_TYPE_NAMES.get(device_type, _("container"))
> @@ -429,10 +537,9 @@ class ContainerDialog(GUIObject, GUIDialogInputCheckHandler):
>
>           raid_level = selectedRaidLevel(self._raidLevelCombo)
>           if raid_level:
> -            md_level = mdraid.getRaidLevel(raid_level)
> -            min_disks = md_level.min_members
> +            min_disks = raid_level.min_members
>               if len(paths) < min_disks:
> -                self._error = (_(RAID_NOT_ENOUGH_DISKS) % {"level" : md_level,
> +                self._error = (_(RAID_NOT_ENOUGH_DISKS) % {"level" : raid_level,
>                                                              "min" : min_disks,
>                                                              "count" : len(paths)})
>                   self._error_label.set_text(self._error)
> @@ -484,32 +591,28 @@ class ContainerDialog(GUIObject, GUIDialogInputCheckHandler):
>           else:
>               self._sizeEntry.set_sensitive(True)
>
> -    def _raid_level_visible(self, model, itr, user_data):
> -        raid_level = model[itr][1]
>
> -        # This is weird because for lvm's container-wide raid we use md.
> -        if self.device_type in (DEVICE_TYPE_LVM, DEVICE_TYPE_LVM_THINP):
> -            # no RAID is an option for LVM(ThP) as well
> -            return (raid_level == "none" or
> -                    raid_level in get_supported_raid_levels(DEVICE_TYPE_MD))
> -        else:
> -            return raid_level in get_supported_raid_levels(self.device_type)
> +    def _raid_level_visible(self, model, itr, user_data):
> +        raid_level = raid.ALL_LEVELS.raidLevel(model[itr][1])
> +        return raid_level in containerRaidLevelsSupported(self.device_type)
>
>       def _populate_raid(self):
> -        """ Set up the raid-specific portion of the device details. """
> -        if not get_supported_raid_levels(self.device_type):
> -            # no supported raid levels for this device type
> +        """ Set up the raid-specific portion of the device details.
> +
> +            Hide the RAID level menu if this device type does not support RAID.
> +            Choose a default RAID level.
> +        """
> +        if not containerRaidLevelsSupported(self.device_type):
>               map(really_hide, [self._raidLevelLabel, self._raidLevelCombo])
>               return
>
> -        raid_level = self.raid_level
> -        if not raid_level or raid_level == "single":
> -            raid_level = "none"
> +        raid_level = self.raid_level or defaultContainerRaidLevel(self.device_type)
> +        raid_level_name = raidLevelSelection(raid_level)
>
>           # Set a default RAID level in the combo.
>           for (i, row) in enumerate(self._raidLevelCombo.get_model()):
>               log.debug("container dialog: raid level %s", row[1])
> -            if row[1] == raid_level:
> +            if row[1] == raid_level_name:
>                   self._raidLevelCombo.set_active(i)
>                   break
>
>


More information about the anaconda-patches mailing list