From 8228a86052546b1da56b856ddade4da431bf7728 Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Thu, 1 Nov 2012 11:07:39 -0500
Subject: [PATCH 11/12] Improve management of complex devices in custom spoke.
 (#865199)

Containers size calculations were not taking into account the size of an
already-defined device while adjusting the size of the same device. This
meant that changing an lv size from 10G to 5G _grew_ the container by 5G
instead of shrinking it by 5G.
---
 pyanaconda/storage/__init__.py     |   48 +++++++++++++++++++++++++++++------
 pyanaconda/ui/gui/spokes/custom.py |   14 +++++++++-
 2 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py
index 259054f..8691bef 100644
--- a/pyanaconda/storage/__init__.py
+++ b/pyanaconda/storage/__init__.py
@@ -1771,7 +1771,8 @@ class Storage(object):
 
         return fstype
 
-    def setContainerMembers(self, container, factory, members=None):
+    def setContainerMembers(self, container, factory, members=None,
+                            device=None):
         """ Set up and return the container's member partitions. """
         if factory.member_list is not None:
             # short-circuit the logic below for partitions
@@ -1793,7 +1794,7 @@ class Storage(object):
         if container:
             log.debug("using container %s with %d devices" % (container.name,
                                 len(self.devicetree.getChildren(container))))
-            container_size = factory.container_size_func(container)
+            container_size = factory.container_size_func(container, device)
             log.debug("raw container size reported as %d" % container_size)
 
         if members:
@@ -1993,7 +1994,7 @@ class Storage(object):
 
         try:
             parents = self.setContainerMembers(container, factory,
-                                               members=members)
+                                               members=members, device=device)
         except PartitioningError as e:
             # If this is a new device, just clean up and get out.
             if device:
@@ -2011,7 +2012,8 @@ class Storage(object):
 
                 try:
                     self.setContainerMembers(container, factory,
-                                             members=members)
+                                             members=members,
+                                             device=device)
                 except StorageError as e:
                     log.error("failed to revert device size: %s" % e)
                     raise ErrorRecoveryFailure("failed to revert container")
@@ -2030,6 +2032,9 @@ class Storage(object):
                 raise
 
             self.createDevice(container)
+        elif container and not container.exists and \
+             hasattr(container, "dataLevel"):
+            container.dataLevel = factory.raid_level
 
         if container:
             parents = [container]
@@ -3148,9 +3153,14 @@ class DeviceFactory(object):
         """ Perform actions required after device creation. """
         pass
 
-    def container_size_func(self, container):
-        """ Return the total used space in the specified container. """
-        return container.size
+    def container_size_func(self, container, device=None):
+        """ Return the total space needed for the specified container. """
+        size = container.size
+        size += self.device_size
+        if device:
+            size -= device.size
+
+        return size
 
     @property
     def device_size(self):
@@ -3219,6 +3229,20 @@ class BTRFSFactory(DeviceFactory):
         kwargs["dataLevel"] = self.raid_level
         return getattr(self.storage, self.new_container_attr)(*args, **kwargs)
 
+    def container_size_func(self, container, device=None):
+        """ Return the total space needed for the specified container. """
+        if container.exists:
+            container_size = container.size
+        else:
+            container_size = sum([s.req_size for s in container.subvolumes])
+
+        if device:
+            size = self.device_size
+        else:
+            size = container_size + self.device_size
+
+        return size
+
     @property
     def device_size(self):
         # until we get/need something better
@@ -3248,8 +3272,14 @@ class LVMFactory(DeviceFactory):
             size_func_kwargs["striped"] = True
         return get_pv_space(self.size, len(self.disks), **size_func_kwargs)
 
-    def container_size_func(self, container):
-        return container.size - container.freeSpace
+    def container_size_func(self, container, device=None):
+        size = sum([p.size for p in container.parents])
+        size -= container.freeSpace
+        size += self.device_size
+        if device:
+            size -= get_pv_space(device.size, len(container.parents))
+
+        return size
 
     def set_device_size(self, container, device=None):
         size = self.size
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index 475e0e4..dfa7b52 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -1089,6 +1089,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
                     selector.props.name = (self._mountpointName(mountpoint) or
                                            selector._device.format.name)
 
+            self._devices = self.__storage.devices
             # update size props of all btrfs devices' selectors
             self._update_btrfs_selectors()
 
@@ -1139,6 +1140,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
                                              device_configuration_error_msg)
                         self.window.show_all()
 
+                    self._devices = self.__storage.devices
+
             log.debug("updating selector size to '%s'"
                        % str(Size(spec="%f MB" % device.size)).upper())
             # update the selector's size property
@@ -1187,6 +1190,9 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             ## FORMATTING
             ##
             encryption_changed = (device != old_device)
+            if encryption_changed:
+                self._devices = self.__storage.devices
+
             fs_type_changed = (fs_type_short != old_fs_type)
             fs_exists = old_device.format.exists
             if encryption_changed or fs_type_changed or fs_exists:
@@ -1706,17 +1712,21 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             device.vg._removeLogVol(device)
             container = device.vg
             device_type = AUTOPART_TYPE_LVM
+            raid_level = None
         elif hasattr(device, "volume"):
             device.volume._removeSubVolume(device.name)
             container = device.volume
             device_type = AUTOPART_TYPE_BTRFS
+            raid_level = container.dataLevel
 
         if container and not container.exists and \
            self.__storage.devicetree.getChildren(container):
             # adjust container to size of remaining devices
             with ui_storage_logger():
-                # TODO: raid
-                factory = self.__storage.getDeviceFactory(device_type, 0)
+                factory = self.__storage.getDeviceFactory(device_type, 0,
+                                                          disks=container.disks,
+                                                          encrypted=container.encrypted,
+                                                          raid_level=raid_level)
                 parents = self.__storage.setContainerMembers(container, factory)
 
         # if this device has parents with no other children, remove them too
-- 
1.7.7.6

