[PATCH 4/4] Try to add new device to an existing container if disks are full.

David Lehman dlehman at redhat.com
Wed Nov 21 19:44:40 UTC 2012


VGs have a freeSpace attribute while btrfs vols do not. Choose the
existing container with the most free space or the most total space.
---
 pyanaconda/storage/__init__.py     |   17 +++++++++----
 pyanaconda/ui/gui/spokes/custom.py |   47 +++++++++++++++++++++++++++++------
 2 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py
index 07f2cce..32ca2cb 100644
--- a/pyanaconda/storage/__init__.py
+++ b/pyanaconda/storage/__init__.py
@@ -1992,15 +1992,15 @@ class Storage(object):
                     self, size, [d.name for d in disks], raid_level))
         return factory_class(self, size, disks, raid_level, encrypted)
 
-    def getContainer(self, factory, device=None, container_name=None):
+    def getContainer(self, factory, device=None, name=None, existing=False):
         # XXX would it be useful to implement this as a series of fallbacks
         #     instead of mutually exclusive branches?
         container = None
-        if container_name:
-            container = self.devicetree.getDeviceByName(container_name)
+        if name:
+            container = self.devicetree.getDeviceByName(name)
             if container and container not in factory.container_list:
                 log.debug("specified container name %s is wrong type (%s)"
-                            % (container_name, container.type))
+                            % (name, container.type))
                 container = None
         elif device:
             if hasattr(device, "vg"):
@@ -2012,6 +2012,13 @@ class Storage(object):
             if containers:
                 container = containers[0]
 
+        if container is None and existing:
+            containers = [c for c in factory.container_list if c.exists]
+            if containers:
+                containers.sort(key=lambda c: getattr(c, "freeSpace", c.size),
+                                reverse=True)
+                container = containers[0]
+
         return container
 
     def __cleanUpMemberDevices(self, members, container=None):
@@ -2108,7 +2115,7 @@ class Storage(object):
 
 
         container = self.getContainer(factory, device=device,
-                                      container_name=container_name)
+                                      name=container_name)
 
         # TODO: striping, mirroring, &c
         # TODO: non-partition members (pv-on-md)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index c52789c..ee70c14 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -24,7 +24,6 @@
 # - Add a way for users to specify the names of md, lv, subvol devices.
 # - We should either remove boot disk selection from the cart we show from here
 #   or re-partition when it gets changed to make a best-effort at keeping up.
-# - Add new LVs to existing VG if creating a new VG fails outright.
 # - Deleting an LV is not reflected in available space in the bottom left.
 #   - this is only true for preexisting LVs
 # - Device descriptions, suggested sizes, etc. should be moved out into a support file.
@@ -35,6 +34,7 @@
 # - If you click to add a mountpoint while editing a device the lightbox
 #   screenshot is taken prior to the ui update so the background shows the old
 #   size and free space while you're deciding on a size for the new device.
+# - DeviceTree.populate brings back deleted devices when unlocking LUKS.
 
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
@@ -122,6 +122,11 @@ DEVICE_TEXT_PARTITION = N_("Standard Partition")
 DEVICE_TEXT_BTRFS = N_("BTRFS")
 DEVICE_TEXT_DISK = N_("Disk")
 
+device_text_map = {DEVICE_TYPE_LVM: DEVICE_TEXT_LVM,
+                   DEVICE_TYPE_MD: DEVICE_TEXT_MD,
+                   DEVICE_TYPE_PARTITION: DEVICE_TEXT_PARTITION,
+                   DEVICE_TYPE_BTRFS: DEVICE_TEXT_BTRFS}
+
 options_page_dict = {DEVICE_TYPE_LVM: 0,
                      DEVICE_TYPE_MD: 1,
                      DEVICE_TYPE_BTRFS: 2}
@@ -1005,7 +1010,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             old_container = self.__storage.getContainer(factory,
                                                         device=device)
             container = self.__storage.getContainer(factory,
-                                                    container_name=self._device_container_name)
+                                                    name=self._device_container_name)
             if self._device_container_name != old_container.name:
                 old_container_name = old_container.name
                 changed_container = True
@@ -1713,12 +1718,13 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             encrypted = False
 
         disks = self._clearpartDevices
+        size = float(size.convertTo(spec="mb"))
         self.clear_errors()
 
         with ui_storage_logger():
             try:
                 self.__storage.newDevice(device_type,
-                                         size=float(size.convertTo(spec="mb")),
+                                         size=size,
                                          fstype=fstype,
                                          mountpoint=mountpoint,
                                          encrypted=encrypted,
@@ -1732,11 +1738,36 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
                 self._reset_storage()
             except StorageError as e:
                 log.error("newDevice failed: %s" % e)
-                self._error = e
-                self.window.set_info(Gtk.MessageType.ERROR,
-                                     _("Failed to add new device. Click for "
-                                       "details."))
-                self.window.show_all()
+                log.debug("trying to find an existing container to use")
+                factory = self.__storage.getDeviceFactory(device_type, size)
+                container = self.__storage.getContainer(factory, existing=True)
+                log.debug("found container %s" % container)
+                if container:
+                    try:
+                        self.__storage.newDevice(device_type,
+                                                 size=size,
+                                                 fstype=fstype,
+                                                 mountpoint=mountpoint,
+                                                 encrypted=encrypted,
+                                                 disks=disks,
+                                                 container_name=container.name)
+                    except StorageError as e2:
+                        log.error("newDevice failed w/ old container: %s" % e2)
+                    else:
+                        type_str = device_text_map[device_type]
+                        self.window.set_info(Gtk.MessageType.INFO,
+                                             _("Added new %s to existing "
+                                               "container %s.")
+                                             % (type_str, container.name))
+                        self.window.show_all()
+                        e = None
+
+                if e:
+                    self._error = e
+                    self.window.set_info(Gtk.MessageType.ERROR,
+                                         _("Failed to add new device. Click for "
+                                           "details."))
+                    self.window.show_all()
 
         self._devices = self.__storage.devices
         self._do_refresh()
-- 
1.7.7.6



More information about the anaconda-patches mailing list