Re: [PATCH] Handle system crappyness.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Mar 16, 2009 at 07:13:43PM +0100, Joel Granados Moreno wrote:
> * storage/devicelibs/lvm.py (zeroLvmMetadata): zero out the LVM metadata
>   only.  This basically means from 513 byte and on.  This will also
>   ignore the firs 512 bytes if we are in a partition, but that does not
>   matter because LVM does not touch those bits anyways.
> * storage/devicelibs/lvm.py (pv_complete): Complete here means that all
>   the related PVs for the containing VG are present in the system.
>   Returns the Completeness value and a list of known devices.
> * storage/devicelibs/lvm.py (vg_complete): likewise but for VG.
> * storage/devicelibs/lvm.py (vgreduce): introduces a new argument to the
>   function.  rm means use the lvm --removemissing option.
> 
> * storage/devicetree.py (_handleSysCrapyness): New function intended to
>   catch all unwanted behavior from the system before continuing.
> * storage/devicetree.py (questionReinitializeIVG): New function intended
>   to ask the user what to do in case we find inconsistent LVM metadata.
> ---
>  storage/devicelibs/lvm.py |  127 +++++++++++++++++++++++++++++++++++++++++++--
>  storage/devicetree.py     |  104 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 226 insertions(+), 5 deletions(-)
> 
> diff --git a/storage/devicelibs/lvm.py b/storage/devicelibs/lvm.py
> index 0a19711..df21ea9 100644
> --- a/storage/devicelibs/lvm.py
> +++ b/storage/devicelibs/lvm.py
> @@ -99,6 +99,22 @@ def lvm_cc_addFilterRejectRegexp(regexp):
>      _composeConfig()
>  # End config_args handling code.
>  
> +def zeroLvmMetadata(device):
> +    """ This dds from byte 513 to 200Mb+513 of the disk.
> +
> +    We assume that lvm has nothing to do with the first 512 bytes.
> +    We assume that 200Mb is enough.  My tests failed with 100Mb for
> +    some unknown reason.
> +    """
> +    try:
> +        fd = os.open(device, os.O_WRONLY)
> +        os.lseek(fd, 513, os.SEEK_SET)
> +        for i in range(200):
> +            os.write(fd, "\0"*1024)
> +        os.close(fd)
> +    except:
> +        raise LVMError("Falied to zero LVM data on %s." % device)
> +
>  def getPossiblePhysicalExtents(floor=0):
>      """Returns a list of integers representing the possible values for
>         the physical extent of a volume group.  Value is in KB.
> @@ -229,6 +245,100 @@ def pvinfo(device):
>  
>      return info
>  
> +# Start of LVM consistency code
> +#
> +# PV_{,NOT}_COMPLETE:  A PV is complete when it is part of a complete VG or
> +#                      it is part of no VG.  It is incomplete otherwise.
> +# VG_{,NOT}_COMPLETE:  A VG is complete when all its PVs are accounted for
> +#                      by LVM metadata.  More specifically, the `lvm vgs`
> +#                      command has no PVs described as "unknown device"
> +
> +PV_COMPLETE = 0
> +PV_NOT_COMPLETE = 1
> +VG_COMPLETE = 0
> +VG_NOT_COMPLETE = 1
> +
> +def pv_complete(device):
> +    """ Check completeness of lvm structure with Physical Volume device.
> +
> +    Returns : (state, pv_list)
> +              (None, None) means that device is not a PV.
> +
> +    state: [PV_COMPLETE | PV_NOT_COMPLETE]
> +    pv_list: List of PVs related to VG.  If no related VG is found then return
> +             [device]
> +    """
> +    # Make sure this is a PV.
> +    args = ["pvs"] + \
> +            ["--noheadings"] + \
> +            ["-o", "pv_name"] + \
> +            [device]
> +    rc = iutil.execWithCapture("lvm", args,
> +                                stderr = "/dev/tty5")
> +    if rc == None:
> +        # This is not a PV.
> +        return (None, None)
> +
> +    # Get the VG name related to the PV.
> +    args = ["pvs"] + \
> +            ["--noheadings"] + \
> +            ["-o", "vg_name"] + \
> +            [device]
> +    rc = iutil.execWithCapture("lvm", args,
> +                                stderr = "/dev/tty5")
> +    if rc == None:
> +        # Has no VG, but its ok
> +        # FIXME: should look at stderr.
> +        return (PV_COMPLETE, [device])
> +    vg_name = rc.strip()
> +
> +    # Volume Group Completeness (vgs)
> +    (vgc, devices) = vgstatus_ok(vg_name)
> +    if vgc == None:
> +        return (None, None)
> +    elif vgc == VG_NOT_COMPLETE:
> +        return (PV_NOT_COMPLETE, devices)
> +    elif vgc == VG_COMPLETE:
> +        return (PV_COMPLETE, devices)
> +    else:
> +        raise LVMError("Error checking completeness of %s" % vg_name)
> +
> +def vgcomplete(vg_name):
> +    """ Check validity of lvm structure with Physical Volume device.
> +
> +    Returns : (state, pv_list)
> +              (None, None) means that device is not a VG.
> +
> +    state: [VG_COMPLETE | VG_NOT_COMPLETE]
> +    pv_list: List of PVs related to VG.
> +    """
> +    # Ask for the names of the PVs.
> +    args = ["vgs"] +\
> +            ["--noheadings"] + \
> +            ["-o", "pv_name"] + \
> +            [vg_name]
> +    rc = iutil.execWithCapture("lvm", args,
> +                                stderr = "/dev/tty5")
> +
> +    if rc == None:
> +        # This is not a VG.
> +        return (None, None)
> +
> +    # we make sure that every element is striped.  Also, we don't want to
> +    # return "unknown device"
> +    pv_names = rc.strip("\n").split("\n")
> +    ret_pv_names = []
> +    completeness = VG_COMPLETE
> +    for i in range(len(pv_names)):
> +        if pv_names[i].strip() != "unknown device":
> +            ret_pv_names.append(pv_names[i].strip())
> +        else:
> +            completeness = VG_NOT_COMPLETE
> +
> +    return (completeness, pv_names)
> +#
> +# End of LVM consistency code
> +
>  def vgcreate(vg_name, pv_list, pe_size):
>      argv = ["vgcreate"]
>      if pe_size:
> @@ -283,11 +393,18 @@ def vgdeactivate(vg_name):
>      if rc:
>          raise LVMError("vgdeactivate failed for %s" % vg_name)
>  
> -def vgreduce(vg_name, pv_list):
> -    args = ["vgreduce"] + \
> -            config_args + \
> -            [vg_name] + \
> -            pv_list
> +def vgreduce(vg_name, pv_list, rm=False):
> +    """ Reduce a VG.
> +
> +    rm -> with RemoveMissing option.
> +    Use pv_list when rm=False, otherwise ignore pv_list and call vgreduce with
> +    the --removemissing option.
> +    """
> +    args = ["vgreduce"]
> +    if rm:
> +        args.extend(["--removemissing", vg_name])
> +    else:
> +        args.extend([vg_name] + pv_list)
>  
>      rc = iutil.execWithRedirect("lvm", args,
>                                  stdout = "/dev/tty5",
> diff --git a/storage/devicetree.py b/storage/devicetree.py
> index 66d053e..1b4fcbd 100644
> --- a/storage/devicetree.py
> +++ b/storage/devicetree.py
> @@ -136,6 +136,35 @@ def questionInitializeDisk(intf=None, name=None):
>              retVal = True
>      return retVal
>  
> +def questionReinitializeIVG(intf=None, vg_name=None, pv_names=None):
> +    retVal = False # The less destructive default
> +    if not intf or not pv_names: # We need at least the pv_names (list)
> +        pass
> +    else:
> +        if vg_name is not None:
> +            message_part = _("%s, that is an incomplete" % vg_name)
> +        else:
> +            message_part = _("an unknown")
> +
> +        rc = intf.messageWindow(_("Warning"),
> +                  _("Error processing drive(s) %s.\n"
> +                    "It seems that there is inconsistent LVM data "
> +                    "(%s) make(s) up %s Volume Group. "
> +                    "You can reinitialize all related PVs, which will "
> +                    "erase all LVM metadata. Or ignore, which will "
> +                    "preserve contents.")
> +                    %(str(pv_names), str(pv_names), message_part),
> +                type="custom",
> +                custom_buttons = [ _("_Ignore drive(s)"),
> +                                   _("_Re-initialize drive(s)") ],
> +                custom_icon="question")
> +        if rc == 0:
> +            pass
> +        else:
> +            retVal = True # thie means clobber.
> +
> +    return retVal
> +
>  class DeviceTree(object):
>      """ A quasi-tree that represents the devices in the system.
>  
> @@ -1296,6 +1325,76 @@ class DeviceTree(object):
>                                  log.info("setup of %s failed: %s" 
>                                                      % (lv_device.name, e))
>  
> +    def _handleSysCrapyness(self, device):
> +        if device.type == "lvmvg":
> +            # VG completeness (vgc)
> +            (vgc, paths) = lvm.vgcomplete(device.name)
> +            if vgc == lvm.VG_NOT_COMPLETE and \
> +                    questionReinitializeIVG(intf=self.intf, \
> +                        vg_name=device.name, pv_names=paths):
> +                # We reinitialize all de parents.
> +                # First we remove VG data
> +                try:
> +                    lvm.vgreduce(device.name, [], rm=True)
> +                    lvm.vgremove(device.name) # now we can remove
> +                except LVMError:
> +                    # the pvremoves will finish the job.
> +                    pass
> +
> +                for parent in device.parents:
> +                    try:
> +                        lvm.pvremove(parent.path)
> +                    except:
> +                        # does lvm.zerometadata make sence?
> +                        lvm.zeroLvmMetadata(device.path)
> +
> +                    # Give the device the a default format
> +                    kwargs = {"uuid": parent.uuid,
> +                              "label": parent.diskLabel,
> +                              "device": parent.path,
> +                              "exists": parent.exists}
> +                    parent.format = formats.getFormat(*[""], **kwargs)
> +
> +                    # to make sure that we have all the devices:
> +                    #device.remove(parent.path)
> +
> +                # Make sure all devices are handled
> +                #for path in devices:
> +                #   pass # what to do here?
> +
> +                # remove VG device from list.
> +                self._removeDevice(device)

