Restore html_theme = 'default' in docs/conf.py
[snf-image-creator] / image_creator / bundle_volume.py
index e373f88..aca14b3 100644 (file)
@@ -131,7 +131,7 @@ class BundleVolume(object):
     def _create_partition_table(self, image):
 
         # Copy the MBR and the space between the MBR and the first partition.
-        # In msdos partitons tables Grub Stage 1.5 is located there.
+        # In msdos partition tables Grub Stage 1.5 is located there.
         # In gpt partition tables the Primary GPT Header is there.
         first_sector = self.disk.getPrimaryPartitions()[0].geometry.start
 
@@ -143,9 +143,9 @@ class BundleVolume(object):
             # Copy the Secondary GPT Header
             table = GPTPartitionTable(self.disk.device.path)
             dd('if=%s' % self.disk.device.path, 'of=%s' % image,
-            'bs=%d' % self.disk.device.sectorSize, 'conv=notrunc',
-            'seek=%d' % table.primary.last_usable_lba,
-            'skip=%d' % table.primary.last_usable_lba)
+               'bs=%d' % self.disk.device.sectorSize, 'conv=notrunc',
+               'seek=%d' % table.primary.last_usable_lba,
+               'skip=%d' % table.primary.last_usable_lba)
 
         # Create the Extended boot records (EBRs) in the image
         extended = self.disk.getExtendedPartition()
@@ -222,9 +222,13 @@ class BundleVolume(object):
             # Align to 2048
             part_end = ((part_end + 2047) // 2048) * 2048
 
+            # Make sure the partition starts where the old partition started.
+            constraint = parted.Constraint(device=image_disk.device)
+            constraint.startRange = parted.Geometry(device=image_disk.device,
+                                                    start=last.start, length=1)
+
             image_disk.setPartitionGeometry(
-                image_disk.getPartitionBySector(last.start),
-                parted.Constraint(device=image_disk.device),
+                image_disk.getPartitionBySector(last.start), constraint,
                 start=last.start, end=part_end)
             image_disk.commitToDevice()
 
@@ -350,9 +354,11 @@ class BundleVolume(object):
         # For partitions that are not mounted right now, we can simply dd them
         # into the image.
         for p in unmounted:
+            self.out.output('Cloning partition %d ... ' % p.num, False)
             dd('if=%s' % self.disk.device.path, 'of=%s' % image,
                'count=%d' % (p.end - p.start + 1), 'conv=notrunc',
                'seek=%d' % p.start, 'skip=%d' % p.start)
+            self.out.success("done")
 
         loop = str(losetup('-f', '--show', image)).strip()
         mapped = {}
@@ -374,15 +380,15 @@ class BundleVolume(object):
 
             target = tempfile.mkdtemp()
             try:
-                absmpoints = self._mount(target,
-                                         [(mapped[i], filesystem[i].mpoint)
-                                         for i in mapped.keys()])
+                self._mount(
+                    target,
+                    [(mapped[i], filesystem[i].mpoint) for i in mapped.keys()])
+
                 excluded = self._to_exclude()
 
                 rsync = Rsync(self.out)
 
-                # Excluded paths need to be relative to the source
-                for excl in map(lambda p: p[1:], excluded + [image]):
+                for excl in excluded + [image]:
                     rsync.exclude(excl)
 
                 rsync.archive().hard_links().xattrs().sparse().acls()
@@ -393,10 +399,22 @@ class BundleVolume(object):
                 # directory. Make them inherit those properties from their
                 # parent dir
                 for excl in excluded:
-                   dirname = os.path.dirname(excl)
-                   stat = os.stat(dirname)
-                   os.mkdir(target + excl, stat.st_mode)
-                   os.chown(target + excl, stat.st_uid, stat.st_gid)
+                    dirname = os.path.dirname(excl)
+                    stat = os.stat(dirname)
+                    os.mkdir(target + excl)
+                    os.chmod(target + excl, stat.st_mode)
+                    os.chown(target + excl, stat.st_uid, stat.st_gid)
+
+                # /tmp and /var/tmp are special cases. We exclude then even if
+                # they aren't mountpoints. Restore their permissions.
+                for excl in ('/tmp', '/var/tmp'):
+                    if self._is_mpoint(excl):
+                        os.chmod(target + excl, 041777)
+                        os.chown(target + excl, 0, 0)
+                    else:
+                        stat = os.stat(excl)
+                        os.chmod(target + excl, stat.st_mode)
+                        os.chown(target + excl, stat.st_uid, stat.st_gid)
 
                 # We need to replace the old UUID referencies with the new
                 # ones in grub configuration files and /etc/fstab for file
@@ -449,8 +467,8 @@ class BundleVolume(object):
         dirname = os.path.dirname(image)
         self.out.output("Examining available space ...", False)
         if free_space(dirname) <= size:
-            raise FatalError('Not enough space under %s to host the image' %
-                             dirname)
+            raise FatalError("Not enough space under %s to host the temporary "
+                             "image" % dirname)
         self.out.success("sufficient")
 
         self._create_filesystems(image, partitions)