[PATCH] Handle the incompleteness of a VG.

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

 



* storage/devicelibs/lvm.py (pvstatus_ok): New function that tests the
  status of a PV.  If PV part of a complete VG or not part of a VG at
  all, we consider it to be OK. otherwise it needs to be cleaned.
* storage/devicelibs/lvm.py (vgreduce): Add the rm=True arg to the
  vgreduce call.  This will allow us to ignore the device list and tell
  LVM to clean all the additional LVM metadata.
* storage/devicelibs/lvm.py (zeroLvmMetadata): New function to try to
  clobber LVM metadata completely.  This should be used as a last resort
  and zeros out the device from 512bytes to 10Mb.
* storage/devicetree (questionClobberInconsistengVG): New function.  Its
  the callback used to ask the user if the LVM metadata should be erased
  from a dirty PV.
* storage/devicetree (addUdevDevice): Use pvstatus_ok to check for the
  status of each PV we find.
---
 storage/devicelibs/lvm.py |   87 +++++++++++++++++++++++++++++++++++++++++++-
 storage/devicetree.py     |   71 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 155 insertions(+), 3 deletions(-)

diff --git a/storage/devicelibs/lvm.py b/storage/devicelibs/lvm.py
index 0faee10..d4926a6 100644
--- a/storage/devicelibs/lvm.py
+++ b/storage/devicelibs/lvm.py
@@ -49,6 +49,23 @@ def has_lvm():
 
     return has_lvm
 
+def zeroLvmMetadata(device):
+    """ This dds from byte 513 to 100Mb of the disk.
+
+    We assume that lvm has nothing to do with the first 512 bytes.
+    We assume that 20Mb is enough.  My tests failed with 10Mb for
+    some unknown reason.
+    """
+    args = ["if=/dev/zero" , "of=%s"%device] + \
+            ["seek=1", "bs=512", "count=400"]
+    rc = iutil.execWithRedirect("dd", args,
+                                stdout = "/dev/tty5",
+                                stderr = "/dev/tty5",
+                                searchPath=1)
+    if rc:
+        raise LVMError("dd failed for %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.
@@ -171,6 +188,60 @@ def pvinfo(device):
 
     return info
 
+def pvstatus_ok(device):
+    """ Check validity of lvm structure with Physical Volume device.
+
+    Possibilities:
+    1. PV part of a complete VG (OK!)
+    2. PV is not part of any VG (OK!)
+    3. PV part of an incomplete VG (ERROR!)
+    4. device is not a PV (ERROR!)
+
+    Returs True for 1 & 2. False for 3 & 4.
+    """
+    # 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 False
+
+    # 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 True
+    vg_name = rc.strip()
+
+    # Get all the PVs that are in the VG
+    args = ["vgs"] + \
+            ["--noheadings"] + \
+            ["-o", "pv_name"] + \
+            [vg_name]
+    rc = iutil.execWithCapture("lvm", args,
+                                stderr = "/dev/tty5")
+    pv_names = rc.strip("\n").split("\n")
+
+    if len(pv_names) == 0:
+        return False
+
+    # Analyse returned PVs
+    for pv_name in pv_names:
+        if pv_name.strip() == "unknown device":
+            return False
+
+    return True
+
 def vgcreate(vg_name, pv_list, pe_size):
     argv = ["vgcreate"]
     if pe_size:
@@ -212,8 +283,20 @@ def vgdeactivate(vg_name):
     if rc:
         raise LVMError("vgdeactivate failed for %s" % vg_name)
 
-def vgreduce(vg_name, pv_list):
-    rc = iutil.execWithRedirect("lvm", ["vgreduce", 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",
                                 stderr = "/dev/tty5",
                                 searchPath=1)
diff --git a/storage/devicetree.py b/storage/devicetree.py
index e974717..fb82e28 100644
--- a/storage/devicetree.py
+++ b/storage/devicetree.py
@@ -135,6 +135,35 @@ def questionInitializeDisk(intf=None, name=None):
             retVal = True
     return retVal
 
+def questionClobberInconsistengVG(intf=None, pv_name=None, vg_name=None):
+    retVal = False # The less destructive default
+    if not intf or not pv_name:
+        pass
+    else:
+        if vg_name is not None:
+            message_part = _("%s, that is an incomplete" % vg_name)
+        else:
+            message_part = _("an unknown")
+
+        message = _("Error processing drive %s.\n"
+                    "It seems that %s is part of %s Volume Group. "
+                    "Or has inconsistent LVM metadata. "
+                    "You can reinitialize %s, loosing all data or ignore "
+                    "it, preserving its contents.") % (pv_name, pv_name,
+                            message_part, pv_name)
+
+        rc = intf.messageWindow(_("Warning"),
+                message,
+                type="custom",
+                custom_buttons = [ _("_Ignore drive"),
+                                   _("_Re-initialize drive") ],
+                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.
 
@@ -1168,12 +1197,52 @@ class DeviceTree(object):
                 try:
                     vg_name = udev_device_get_vg_name(info)
                 except KeyError:
-                    # no vg name means no vg -- we're done with this pv
+                    # This means either there are valid PVs with no VG.  Or,
+                    # leftover PVs from an incomplete VG.
+                    if not lvm.pvstatus_ok(device.path):
+                        if questionClobberInconsistengVG(intf = self.intf,
+                                pv_name = device.path):
+                            lvm.pvremove(device.path)
+                            # Give the device the a default format
+                            for arg in ["vgName", "vgUuid", "peStart"]:
+                                if kwargs.has_key(arg):
+                                    del kwargs[arg]
+                            device.format = formats.getFormat(*[""], **kwargs)
+
+                        else:
+                            self.ignoredDisks.append(device.name)
                     return
 
+
                 vg_device = self.getDeviceByName(vg_name)
                 if vg_device:
                     vg_device._addDevice(device)
+
+                elif not lvm.pvstatus_ok(device.path):
+                    if questionClobberInconsistengVG(intf = self.intf,
+                            pv_name = device.path,
+                            vg_name = vg_name):
+                        # For some reason there is a failure possibility here
+                        # if the lvm commands dont work, just zero the device.
+                        try:
+                            lvm.vgreduce(vg_name, [], rm=True) #with --removemissing
+                            lvm.vgremove(vg_name) # 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
+                        for arg in ["vgName", "vgUuid", "peStart"]:
+                            if kwargs.has_key(arg):
+                                del kwargs[arg]
+                        device.format = formats.getFormat(*[""], **kwargs)
+
+                    else:
+                        self.ignoredDisks.append(device.name)
+
+                    return
+
                 else:
                     try:
                         vg_uuid = udev_device_get_vg_uuid(info)
-- 
1.6.0.6

_______________________________________________
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