[PATCH 4/8] Automatic partitioning support for whole-disk formatting.

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

 



When using the entire disk, whole-disk formats are replaced with a
new disklabel. When replacing existing linux installations, linux-
native whole-disk formats are replaced with a new disklabel. Disks
containing whole-disk formatting are not offered as bootloader
installation targets.
---
 iw/autopart_type.py            |   85 ++++++++++++++++++++++++++++++++++------
 iw/partition_ui_helpers_gui.py |    9 ++--
 storage/partitioning.py        |   80 ++++++++++++++++++++++++--------------
 3 files changed, 129 insertions(+), 45 deletions(-)

diff --git a/iw/autopart_type.py b/iw/autopart_type.py
index fc0e4be..c0dfcd8 100644
--- a/iw/autopart_type.py
+++ b/iw/autopart_type.py
@@ -34,6 +34,8 @@ import network
 from storage import iscsi
 from storage import fcoe
 from storage.deviceaction import *
+from storage.partitioning import shouldClear
+import isys
 
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
@@ -211,6 +213,16 @@ class PartitionTypeWindow(InstallWindow):
                 if not rc:
                     raise gui.StayOnScreen
             
+            # our list of bootloader drives may contain some drives not in
+            # the bootloader's list because of unpartitioned drives that
+            # were selected for clearing and will therefore be partitioned
+            # by the time we install the bootloader
+            for drive in self.bl_drivelist:
+                if drive.name not in self.anaconda.id.bootloader.drivelist:
+                    self.anaconda.id.bootloader.drivelist.append(drive.name)
+            self.anaconda.id.bootloader.drivelist.sort(isys.compareDrives)
+
+            # put the chosen boot device at the front of the list
             self.anaconda.id.bootloader.drivelist.remove(defboot)
             self.anaconda.id.bootloader.drivelist.insert(0, defboot)            
 
@@ -251,6 +263,58 @@ class PartitionTypeWindow(InstallWindow):
             self.xml.get_widget("bootDriveCombo").set_sensitive(True)
             self.xml.get_widget("encryptButton").set_sensitive(True)
 
+        self.updateDriveLists()
+
+    def updateDriveLists(self):
+        active = self.combo.get_active_iter()
+        clearpart = self.combo.get_model().get_value(active, 1)
+
+        # modify self.bootcombo and self.drivelist to reflect the current
+        # projected set of partitioned disks
+        disallowed = [self.anaconda.updateSrc]
+        disks = self.storage.disks
+        partitioned = self.storage.partitioned
+        if clearpart not in [CLEARPART_TYPE_ALL, -1]:
+            # only disks that are already partitioned or whose whole-disk
+            # formatting is "linux native" should be allowed
+            for disk in disks:
+                if disk not in partitioned and not shouldClear(disk, clearpart):
+                    disallowed.append(disk.name)
+        else:
+            # for CLEARPART_TYPE_ALL and custom layouts all disks should be
+            # allowed since we'll put a disklabel on any unlabeled disks we
+            # clear
+            disks = self.storage.disks
+
+        createAllowedDrivesStore(self.storage.disks,
+                                 self.storage.clearPartDisks,
+                                 self.drivelist,
+                                 disallowDrives=disallowed)
+
+        # Figure out which disks are selected for populating the bootloader
+        # combo. Also deselect unsuitable disks and ensure they cannot be
+        # selected.
+        selections = {}
+        row_iter = iter(self.drivelist.get_model())
+        for row in row_iter:
+            (selected, drive, size, desc, sensitive) = tuple(row)
+            selections[drive] = selected
+
+            if self.drivelist.sensitivity_col is not None:
+                row[self.drivelist.sensitivity_col] = drive not in disallowed
+
+            if drive in disallowed:
+                row[0] = False
+
+        # bootloader is unusual in that we only want to look at disks that
+        # have disklabels -- no partitioned md or unpartitioned disks
+        self.bl_drivelist = []
+        for disk in self.storage.disks:
+            if selections[disk.name] and disk.name not in disallowed:
+                self.bl_drivelist.append(disk)
+        self.bl_drivelist.sort(cmp=isys.compareDrives, key=lambda d: d.name)
+        self._fillBootStore()
+
     def addIscsiDrive(self):
         if not network.hasActiveNetDev():
             net = NetworkConfigurator(self.anaconda.id.network)
