[PATCH 4/5] Add container size policies for unlimited growth and fixed size.

David Lehman dlehman at redhat.com
Thu May 2 17:58:03 UTC 2013


---
 blivet/devicefactory.py | 131 ++++++++++++++++++++++++++++++++++--------------
 blivet/devices.py       |   6 ++-
 2 files changed, 99 insertions(+), 38 deletions(-)

diff --git a/blivet/devicefactory.py b/blivet/devicefactory.py
index edca449..938a48c 100644
--- a/blivet/devicefactory.py
+++ b/blivet/devicefactory.py
@@ -40,6 +40,9 @@ _ = lambda x: gettext.ldgettext("blivet", x)
 import logging
 log = logging.getLogger("blivet")
 
+SIZE_POLICY_MAX = -1
+SIZE_POLICY_AUTO = 0
+
 DEVICE_TYPE_LVM = 0
 DEVICE_TYPE_MD = 1
 DEVICE_TYPE_PARTITION = 2
@@ -211,7 +214,7 @@ class DeviceFactory(object):
     def __init__(self, storage, size, disks, fstype=None, mountpoint=None,
                  label=None, raid_level=None, encrypted=False,
                  container_encrypted=False, container_name=None,
-                 container_raid_level=None,
+                 container_raid_level=None, container_size=SIZE_POLICY_AUTO,
                  name=None, device=None):
         """ Create a new DeviceFactory instance.
 
@@ -228,16 +231,16 @@ class DeviceFactory(object):
                 label               filesystem label text
 
                 raid_level          raid level string, eg: "raid1"
-                container_raid_level
-
                 encrypted           whether to encrypt (boolean)
-                container_encrypted whether to encrypt the entire container
-
-                container_name      name of requested container
                 name                name of requested device
 
                 device              an already-defined but non-existent device
                                     to adjust instead of creating a new device
+
+                container_name      name of requested container
+                container_raid_level
+                container_encrypted whether to encrypt the entire container
+                container_size      requested container size
         """
         self.storage = storage          # a Blivet instance
         self.size = size                # the requested size for this device
@@ -259,6 +262,8 @@ class DeviceFactory(object):
         self.container_name = container_name
         self.device_name = name
 
+        self.container_size = container_size
+
         self.container = None
         self.device = device
 
@@ -278,20 +283,30 @@ class DeviceFactory(object):
     #
     # methods related to device size and disk space requirements
     #
+    def _get_free_disk_space(self):
+        free_info = self.storage.getFreeSpace(disks=self.disks)
+        free = sum(d[0] for d in free_info.values())
+        return int(free.convertTo(spec="mb"))
+
     def _handle_no_size(self):
         """ Set device size so that it grows to the largest size possible. """
         if self.size is not None:
             return
 
-        free_info = self.storage.getFreeSpace(disks=self.disks)
-        free = sum(d[0] for d in free_info.values())
-        self.size = int(free.convertTo(spec="mb"))
+        self.size = self._get_free_disk_space()
 
         if self.device:
             self.size += self.device.size
 
+        if self.container_size > 0:
+            self.size = min(self.container_size, self.size)
+
     def _get_total_space(self):
-        """ Return the total space need for this factory's device/container. """
+        """ Return the total space need for this factory's device/container.
+
+            This is used for the size argument to the child factory constructor
+            and also to construct the size set in PartitionSetFactory.configure.
+        """
         size = self._get_device_space()
         if self.container:
             size += container.size
@@ -648,8 +663,12 @@ class DeviceFactory(object):
         if self.child_factory or not self.child_factory_class:
             return
 
-        factory = self.child_factory_class(*self._get_child_factory_args(),
-                                           **self._get_child_factory_kwargs())
+        args = self._get_child_factory_args()
+        kwargs = self._get_child_factory_kwargs()
+        log.debug("child factory class: %s" % self.child_factory_class)
+        log.debug("child factory args: %s" % args)
+        log.debug("child factory kwargs: %s" % kwargs)
+        factory = self.child_factory_class(*args, **kwargs)
         self.child_factory = factory
         factory.parent_factory = self
 
@@ -714,6 +733,10 @@ class DeviceFactory(object):
         else:
             self._create_container()
 
+        if self.container and hasattr(self.container, "size_policy") and \
+           not self.container.exists:
+            self.container.size_policy = self.container_size
+
         # Configure this factory's leaf device, eg, for LVMFactory: the LV.
         if self.device:
             self._reconfigure_device()
@@ -859,6 +882,10 @@ class PartitionSetFactory(PartitionFactory):
         container = self.parent_factory.container
         log.debug("parent factory container: %s" % self.parent_factory.container)
         if container:
+            if container.exists:
+                log.info("parent factory container exists -- nothing to do")
+                return
+
             # update our device list from the parent factory's container members
             members = container.parents[:]
             self._devices = members
@@ -1021,7 +1048,8 @@ class LVMFactory(DeviceFactory):
         if self.size is not None:
             return
 
