From 9fcb8cfe7432f3220b488b11a98631c17449257a Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Thu, 28 Feb 2013 09:49:43 -0600
Subject: [PATCH 21/21] Move partition alignment code into DiskLabel.

Also make DiskLabel.addPartition useful for direct use.
---
 blivet/devices.py           | 14 +++++++--
 blivet/formats/disklabel.py | 72 +++++++++++++++++++++++++++++++++++----------
 blivet/partitioning.py      | 37 ++++++-----------------
 3 files changed, 78 insertions(+), 45 deletions(-)

diff --git a/blivet/devices.py b/blivet/devices.py
index f87d4ed..92ca48d 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -1455,7 +1455,11 @@ class PartitionDevice(StorageDevice):
     def _create(self):
         """ Create the device. """
         log_method_call(self, self.name, status=self.status)
-        self.disk.format.addPartition(self.partedPartition)
+        constraint = parted.Constraint(exactGeom=geometry)
+        self.disk.format.addPartition(type=self.partedPartition.type,
+                                      start=self.partedPartition.geometry.start,
+                                      end=self.partedPartition.geometry.end,
+                                      constraint=constraint)
 
         try:
             self.disk.format.commit()
@@ -1538,7 +1542,13 @@ class PartitionDevice(StorageDevice):
         try:
             self.disk.originalFormat.commit()
         except DiskLabelCommitError:
-            self.disk.originalFormat.addPartition(self.partedPartition)
+            partition = self.partedPartition
+            geometry = partition.geometry
+            constraint = parted.Constraint(exactGeom=geometry)
+            self.disk.originalFormat.addPartition(type=partition.type,
+                                                  start=geometry.start,
+                                                  end=geometry.end,
+                                                  constraint=constraint)
             self.partedPartition = self.disk.originalFormat.partedDisk.getPartitionByPath(self.path)
             raise
 
diff --git a/blivet/formats/disklabel.py b/blivet/formats/disklabel.py
index 90b73f3..e05b374 100644
--- a/blivet/formats/disklabel.py
+++ b/blivet/formats/disklabel.py
@@ -264,10 +264,7 @@ class DiskLabel(DeviceFormat):
 
         DeviceFormat.create(self, *args, **kwargs)
 
-        # We're relying on someone having called resetPartedDisk -- we
-        # could ensure a fresh disklabel by setting self._partedDisk to
-        # None right before calling self.commit(), but that might hide
-        # other problems.
+        self.resetPartedDisk()
         self.commit()
         self.exists = True
 
@@ -307,19 +304,64 @@ class DiskLabel(DeviceFormat):
         else:
             self.updateOrigPartedDisk()
 
-    def addPartition(self, *args, **kwargs):
-        partition = kwargs.get("partition", None)
-        if not partition:
-            partition = args[0]
-        geometry = partition.geometry
-        constraint = kwargs.get("constraint", None)
-        if not constraint and len(args) > 1:
-            constraint = args[1]
-        elif not constraint:
-            constraint = parted.Constraint(exactGeom=geometry)
+    def createAlignedGeometry(self, geometry=None, start=None, end=None,
+                              type=None):
+        """ Return an aligned Geometry based on free, start, end, type. """
+        if start is None:
+            start = geometry.start
+
+        if not self.alignment.isAligned(geometry, start):
+            start = self.alignment.alignNearest(geometry, start)
+
+        if self.labelType == "sun" and start == 0:
+            start = self.alignment.alignUp(geometry, start)
+
+        if type == parted.PARTITION_LOGICAL:
+            # make room for logical partition's metadata
+            start += disklabel.alignment.grainSize
+
+        if start != geometry.start:
+            log.debug("adjusted start sector from %d to %d" % (geometry.start,
+                                                               start))
+
+        if part_type == parted.PARTITION_EXTENDED and end is None:
+            end = geometry.end
+
+        if not disklabel.endAlignment.isAligned(free, end):
+            length = end - start + 1
+            end = disklabel.endAlignment.alignNearest(free, end)
+            log.debug("adjusted length from %d to %d" % (length, end - start + 1))
+
+        aligned = parted.Geometry(device=self.partedDevice,
+                                  start=start, end=end)
+        return aligned
+
+    def addPartition(self, type=None, start=None, end=None, constraint=None,
+                     aligned=False):
+        """ Add a partition to this disklabel.
+
+            Keyword Arguments:
+
+                type        -   a parted partition type constant
+                start       -   start sector
+                end         -   end sector
+                constraint  -   a parted constraint
+                aligned     -   whether the given start/end are aligned
+
+            This might be nice as a public API for adding partitions, but the
+            problem is that we don't have a public API for listing free regions
+            or probably a variety of other things in parted we may not want to
+            wrap.
+        """
+        geometry = parted.Geometry(device=self.partedDevice,
+                                   start=start, end=end)
+        if not aligned:
+            geometry = self.createAlignedGeometry(geometry=geometry,
+                                                  start=start, end=end,
+                                                  type=type)
 
         new_partition = parted.Partition(disk=self.partedDisk,
-                                         type=partition.type,
+                                         type=type,
                                          geometry=geometry)
         self.partedDisk.addPartition(partition=new_partition,
                                      constraint=constraint)
diff --git a/blivet/partitioning.py b/blivet/partitioning.py
index 11b44bc..4658b24 100644
--- a/blivet/partitioning.py
+++ b/blivet/partitioning.py
@@ -630,37 +630,18 @@ def addPartition(disklabel, free, part_type, size):
         Return value is a parted.Partition instance.
 
     """
-    start = free.start
-    if not disklabel.alignment.isAligned(free, start):
-        start = disklabel.alignment.alignNearest(free, start)
-
-    if disklabel.labelType == "sun" and start == 0:
-        start = disklabel.alignment.alignUp(free, start)
-
-    if part_type == parted.PARTITION_LOGICAL:
-        # make room for logical partition's metadata
-        start += disklabel.alignment.grainSize
-
-    if start != free.start:
-        log.debug("adjusted start sector from %d to %d" % (free.start, start))
-
-    if part_type == parted.PARTITION_EXTENDED:
-        end = free.end
-        length = end - start + 1
-    else:
-        # size is in MB
+    if size:
         length = sizeToSectors(size, disklabel.partedDevice.sectorSize)
         end = start + length - 1
 
-    if not disklabel.endAlignment.isAligned(free, end):
-        end = disklabel.endAlignment.alignNearest(free, end)
-        log.debug("adjusted length from %d to %d" % (length, end - start + 1))
-        if start > end:
-            raise PartitioningError(_("unable to allocate aligned partition"))
-
-    new_geom = parted.Geometry(device=disklabel.partedDevice,
-                               start=start,
-                               end=end)
+    try:
+        new_geom = disklabel.createAlignedGeometry(free, start=free.start,
+                                                   end=end, type=part_type)
+    except Exception as e:
+        # XXX FIXME: find out the exception pyparted raises when the start is
+        #            past the end
+        log.error("error creating aligned partition geometry: %s" % e)
+        raise PartitioningError(_("unable to allocate aligned partition"))
 
     max_length = disklabel.partedDisk.maxPartitionLength
     if max_length and new_geom.length > max_length:
-- 
1.8.1