@@ -487,24 +551,22 @@ class PartitionTypeWindow(InstallWindow):
             w = self.intf.waitWindow(_("Rescanning disks"),
                                      _("Rescanning disks"))
             self.storage.reset()
-            createAllowedDrivesStore(self.storage.disks,
-                                     self.storage.clearPartDisks,
-                                     self.drivelist,
-                                     disallowDrives=[self.anaconda.updateSrc])
-            self._fillBootStore()
+            self.updateDriveLists()
             w.pop()
 
     def _fillBootStore(self):
+        # this isn't strictly necessary, but it can't hurt -- especially if
+        # the user has added drives via iscsi or fcoe or similar
         self.anaconda.id.bootloader.updateDriveList()
+
         bootstore = self.bootcombo.get_model()
         bootstore.clear()
-        if len(self.anaconda.id.bootloader.drivelist) > 0:
-            defaultBoot = self.anaconda.id.bootloader.drivelist[0]
+        if len(self.bl_drivelist) > 0:
+            defaultBoot = self.bl_drivelist[0].name
         else:
             defaultBoot = None
-        for disk in self.storage.disks:
-            if disk.name not in self.anaconda.id.bootloader.drivelist:
-                continue
+
+        for disk in self.bl_drivelist:
             dispstr = "%s %8.0f MB %s" %(disk.name, disk.size, disk.description)
             i = bootstore.append(None)
             bootstore[i] = (dispstr, disk.name)
@@ -574,7 +636,7 @@ class PartitionTypeWindow(InstallWindow):
 
         bootstore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
         self.bootcombo.set_model(bootstore)
-        self._fillBootStore()
+        self.updateDriveLists()
 
         self.prevrev = None
         self.review = not self.dispatch.stepInSkipList("partition")
@@ -604,5 +666,4 @@ class PartitionTypeWindow(InstallWindow):
         sigs = { "on_partitionTypeCombo_changed": self.comboChanged,
                  "on_addButton_clicked": self.addDrive }
         self.xml.signal_autoconnect(sigs)
-
         return vbox
diff --git a/iw/partition_ui_helpers_gui.py b/iw/partition_ui_helpers_gui.py
index ee6d0ac..2f05a6e 100644
--- a/iw/partition_ui_helpers_gui.py
+++ b/iw/partition_ui_helpers_gui.py
@@ -166,10 +166,11 @@ def createAllowedDrivesStore(disks, reqdrives, drivelist, selectDrives=True,
 
 def createAllowedDrivesList(disks, reqdrives, selectDrives=True, disallowDrives=[]):
     store = gtk.TreeStore(gobject.TYPE_BOOLEAN,
-			  gobject.TYPE_STRING,
-			  gobject.TYPE_STRING,
-			  gobject.TYPE_STRING)
-    drivelist = WideCheckList(3, store)
+                          gobject.TYPE_STRING,
+                          gobject.TYPE_STRING,
+                          gobject.TYPE_STRING,
+                          gobject.TYPE_BOOLEAN)
+    drivelist = WideCheckList(3, store, sensitivity=True)
     createAllowedDrivesStore(disks, reqdrives, drivelist, selectDrives=selectDrives,
                              disallowDrives=disallowDrives)
 
diff --git a/storage/partitioning.py b/storage/partitioning.py
index 1bb1567..101f6d4 100644
--- a/storage/partitioning.py
+++ b/storage/partitioning.py
@@ -32,6 +32,7 @@ from constants import *
 from errors import *
 from deviceaction import *
 from devices import PartitionDevice, LUKSDevice, devicePathToName
+from formats import getFormat
 
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
@@ -276,37 +277,40 @@ def doAutoPartition(anaconda):
         anaconda.id.storage.reset()
         return DISPATCH_BACK
 