-        if self.container and self.container.exists:
+        if self.container and (self.container.exists or
+                               self.container_size > 0):
             self.size = self.container.freeSpace
 
             if self.device:
@@ -1067,17 +1095,38 @@ class LVMFactory(DeviceFactory):
     def _get_total_space(self):
         """ Total disk space requirement for this device and its container. """
         size = 0
-        if self.container:
-            size += sum([p.size for p in self.container.parents])
-            size -= self.container.freeSpace
-
-        size += self._get_device_space()
-        if self.device:
-            # The member count here uses the container's current member set
-            # since that's the basis for the current device's disk space usage.
-            size -= get_pv_space(self.device.size,
-                                 len(self.container.parents),
-                                 **self.size_func_kwargs)
+        if self.container and self.container.exists:
+            return size
+
+        if self.container_size == 0:
+            # automatic container size management
+            if self.container:
+                size += sum([p.size for p in self.container.parents])
+                size -= self.container.freeSpace
+        elif self.container_size == SIZE_POLICY_MAX:
+            # grow the container as large as possible
+            if self.container:
+                size += sum(p.size for p in self.container.parents)
+                log.debug("size bumped to %d to include container parents" % size)
+
+            size += self._get_free_disk_space()
+            log.debug("size bumped to %d to include free disk space" % size)
+        else:
+            # container_size is a request for a fixed size for the container
+            size += get_pv_space(self.container_size, len(self.disks))
+
+        # this does not apply if a specific container size was requested
+        if self.container_size in [SIZE_POLICY_AUTO, SIZE_POLICY_MAX]:
+            size += self._get_device_space()
+            log.debug("size bumped to %d to include new device space" % size)
+            if self.device and self.container_size == SIZE_POLICY_AUTO:
+                # The member count here uses the container's current member set
+                # since that's the basis for the current device's disk space
+                # usage.
+                size -= get_pv_space(self.device.size,
+                                     len(self.container.parents),
+                                     **self.size_func_kwargs)
+                log.debug("size cut to %d to omit old device space" % size)
 
         return size
 
@@ -1127,12 +1176,12 @@ class MDFactory(DeviceFactory):
     size_set_class = SameSizeSet
 
     def _get_device_space(self):
-        return self._get_total_space()
-
-    def _get_total_space(self):
         return get_member_space(self.size, len(self._get_member_devices()),
                                 level=self.raid_level)
 
+    def _get_total_space(self):
+        return self._get_device_space()
+
     def _set_raid_level(self):
         # TODO: write MDRaidArrayDevice.setRAIDLevel
         # make sure the member count is adequate for the new level
@@ -1220,18 +1269,26 @@ class BTRFSFactory(DeviceFactory):
 
     def _get_total_space(self):
         """ Return the total space needed for the specified container. """
-        if not self.container:
-            container_size = 0
-        elif self.container.exists:
-            container_size = self.container.size
-        else:
-            container_size = sum(s.req_size for s in self.container.subvolumes)
+        size = 0
+        if self.container and self.container.exists:
+            return size
 
-        size = self._get_device_space()
+        if self.container_size == SIZE_POLICY_AUTO:
+            # automatic
+            if self.container and not self.device:
+                # For new subvols the size is in addition to the volume's size.
+                size += sum(s.req_size for s in self.container.subvolumes)
 
-        if not self.device:
-            # For new subvols the size is in addition to the volume's size.
-            size += container_size
+            size += self._get_device_space()
+        elif self.container_size == SIZE_POLICY_MAX:
+            # as large as possible
+            if self.container:
+                size += self.container.size
+
+            size += self._get_free_disk_space()
+        else:
+            # fixed-size request
+            size = self.container_size
 
         return size
 
diff --git a/blivet/devices.py b/blivet/devices.py
index aa96d3d..450dac0 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -1,7 +1,7 @@
 # devices.py
 # Device classes for anaconda's storage configuration module.
 # 
-# Copyright (C) 2009  Red Hat, Inc.
+# Copyright (C) 2009-2013  Red Hat, Inc.
 #
 # This copyrighted material is made available to anyone wishing to use,
 # modify, copy, or redistribute it subject to the terms and conditions of
@@ -2022,6 +2022,9 @@ class LVMVolumeGroupDevice(DMDevice):
         # They still occupy space in the VG.
         self.voriginSnapshots = {}
 
+        # >0 is fixed
+        self.size_policy = self.size
+
     def __repr__(self):
         s = DMDevice.__repr__(self)
         s += ("  free = %(free)s  PE Size = %(peSize)s  PE Count = %(peCount)s\n"
@@ -3988,6 +3991,7 @@ class BTRFSVolumeDevice(BTRFSDevice):
         super(BTRFSVolumeDevice, self).__init__(*args, **kwargs)
 
         self.subvolumes = []
+        self.size_policy = self.size
 
         for parent in self.parents:
             if parent.format.type != "btrfs":
-- 
1.8.1.4



More information about the anaconda-patches mailing list