[PATCH 03/11] Add PartitionFactory class so partitions don't need a separate code path.
David Lehman
dlehman at redhat.com
Thu Aug 16 21:48:42 UTC 2012
---
pyanaconda/storage/__init__.py | 117 ++++++++++++++++++++----------------
pyanaconda/storage/partitioning.py | 9 +++
2 files changed, 73 insertions(+), 53 deletions(-)
diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py
index fdf97d6..702337b 100644
--- a/pyanaconda/storage/__init__.py
+++ b/pyanaconda/storage/__init__.py
@@ -1823,6 +1823,14 @@ class Storage(object):
return fstype
def setContainerMembers(self, container, factory):
+ """ Set up and return the container's member partitions. """
+ if factory.member_list is not None:
+ # short-circuit the logic below for partitions
+ return factory.member_list
+
+ if factory.container_size_func is None:
+ return []
+
# set up member devices
container_size = 0
if container:
@@ -1851,10 +1859,6 @@ class Storage(object):
member.req_base_size = PartitionDevice.defaultSize
member.req_size = member.req_base_size
member.req_grow = True
-
- for ss in self.size_sets[:]:
- if member in ss.devices:
- self.size_sets.remove(ss)
else:
# set up members as needed to accommodate the device
members = []
@@ -1879,28 +1883,21 @@ class Storage(object):
log.debug("adding a %s with size %d" % (factory.set_class.__name__,
container_size))
size_set = factory.set_class(members, container_size)
- self.size_sets.append(size_set)
+ self.size_sets = [size_set]
+ self.allocatePartitions()
+ return members
+ def allocatePartitions(self):
+ """ Allocate all requested partitions. """
try:
doPartitioning(self)
except StorageError as e:
log.error("UI: failed to allocate partitions: %s" % e)
- for device in members:
- actions = self.devicetree.findActions(device=device)
- for a in reversed(actions):
- self.devicetree.cancelAction(a)
# FIXME: revert container to its original state?
- return
- else:
- # fix the sizes of all allocated partitions
- for partition in self.partitions:
- partition.req_grow = False
- partition.req_base_size = partition.size
- partition.req_size = partition.size
-
- return members
+ raise
def getDeviceFactory(self, device_type, size, **kwargs):
+ """ Return a suitable DeviceFactory instance for device_type. """
disks = kwargs.get("disks", [])
encrypted = kwargs.get("encrypted", False)
@@ -1908,7 +1905,8 @@ class Storage(object):
raid_level = kwargs.get("level")
class_table = {AUTOPART_TYPE_LVM: LVMFactory,
- AUTOPART_TYPE_BTRFS: BTRFSFactory}
+ AUTOPART_TYPE_BTRFS: BTRFSFactory,
+ AUTOPART_TYPE_PLAIN: PartitionFactory}
factory_class = class_table.get(device_type, MDFactory)
log.debug("instantiating %s: %r, %s, %s, %s" % (factory_class,
@@ -1965,39 +1963,16 @@ class Storage(object):
if label:
fmt_args["label"] = label
- # TODO: striping, mirroring, &c
- # TODO: non-partition members (pv-on-md)
- if device_type == AUTOPART_TYPE_PLAIN:
- device = self.newPartition(grow=True, maxsize=size,
- fmt_type=fstype, mountpoint=mountpoint,
- fmt_args=fmt_args)
- self.createDevice(device)
- try:
- doPartitioning(self)
- except StorageError as e:
- log.error("failed to allocate partitions: %s" % e)
- actions = self.devicetree.findActions(device=device)
- for a in reversed(actions):
- self.devicetree.cancelAction(a)
- else:
- # fix the sizes of all allocated partitions
- for partition in self.partitions:
- partition.req_grow = False
- partition.req_base_size = partition.size
- partition.req_size = partition.size
-
- return
-
factory = self.getDeviceFactory(device_type, size, **kwargs)
-
- for p in self.partitions:
- log.debug("%r" % p)
+ self.size_sets = [] # clear this since there are no growable reqs now
container = None
containers = [c for c in factory.container_list if not c.exists]
if containers:
container = containers[0]
+ # TODO: striping, mirroring, &c
+ # TODO: non-partition members (pv-on-md)
parents = self.setContainerMembers(container, factory)
# set up container
@@ -2025,6 +2000,7 @@ class Storage(object):
mountpoint=mountpoint,
fmt_args=fmt_args)
self.createDevice(device)
+ factory.post_create()
def copy(self):
new = copy.deepcopy(self)
@@ -2991,20 +2967,25 @@ def parseFSTab(devicetree, chroot=None):
class DeviceFactory(object):
type_desc = None
- member_format = None
- new_container_attr = None
- new_device_attr = None
- container_list_attr = None
+ member_format = None # format type for member devices
+ new_container_attr = None # name of Storage method to create a container
+ new_device_attr = None # name of Storage method to create a device
+ container_list_attr = None # name of Storage attribute to list containers
def __init__(self, storage, size, disks, raid_level, encrypted):
- self.storage = storage
- self.size = size
- self.disks = disks
+ self.storage = storage # the Storage instance
+ self.size = size # the requested size for this device
+ self.disks = disks # the set of disks to allocate from
self.raid_level = raid_level
self.encrypted = encrypted
- self.size_func_kwargs = {}
+ # this is a list of member devices, used to short-circuit the logic in
+ # setContainerMembers for case of a partition
+ self.member_list = None
+ self.size_func_kwargs = {} # keyword args to pass to size function
+
+ # choose a size set class for member partition allocation
if raid_level in ("raid1", "raid10"):
self.set_class = SameSizeSet
else:
@@ -3012,21 +2993,51 @@ class DeviceFactory(object):
@property
def container_list(self):
+ """ A list of containers of the type used by this device. """
+ if not self.container_list_attr:
+ return []
+
return getattr(self.storage, self.container_list_attr)
def new_container(self, *args, **kwargs):
+ """ Return the newly created container for this device. """
return getattr(self.storage, self.new_container_attr)(*args, **kwargs)
def new_device(self, *args, **kwargs):
+ """ Return the newly created device. """
return getattr(self.storage, self.new_device_attr)(*args, **kwargs)
+ def post_create(self):
+ """ 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
@property
def device_size(self):
+ """ The total disk space required for this device. """
return self.size
+class PartitionFactory(DeviceFactory):
+ type_desc = "partition"
+ new_device_attr = "newPartition"
+
+ def __init__(self, storage, size, disks, raid_level, encrypted):
+ super(PartitionFactory, self).__init__(storage, size, disks, raid_level,
+ encrypted)
+ self.member_list = self.disks
+
+ def new_device(self, *args, **kwargs):
+ size = kwargs.pop("size")
+ device = self.storage.newPartition(*args,
+ grow=True, maxsize=size,
+ **kwargs)
+ return device
+
+ def post_create(self):
+ self.storage.allocatePartitions()
class BTRFSFactory(DeviceFactory):
type_desc = "btrfs"
diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py
index 7f34b85..06654c7 100644
--- a/pyanaconda/storage/partitioning.py
+++ b/pyanaconda/storage/partitioning.py
@@ -770,6 +770,15 @@ def doPartitioning(storage):
try:
allocatePartitions(storage, disks, partitions, free)
growPartitions(disks, partitions, free, size_sets=storage.size_sets)
+ except Exception:
+ raise
+ else:
+ # Mark all growable requests as no longer growable.
+ for partition in storage.partitions:
+ log.debug("fixing size of %s at %.2f" % (partition, partition.size))
+ partition.req_grow = False
+ partition.req_base_size = partition.size
+ partition.req_size = partition.size
finally:
# The number and thus the name of partitions may have changed now,
# allocatePartitions() takes care of this for new partitions, but not
--
1.7.7.6
More information about the anaconda-patches
mailing list