-def shouldClear(part, clearPartType, clearPartDisks=None):
-    if not isinstance(part, PartitionDevice):
+def shouldClear(device, clearPartType, clearPartDisks=None):
+    if clearPartType not in [CLEARPART_TYPE_LINUX, CLEARPART_TYPE_ALL]:
         return False
 
-    if not clearPartType in [CLEARPART_TYPE_LINUX, CLEARPART_TYPE_ALL]:
-        return False
-
-    # Never clear the special first partition on a Mac disk label, as that
-    # holds the partition table itself.
-    if part.disk.format.partedDisk.type == "mac" and \
-       part.partedPartition.number == 1 and \
-       part.partedPartition.name == "Apple":
-        return False
-
-    # If we got a list of disks to clear, make sure this one's on it
-    if clearPartDisks and part.disk.name not in clearPartDisks:
-        return False
-
-    # Don't clear partitions holding install media.
-    if part.protected:
-        return False
-
-    # We don't want to fool with extended partitions, freespace, &c
-    if part.partType not in [parted.PARTITION_NORMAL, parted.PARTITION_LOGICAL]:
-        return False
-
-    if clearPartType == CLEARPART_TYPE_LINUX and \
-       not part.format.linuxNative and \
-       not part.getFlag(parted.PARTITION_LVM) and \
-       not part.getFlag(parted.PARTITION_RAID) and \
-       not part.getFlag(parted.PARTITION_SWAP):
+    if isinstance(device, PartitionDevice):
+        # Never clear the special first partition on a Mac disk label, as that
+        # holds the partition table itself.
+        if device.disk.format.partedDisk.type == "mac" and \
+           device.partedPartition.number == 1 and \
+           device.partedPartition.name == "Apple":
+            return False
+
+        # If we got a list of disks to clear, make sure this one's on it
+        if clearPartDisks and device.disk.name not in clearPartDisks:
+            return False
+
+        # We don't want to fool with extended partitions, freespace, &c
+        if device.partType not in [parted.PARTITION_NORMAL,
+                                   parted.PARTITION_LOGICAL]:
+            return False
+
+        if clearPartType == CLEARPART_TYPE_LINUX and \
+           not device.format.linuxNative and \
+           not device.getFlag(parted.PARTITION_LVM) and \
+           not device.getFlag(parted.PARTITION_RAID) and \
+           not device.getFlag(parted.PARTITION_SWAP):
+            return False
+    elif device.isDisk and not device.partitioned:
+        if clearPartType == CLEARPART_TYPE_LINUX and \
+           not device.format.linuxNative:
+            return False
+
+    # Don't clear devices holding install media.
+    if device.protected:
         return False
 
     # TODO: do platform-specific checks on ia64, pSeries, iSeries, mac
@@ -377,6 +381,24 @@ def removeEmptyExtendedPartitions(storage):
             storage.destroyDevice(extended)
             #disk.partedDisk.removePartition(extended.partedPartition)
 
+    for disk in [d for d in storage.disks if d not in storage.partitioned]:
+        # clear any whole-disk formats that need clearing
+        if shouldClear(disk, storage.clearPartType, storage.clearPartDisks):
+            log.debug("clearing %s" % disk.name)
+            devices = storage.deviceDeps(disk)
+            while devices:
+                log.debug("devices to remove: %s" % ([d.name for d in devices],))
+                leaves = [d for d in devices if d.isleaf]
+                log.debug("leaves to remove: %s" % ([d.name for d in leaves],))
+                for leaf in leaves:
+                    storage.destroyDevice(leaf)
+                    devices.remove(leaf)
+
+            destroy_action = ActionDestroyFormat(disk)
+            newLabel = getFormat("disklabel", device=disk.path)
+            create_action = ActionCreateFormat(disk, format=newLabel)
+            storage.devicetree.registerAction(destroy_action)
+            storage.devicetree.registerAction(create_action)
 
 def partitionCompare(part1, part2):
     """ More specifically defined partitions come first.
-- 
1.6.5.2

_______________________________________________
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