[PATCH] Handle system crappyness.

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

 



* storage/__init__.py (createSuggestedVGName): Take into account the new
  lvm black list.

* storage/devicelibs/lvm.py (blacklistVG): New function, add a VG to a
  the black list.
* storage/devicelibs/lvm.py (vgreduce): introduces a new argument to the
  function.  rm means use the lvm --removemissing option.

* storage/devices.py (LVMVolumeGroupDevice.complete): New function to
  evaluate if VG is consistent.
* storage/devices.py (LVMLogicalVolumeDevice.complete): Likewise for
  LVs.

* storage/devicetree.py (_handleInconsistencies): New function intended to
  catch all unwanted behavior from the system before continuing.
* storage/devicetree.py (questionReinitILVM): New function intended
  to ask the user what to do in case we find inconsistent LVM metadata.
---
 iw/partition_gui.py         |    2 +-
 storage/__init__.py         |    6 ++-
 storage/devicelibs/lvm.py   |   27 +++++++---
 storage/devices.py          |   24 +++++++-
 storage/devicetree.py       |  124 ++++++++++++++++++++++++++++++++++++++++++-
 storage/formats/__init__.py |    3 +
 storage/formats/lvmpv.py    |    6 ++-
 7 files changed, 176 insertions(+), 16 deletions(-)

diff --git a/iw/partition_gui.py b/iw/partition_gui.py
index 0b52a70..6ce1b11 100644
--- a/iw/partition_gui.py
+++ b/iw/partition_gui.py
@@ -819,7 +819,7 @@ class PartitionWindow(InstallWindow):
                 partName = part.getDeviceNodeName().split("/")[-1]
                 device = self.storage.devicetree.getDeviceByName(partName)
                 if not device and not part.type & parted.PARTITION_FREESPACE:
-                    raise RuntimeError("can't find partition %s in device"
+                    log.debug("can't find partition %s in device"
                                        " tree" % partName)
 
                 # ignore the tiny < 1 MB partitions (#119479)
diff --git a/storage/__init__.py b/storage/__init__.py
index 7b7ab5c..6f181d3 100644
--- a/storage/__init__.py
+++ b/storage/__init__.py
@@ -632,13 +632,15 @@ class Storage(object):
         else:
             vgtemplate = "VolGroup"
 
-        if vgtemplate not in vgnames:
+        if vgtemplate not in vgnames and \
+                vgtemplate not in lvm.lvm_vg_blacklist:
             return vgtemplate
         else:
             i = 0
             while 1:
                 tmpname = "%s%02d" % (vgtemplate, i,)
-                if not tmpname in vgnames:
+                if not tmpname in vgnames and \
+                        tmpname not in lvm.lvm_vg_blacklist:
                     break
 
                 i += 1
diff --git a/storage/devicelibs/lvm.py b/storage/devicelibs/lvm.py
index 8b755a4..aa93071 100644
--- a/storage/devicelibs/lvm.py
+++ b/storage/devicelibs/lvm.py
@@ -73,7 +73,7 @@ def _composeConfig():
 
     if len(rejects) > 0:
         for i in range(len(rejects)):
-            filter_string = filter_string + ("\"r|%s|\", " % rejects[i])
+            filter_string = filter_string + ("\"r|%s|\"," % rejects[i])
 
 
     filter_string = " filter=[%s] " % filter_string.strip(",")
@@ -86,7 +86,7 @@ def _composeConfig():
     # devices_string can have (inside the brackets) "dir", "scan",
     # "preferred_names", "filter", "cache_dir", "write_cache_state",
     # "types", "sysfs_scan", "md_component_detection".  see man lvm.conf.
-    devices_string = " devices { %s } " % (filter_string) # strings can be added
+    devices_string = " devices {%s} " % (filter_string) # strings can be added
     config_string = devices_string # more strings can be added.
     config_args = ["--config", config_string]
 
@@ -99,6 +99,12 @@ def lvm_cc_addFilterRejectRegexp(regexp):
     _composeConfig()
 # End config_args handling code.
 
+# Names that should not be used int the creation of VGs
+lvm_vg_blacklist = []
+def blacklistVG(name):
+    global lvm_vg_blacklist
+    lvm_vg_blacklist.append(name)
+
 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.
@@ -283,11 +289,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/devices.py b/storage/devices.py
index 1a52c71..62bc804 100644
--- a/storage/devices.py
+++ b/storage/devices.py
@@ -1633,9 +1633,15 @@ class LVMVolumeGroupDevice(DMDevice):
 
         self.teardown()
 
-        lvm.vgremove(self.name)
-        self.notifyKernel()
-        self.exists = False
+        # this sometimes fails for some reason.
+        try:
+            lvm.vgreduce(self.name, [], rm=True)
+            lvm.vgremove(self.name)
+        except lvm.LVMErorr:
+            raise DeviceError("Could not completely remove VG %s" % self.name)
+        finally:
+            self.notifyKernel()
+            self.exists = False
 
     def reduce(self, pv_list):
         """ Remove the listed PVs from the VG. """
@@ -1764,6 +1770,13 @@ class LVMVolumeGroupDevice(DMDevice):
         """ A list of this VG's LVs """
         return self._lvs[:]     # we don't want folks changing our list
 
+    @property
+    def complete(self):
+        """Check if the vg has all its pvs in the system
+        Return True if complete.
+        """
+        return len(self.pvs) == self.pvCount or not self.exists
+
 
 class LVMLogicalVolumeDevice(DMDevice):
     """ An LVM Logical Volume """
@@ -1863,6 +1876,11 @@ class LVMLogicalVolumeDevice(DMDevice):
         """ The LV's name (not including VG name). """
         return self._name
 
+    @property
+    def complete(self):
+        """ Test if vg exits and if it has all pvs. """
+        return self.vg.complete
+
     def setup(self, intf=None):
         """ Open, or set up, a device. """
         log_method_call(self, self.name, status=self.status)
diff --git a/storage/devicetree.py b/storage/devicetree.py
index 2b997b5..3431cac 100644
--- a/storage/devicetree.py
+++ b/storage/devicetree.py
@@ -136,6 +136,36 @@ def questionInitializeDisk(intf=None, name=None):
             retVal = True
     return retVal
 
+def questionReinitILVM(intf=None, pv_names=None, lv_name=None, vg_name=None):
+    retVal = False # The less destructive default
+    if not intf or not pv_names or (lv_name is None and vg_name is None):
+        pass
+    else:
+        if vg_name is not None:
+            message = "%s Volume Group" % vg_name
+        elif lv_name is not None:
+            message = "%s Logical Volume" % lv_name
+
+
+        rc = intf.messageWindow(_("Warning"),
+                  _("Error processing LVM.\n"
+                    "It seems that there is inconsistent LVM data. "
+                    "(%s) make(s) up %s. "
+                    "You can reinitialize all related PVs, which will "
+                    "erase all LVM metadata. Or ignore, which will "
+                    "preserve contents.")
+                    %(str(pv_names), message),
+                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.
 
@@ -652,7 +682,7 @@ class DeviceTree(object):
         log.debug("added %s (%s) to device tree" % (newdev.name,
                                                     newdev.type))
 
-    def _removeDevice(self, dev, force=None):
+    def _removeDevice(self, dev, force=None, moddisk=True):
         """ Remove a device from the tree.
 
             Only leaves may be removed.
@@ -665,7 +695,8 @@ class DeviceTree(object):
             raise ValueError("Cannot remove non-leaf device '%s'" % dev.name)
 
         # if this is a partition we need to remove it from the parted.Disk
-        if isinstance(dev, PartitionDevice) and dev.disk is not None:
+        if moddisk and isinstance(dev, PartitionDevice) and \
+                dev.disk is not None:
             # if this partition hasn't been allocated it could not have
             # a disk attribute
             dev.disk.partedDisk.removePartition(dev.partedPartition)
@@ -1328,12 +1359,96 @@ class DeviceTree(object):
                                                                size=lv_size,
                                                                exists=True)
                             self._addDevice(lv_device)
+
                             try:
                                 lv_device.setup()
                             except DeviceError as e:
                                 log.info("setup of %s failed: %s" 
                                                     % (lv_device.name, e))
 
+    def _handleInconsistencies(self, device):
+        def reinitializeVG(vg):
+            # First we remove VG data
+            try:
+                vg.destroy()
+            except DeviceError:
+                # the pvremoves will finish the job.
+                log.debug("There was an error destroying the VG %s." % vg.name)
+                pass
+
+            # remove VG device from list.
+            self._removeDevice(vg)
+
+            for parent in vg.parents:
+                parent.format.destroy()
+
+                # Give the vg the a default format
+                kwargs = {"uuid": parent.uuid,
+                          "label": parent.diskLabel,
+                          "device": parent.path,
+                          "exists": parent.exists}
+                parent.format = formats.getFormat(*[""], **kwargs)
+
+        if device.type == "lvmvg":
+            paths = []
+            for parent in device.parents:
+                paths.append(parent.path)
+
+            # when zeroMbr is true he wont ask.
+            if not device.complete and (self.zeroMbr or \
+                    questionReinitILVM(intf=self.intf, \
+                        vg_name=device.name, pv_names=paths)):
+                reinitializeVG(device)
+
+            elif not device.complete:
+                # The user chose not to reinitialize.
+                # hopefully this will ignore the vg components too.
+                self._removeDevice(vg)
+                lvm.lvm_cc_addFilterRejectRegexp(vg.name)
+                lvm.blacklistVG(vg.name)
+                for parent in vg.parents:
+                    self._removeDevice(parent, moddisk=False)
+                    lvm.lvm_cc_addFilterRejectRegexp(parent.name)
+
+            return
+
+        elif device.type == "lvmlv":
+            # we might have already fixed this.
+            if device not in self._devices or \
+                    device.name in self._ignoredDisks:
+                return
+
+            paths = []
+            for parent in device.vg.parents:
+                paths.append(parent.path)
+
+            if not device.complete and (self.zeroMbr or \
+                questionReinitILVM(intf=self.intf, \
+                    lv_name=device.name, pv_names=paths)):
+
+                # destroy all lvs.
+                for lv in device.vg.lvs:
+                    lv.destroy()
+                    device.vg._removeLogVol(lv)
+                    self._removeDevice(lv)
+
+                reinitializeVG(device.vg)
+
+            elif not device.complete:
+                # ignore all the lvs.
+                for lv in device.vg.lvs:
+                    self._removeDevice(lv)
+                    lvm.lvm_cc_addFilterRejectRegexp(lv.name)
+                # ignore the vg
+                self._removeDevice(device.vg)
+                lvm.lvm_cc_addFilterRejectRegexp(device.vg.name)
+                lvm.blacklistVG(device.vg.name)
+                # ignore all the pvs
+                for parent in device.vg.parents:
+                    self._removeDevice(parent, moddisk=False)
+                    lvm.lvm_cc_addFilterRejectRegexp(parent.name)
+            return
+
     def populate(self):
         """ Locate all storage devices. """
         # each iteration scans any devices that have appeared since the
@@ -1363,6 +1478,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._handleInconsistencies(leaf)
+
         self.teardownAll()
 
     def teardownAll(self):
diff --git a/storage/formats/__init__.py b/storage/formats/__init__.py
index 3eaeb0f..63d6dac 100644
--- a/storage/formats/__init__.py
+++ b/storage/formats/__init__.py
@@ -253,6 +253,9 @@ class DeviceFormat(object):
             os.lseek(fd, -1024 * 1024, 2)
             os.write(fd, buf)
             os.close(fd)
+        except OSError as e:
+            if e.errno == 28: # No space left in device
+                pass
         except Exception, e:
             log.error("error zeroing out %s: %s" % (self.device, e))
 
diff --git a/storage/formats/lvmpv.py b/storage/formats/lvmpv.py
index cc243eb..c9cbe29 100644
--- a/storage/formats/lvmpv.py
+++ b/storage/formats/lvmpv.py
@@ -106,7 +106,11 @@ class LVMPhysicalVolume(DeviceFormat):
             raise PhysicalVolumeError("device is active")
 
         # FIXME: verify path exists?
-        lvm.pvremove(self.device)
+        try:
+            lvm.pvremove(self.device)
+        except LVMError:
+            DeviceFormat.destroy(self, *args, **kwargs)
+
         self.exists = False
         self.notifyKernel()
 
-- 
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