Im missing the part where I ignore the devices here.  I have it, but I
had not commited it :).

> +
> +            return
> +
> +        elif device.format.type == "lvmpv" and \
> +                not lvm.pvstatus_ok(device.path):
> +            if questionReinitializeIVG(intf = self.intf,
> +                                             vg_name = device.format.vgName,
> +                                             pv_names = device.path):
> +                # For some reason there is a failure possibility here
> +                # if the lvm commands dont work, just zero the device.
> +                try:
> +                    if device.format.vgName is not None:
> +                        lvm.vgreduce(device.format.vgName, [], rm=True)
> +                        lvm.vgremove(device.format.vgName) # now we can remove
> +                    lvm.pvremove(device.path) # finally remove the PV
> +                except LVMError:
> +                    # does lvm.zerometadata make sence?
> +                    lvm.zeroLvmMetadata(device.path)
> +
> +                # Give the device the a default format
> +                kwargs = {"uuid": device.uuid,
> +                          "label": device.diskLabel,
> +                          "device": device.path,
> +                          "exists": device.exists}
> +                device.format = formats.getFormat(*[""], **kwargs)
> +
> +            else:
> +                self.addIgnoredDisk(device.name)
> +
> +            return
> +
>      def populate(self):
>          """ Locate all storage devices. """
>          # each iteration scans any devices that have appeared since the
> @@ -1325,6 +1424,11 @@ class DeviceTree(object):
>              for dev in devices:
>                  self.addUdevDevice(dev)
>  
> +        # After having the complete tree we make sure that the system
> +        # inconsistencies are ignored or resolved.
> +        for leaf in self.leaves:
> +            self._handleSysCrapyness(leaf)
> +
>          self.teardownAll()
>  
>      def teardownAll(self):
> -- 
> 1.6.0.6
> 
> _______________________________________________
> Anaconda-devel-list mailing list
> Anaconda-devel-list@xxxxxxxxxx
> https://www.redhat.com/mailman/listinfo/anaconda-devel-list

-- 
Joel Andres Granados
Brno, Czech Republic, Red Hat.

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux