Add a new try_fail_repeat function that wraps cleanup system commands
and retries them if they fail. There are cases where commands like
dmsetup, umount and losetup -d may fail with device is busy. In most
of the cases, sleeping for halve a second and retrying does the job.
import os
import re
import tempfile
import os
import re
import tempfile
from collections import namedtuple
import parted
from collections import namedtuple
import parted
from image_creator.rsync import Rsync
from image_creator.util import get_command
from image_creator.util import FatalError
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')
dd = get_command('dd')
findfs = get_command('findfs')
dd = get_command('dd')
+class BundleVolume(object):
+ """This class can be used to create an image out of the running system"""
def __init__(self, out, meta):
def __init__(self, out, meta):
+ """Create an instance of the BundleVolume class."""
self.out = out
self.meta = meta
self.out = out
self.meta = meta
if not os.path.exists(dev):
return
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):
def _mount(self, target, devs):
mpoints.sort()
for mpoint in reversed(mpoints):
mpoints.sort()
for mpoint in reversed(mpoints):
+ try_fail_repeat(umount, mpoint)
def _to_exclude(self):
excluded = ['/tmp', '/var/tmp']
def _to_exclude(self):
excluded = ['/tmp', '/var/tmp']
losetup('-d', loop)
def create_image(self, image):
losetup('-d', loop)
def create_image(self, image):
+ """Given an image filename, this method will create an image out of the
+ running system.
+ """
size = self.disk.device.getLength() * self.disk.device.sectorSize
size = self.disk.device.getLength() * self.disk.device.sectorSize
from image_creator.util import get_command
from image_creator.util import FatalError
from image_creator.util import get_command
from image_creator.util import FatalError
+from image_creator.util import try_fail_repeat
from image_creator.gpt import GPTPartitionTable
from image_creator.bundle_volume import BundleVolume
from image_creator.gpt import GPTPartitionTable
from image_creator.bundle_volume import BundleVolume
import re
import sys
import guestfs
import re
import sys
import guestfs
from sendfile import sendfile
from sendfile import sendfile
def __init__(self, source, output):
"""Create a new Disk instance out of a source media. The source
def __init__(self, source, output):
"""Create a new Disk instance out of a source media. The source
- media can be an image file, a block device or a directory."""
+ media can be an image file, a block device or a directory.
+ """
self._cleanup_jobs = []
self._devices = []
self.source = source
self._cleanup_jobs = []
self._devices = []
self.source = source
def _losetup(self, fname):
loop = losetup('-f', '--show', fname)
loop = loop.strip() # remove the new-line char
def _losetup(self, fname):
loop = losetup('-f', '--show', fname)
loop = loop.strip() # remove the new-line char
- self._add_cleanup(losetup, '-d', loop)
+ self._add_cleanup(try_fail_repeat, losetup, '-d', loop)
return loop
def _dir_to_disk(self):
return loop
def _dir_to_disk(self):
os.write(tablefd, "0 %d snapshot %s %s n 8" %
(int(size), sourcedev, cowdev))
dmsetup('create', snapshot, table)
os.write(tablefd, "0 %d snapshot %s %s n 8" %
(int(size), sourcedev, cowdev))
dmsetup('create', snapshot, table)
- self._add_cleanup(dmsetup, 'remove', snapshot)
- # Sometimes dmsetup remove fails with Device or resource busy,
- # although everything is cleaned up and the snapshot is not
- # used by anyone. Add a 2 seconds delay to be on the safe side.
- self._add_cleanup(time.sleep, 2)
+ self._add_cleanup(try_fail_repeat, dmsetup, 'remove', snapshot)
finally:
os.unlink(table)
finally:
os.unlink(table)
import sys
import sh
import hashlib
import sys
import sh
import hashlib
class FatalError(Exception):
class FatalError(Exception):
return find_sbin_command(command, e)
return find_sbin_command(command, e)
+def try_fail_repeat(command, *args):
+
+ times = (0.1, 0.5, 1, 2)
+ i = iter(times)
+ while True:
+ try:
+ command(*args)
+ return
+ except sh.ErrorReturnCode:
+ try:
+ wait = i.next()
+ except StopIteration:
+ break
+ time.sleep(wait)
+
+ raise FatalError("Command: `%s %s' failed" % (command, " ".join(args)))
+
+
class MD5:
def __init__(self, output):
self.out = output
def compute(self, filename, size):
class MD5:
def __init__(self, output):
self.out = output
def compute(self, filename, size):
MB = 2 ** 20
BLOCKSIZE = 4 * MB # 4MB
MB = 2 ** 20
BLOCKSIZE = 4 * MB # 4MB