Retry cleanup commands if they fail
[snf-image-creator] / image_creator / bundle_volume.py
index 9f08276..bd418ce 100644 (file)
@@ -33,9 +33,7 @@
 
 import os
 import re
-import uuid
 import tempfile
-import time
 from collections import namedtuple
 
 import parted
@@ -43,9 +41,9 @@ import parted
 from image_creator.rsync import Rsync
 from image_creator.util import get_command
 from image_creator.util import FatalError
+from image_creator.util import try_fail_repeat
 
 findfs = get_command('findfs')
-truncate = get_command('truncate')
 dd = get_command('dd')
 dmsetup = get_command('dmsetup')
 losetup = get_command('losetup')
@@ -68,9 +66,11 @@ MKFS_OPTS = {
     }
 
 
-class BundleVolume():
+class BundleVolume(object):
+    """This class can be used to create an image out of the running system"""
 
     def __init__(self, out, meta):
+        """Create an instance of the BundleVolume class."""
         self.out = out
         self.meta = meta
 
@@ -258,8 +258,7 @@ class BundleVolume():
         if not os.path.exists(dev):
             return
 
-        dmsetup('remove', dev.split('/dev/mapper/')[1])
-        time.sleep(0.1)
+        try_fail_repeat(dmsetup, 'remove', dev.split('/dev/mapper/')[1])
 
     def _mount(self, target, devs):
 
@@ -278,7 +277,7 @@ class BundleVolume():
 
         mpoints.sort()
         for mpoint in reversed(mpoints):
-            umount(mpoint)
+            try_fail_repeat(umount, mpoint)
 
     def _to_exclude(self):
         excluded = ['/tmp', '/var/tmp']
@@ -320,7 +319,7 @@ class BundleVolume():
                  '/boot/grub/menu.lst',
                  '/boot/grub/grub.conf']
 
-        orig = dict(map(lambda p: (p.number, blkid( '-s', 'UUID', '-o',
+        orig = dict(map(lambda p: (p.number, blkid('-s', 'UUID', '-o',
             'value', p.path).stdout.strip()), self.disk.partitions))
 
         for f in map(lambda f: target + f, files):
@@ -392,14 +391,19 @@ class BundleVolume():
                 self._unmap_partition(dev)
             losetup('-d', loop)
 
-    def create_image(self):
+    def create_image(self, image):
+        """Given an image filename, this method will create an image out of the
+        running system.
+        """
 
-        image = '/mnt/%s.diskdump' % uuid.uuid4().hex
-
-        disk_size = self.disk.device.getLength() * self.disk.device.sectorSize
+        size = self.disk.device.getLength() * self.disk.device.sectorSize
 
         # Create sparse file to host the image
-        truncate("-s", "%d" % disk_size, image)
+        fd = os.open(image, os.O_WRONLY | os.O_CREAT)
+        try:
+            os.ftruncate(fd, size)
+        finally:
+            os.close(fd)
 
         self._create_partition_table(image)