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