--- storage/devicelibs/lvm.py | 44 ++++++++++++++++++++++++++ storage/devicetree.py | 76 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 1 deletions(-) diff --git a/storage/devicelibs/lvm.py b/storage/devicelibs/lvm.py index 0faee10..28c3f9e 100644 --- a/storage/devicelibs/lvm.py +++ b/storage/devicelibs/lvm.py @@ -171,6 +171,34 @@ def pvinfo(device): return info +def pvcomplete(device): + """ Check validity of lvm structure with Physical Volume device. + + LVM metadata is stored in all the PVs that compose a VG. This means that + there might be "valid" VGs with missing PVs. This function detects this + LVM behavior. + + Returs True if all the PVs are known to LVM and currently present in system. + False otherwise. + """ + # Its better not to filter any devices here. + args = ["pvs"] + \ + ["--noheadings"] + \ + ["-o", "pv_name"] + + rc = iutil.execWithCapture("lvm", args, + stderr = "/dev/tty5") + + rc = rc.strip("\n").split("\n") + # We don't check for error because what we are looking for *is* an error. + # We search for the "unknown device" string that will tell us + # if this PV is part of an incomplete VG. + for name in rc: + if name.strip(" ") == "unknown device": + return False + + return True + def vgcreate(vg_name, pv_list, pe_size): argv = ["vgcreate"] if pe_size: @@ -221,6 +249,22 @@ def vgreduce(vg_name, pv_list): if rc: raise LVMError("vgreduce failed for %s" % vg_name) +def vgreduce_rm(vg_name): + """ Reduce a VG with the --removemissing options. + + We use this when we don't know the PVs that we are to reduce. + """ + # We should not filter this command because we want lvm to consider all pvs + args = ["vgreduce", "--removemissing", vg_name] + rc = iutil.execWithRedirect("lvm", args, + stdout = "/dev/tty5", + stderr = "/dev/tty5", + searchPath=1) + + if rc: + raise LVMError("vgreduce failed for %s" % vg_name) + + def vginfo(vg_name): buf = iutil.execWithCapture("lvm", ["vgs", "--noheadings", "--nosuffix", "--units", "m", "-o", diff --git a/storage/devicetree.py b/storage/devicetree.py index ccc925a..0d469f1 100644 --- a/storage/devicetree.py +++ b/storage/devicetree.py @@ -135,6 +135,34 @@ def questionInitializeDisk(intf=None, name=None): retVal = True return retVal +def questionClobberIncompleteVG(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. " + "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. @@ -1030,16 +1058,62 @@ class DeviceTree(object): self.ignoredDisks.append(device.name) rs.deactivate() elif format.type == "lvmpv": + import pdb; pdb.set_trace() # lookup/create the VG and LVs 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 that there is LVM metadata in device but not + # enough to identify the vg name. + # There is no need to call lvm.pvcomplete as we already know + # that it is incomplete. + if questionClobberIncompleteVG(intf = self.intf, + pv_name = device.path): + try: + lvm.pvremove(device.path) + except: + # We ignore because we expect an certain error. + # LVM complains that it cannot find uuids + # FIXME: This fails if some other error ocurrs. + pass + # Give the device the a default format + for arg in ["vgName", "vgUuid", "peStarg"]: + if kwargs.has_key(arg): + del kwargs[arg] + device.format = formats.getFormat(None) + + else: + self.ignoredDisks.append(device.name) return + vg_device = self.getDeviceByName(vg_name) if vg_device: vg_device._addDevice(device) + + elif not lvm.pvcomplete(device.path): + # PVs usually have VG data, that does not mean that the VG + # is valid. Here, check to see if all the vg components are + # here. If not, give the user the possibility to ignore or + # initialize this device. + if questionClobberIncompleteVG(intf = self.intf, + pv_name = device.path, + vg_name = vg_name): + lvm.vgreduce_rm(vg_name) #reduce with --removemissing + lvm.vgremove(vg_name) # now we can remove + lvm.pvremove(device.path) # finally remove the PV + + # Give the device the a default format + for arg in ["vgName", "vgUuid", "peStarg"]: + if kwargs.has_key(arg): + del kwargs[arg] + device.format = formats.getFormat(None) + + 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