Joel Granados wrote:
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.
+ """
Aren't you cleaning 200KB instead of 200MB?
+ 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
|